Merge pull request #5008 from kellykelly3/1263-cvt-calllog-tab

1263 - CVT Call Log Tab
This commit is contained in:
Richard Cordovano 2019-07-16 12:53:32 -04:00 committed by GitHub
commit 46c4067db9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 722 additions and 156 deletions

View File

@ -0,0 +1,98 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obt ain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.Comparator;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A comparator class for comparing BlackboardArtifacts of type
* TSK_EMAIL_MSG, TSK_MESSAGE, and TSK_CALLLOG by their respective creation
* date-time.
*/
class BlackboardArtifactDateComparator implements Comparator<BlackboardArtifact> {
static final int ACCENDING = 1;
static final int DECENDING = -1;
private static final Logger logger = Logger.getLogger(BlackboardArtifactDateComparator.class.getName());
private final int direction;
BlackboardArtifactDateComparator(int direction) {
this.direction = direction;
}
@Override
public int compare(BlackboardArtifact bba1, BlackboardArtifact bba2) {
BlackboardAttribute attribute1 = getTimeAttributeForArtifact(bba1);
BlackboardAttribute attribute2 = getTimeAttributeForArtifact(bba2);
// Inializing to Long.MAX_VALUE so that if a BlackboardArtifact of
// any unexpected type is passed in, it will bubble to the top of
// the list.
long dateTime1 = Long.MAX_VALUE;
long dateTime2 = Long.MAX_VALUE;
if (attribute1 != null) {
dateTime1 = attribute1.getValueLong();
}
if (attribute2 != null) {
dateTime2 = attribute2.getValueLong();
}
return Long.compare(dateTime1, dateTime2) * direction;
}
private BlackboardAttribute getTimeAttributeForArtifact(BlackboardArtifact artifact) {
if(artifact == null) {
return null;
}
BlackboardAttribute attribute = null;
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
if (fromID != null) {
try {
switch (fromID) {
case TSK_EMAIL_MSG:
attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT));
break;
case TSK_MESSAGE:
attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME));
break;
case TSK_CALLLOG:
attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START));
break;
default:
attribute = null;
break;
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Unable to compare attributes for artifact %d", artifact.getArtifactID()), ex);
}
}
return attribute;
}
}

View File

@ -1,3 +1,8 @@
CallLogViewer_device_label=Device
CallLogViewer_duration_label=Duration(seconds)
CallLogViewer_noCallLogs=<No call logs found for selected account>
CallLogViewer_recipient_label=To/From
CallLogViewer_title=Call Logs
ContactDetailsPane.nameLabel.text=Placeholder
ContactNode_Email=Email Address
ContactNode_Home_Number=Home Number

View File

@ -0,0 +1,117 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.logging.Level;
import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.communications.Utils;
import static org.sleuthkit.autopsy.communications.relationships.RelationshipsNodeUtilities.getAttributeDisplayString;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG;
import org.sleuthkit.datamodel.BlackboardAttribute;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A BlackboardArtifactNode for Calllogs.
*/
final class CallLogNode extends BlackboardArtifactNode {
private static final Logger logger = Logger.getLogger(CallLogNode.class.getName());
final static String DURATION_PROP = "duration";
CallLogNode(BlackboardArtifact artifact, String deviceID) {
super(artifact, Utils.getIconFilePath(Account.Type.PHONE));
setDisplayName(deviceID);
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
final BlackboardArtifact artifact = getArtifact();
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
if (null != fromID && fromID != TSK_CALLLOG) {
return sheet;
}
String phoneNumber = getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM);
if(phoneNumber == null || phoneNumber.isEmpty()) {
phoneNumber = getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO);
}
long duration = -1;
try{
duration = getCallDuration(artifact);
} catch(TskCoreException ex) {
logger.log(Level.WARNING, String.format("Unable to get calllog duration for artifact: %d", artifact.getArtifactID()), ex);
}
sheetSet.put(createNode(TSK_DATETIME_START, artifact));
sheetSet.put(createNode(TSK_DIRECTION, artifact));
sheetSet.put(new NodeProperty<>(TSK_PHONE_NUMBER.getLabel(), TSK_PHONE_NUMBER.getDisplayName(), "", phoneNumber));
if(duration != -1) {
sheetSet.put(new NodeProperty<>("duration", "Duration", "", Long.toString(duration)));
}
return sheet;
}
NodeProperty<?> createNode(BlackboardAttribute.ATTRIBUTE_TYPE type, BlackboardArtifact artifact) {
return new NodeProperty<>(type.getLabel(), type.getDisplayName(), type.getDisplayName(), getAttributeDisplayString(artifact, type));
}
long getCallDuration(BlackboardArtifact artifact) throws TskCoreException {
BlackboardAttribute startAttribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(TSK_DATETIME_START.getTypeID())));
BlackboardAttribute endAttribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(TSK_DATETIME_END.getTypeID())));
if(startAttribute == null || endAttribute == null) {
return -1;
}
return endAttribute.getValueLong() - startAttribute.getValueLong();
}
/**
* Circumvent DataResultFilterNode's slightly odd delegation to
* BlackboardArtifactNode.getSourceName().
*
* @return the displayName of this Node, which is the type.
*/
@Override
public String getSourceName() {
return getDisplayName();
}
}

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.4" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="outlineViewPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="15" insetsBottom="15" insetsRight="15" anchor="12" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,146 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import javax.swing.JPanel;
import org.netbeans.swing.outline.DefaultOutlineModel;
import org.netbeans.swing.outline.Outline;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.NodeAdapter;
import org.openide.nodes.NodeMemberEvent;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION;
/**
*
* CallLogViewer Panel
*/
final class CallLogViewer extends javax.swing.JPanel implements RelationshipsViewer {
private final CallLogsChildNodeFactory nodeFactory;
@Messages({
"CallLogViewer_title=Call Logs",
"CallLogViewer_noCallLogs=<No call logs found for selected account>",
"CallLogViewer_recipient_label=To/From",
"CallLogViewer_duration_label=Duration(seconds)",
"CallLogViewer_device_label=Device"
})
/**
* Creates new form CallLogViewer
*/
public CallLogViewer() {
initComponents();
nodeFactory = new CallLogsChildNodeFactory(null);
outlineViewPanel.hideOutlineView(Bundle.CallLogViewer_noCallLogs());
outlineViewPanel.getOutlineView().setPropertyColumns(
TSK_DIRECTION.getLabel(), TSK_DIRECTION.getDisplayName(),
TSK_PHONE_NUMBER.getLabel(), Bundle.CallLogViewer_recipient_label(),
TSK_DATETIME_START.getLabel(), TSK_DATETIME_START.getDisplayName(),
CallLogNode.DURATION_PROP, Bundle.CallLogViewer_duration_label()
);
Outline outline = outlineViewPanel.getOutlineView().getOutline();
outline.setRootVisible(false);
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.CallLogViewer_device_label());
outlineViewPanel.getExplorerManager().setRootContext(
new TableFilterNode(
new DataResultFilterNode(
new AbstractNode(Children.create(nodeFactory, true)), outlineViewPanel.getExplorerManager()), true));
outlineViewPanel.getExplorerManager().getRootContext().addNodeListener(new NodeAdapter(){
@Override
public void childrenAdded(NodeMemberEvent nme) {
updateOutlineViewPanel();
}
@Override
public void childrenRemoved(NodeMemberEvent nme) {
updateOutlineViewPanel();
}
});
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
outlineViewPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
setLayout(new java.awt.GridBagLayout());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(15, 15, 15, 15);
add(outlineViewPanel, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
@Override
public String getDisplayName() {
return Bundle.CallLogViewer_title();
}
@Override
public JPanel getPanel() {
return this;
}
@Override
public void setSelectionInfo(SelectionInfo info) {
nodeFactory.refresh(info);
}
@Override
public Lookup getLookup() {
return outlineViewPanel.getLookup();
}
private void updateOutlineViewPanel() {
int nodeCount = outlineViewPanel.getExplorerManager().getRootContext().getChildren().getNodesCount();
if(nodeCount == 0) {
outlineViewPanel.hideOutlineView(Bundle.ContactsViewer_noContacts_message());
} else {
outlineViewPanel.showOutlineView();
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel outlineViewPanel;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,204 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obt ain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.communications.relationships.CallLogsChildNodeFactory.CallLogNodeKey;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.AccountDeviceInstance;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.CommunicationsFilter;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
*A ChildFactory for CallLog artifacts.
*/
final class CallLogsChildNodeFactory extends ChildFactory<CallLogNodeKey>{
private static final Logger logger = Logger.getLogger(CallLogsChildNodeFactory.class.getName());
private SelectionInfo selectionInfo;
private final Map<String, String> deviceIDMap = new HashMap<>();
CallLogsChildNodeFactory(SelectionInfo selectionInfo) {
this.selectionInfo = selectionInfo;
}
void refresh(SelectionInfo selectionInfo) {
this.selectionInfo = selectionInfo;
refresh(true);
}
@Override
protected boolean createKeys(List<CallLogNodeKey> list) {
if(selectionInfo == null) {
return true;
}
final Set<Content> relationshipSources;
try {
relationshipSources = selectionInfo.getRelationshipSources();
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to load relationship sources.", ex); //NON-NLS
return false;
}
for(Content content: relationshipSources) {
if( !(content instanceof BlackboardArtifact)){
continue;
}
BlackboardArtifact bba = (BlackboardArtifact) content;
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID());
if ( fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG) {
String deviceID = "";
try {
deviceID = getDeviceIDForDataSource(bba.getDataSource().getName());
} catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.WARNING, String.format("Unable to get account for artifact data source: artifactID = %d", bba.getId()), ex);
}
list.add(new CallLogNodeKey(bba, deviceID));
}
}
list.sort(new CallLogComparator(BlackboardArtifactDateComparator.ACCENDING));
return true;
}
@Override
protected Node createNodeForKey(CallLogNodeKey key) {
return new CallLogNode(key.getArtifact(), key.getDeviceID());
}
/**
* Gets the device ID for the given data source.
*
* To reduce lookup calls to the DB unique dataSourceName\deviceID pairs
* are stored in deviceIDMap.
*
* @param dataSourceName String name of data source
*
* @return device ID for given dataSourceName or empty string if non is found.
*
* @throws NoCurrentCaseException
* @throws TskCoreException
*/
private String getDeviceIDForDataSource(String dataSourceName) throws NoCurrentCaseException, TskCoreException{
String deviceID = deviceIDMap.get(dataSourceName);
if(deviceID == null) {
CommunicationsManager manager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
CommunicationsFilter filter = new CommunicationsFilter();
List<String> list = new ArrayList<>();
list.add(dataSourceName);
List<Account.Type> typeList = new ArrayList<Account.Type>();
typeList.add(Account.Type.DEVICE);
filter.addAndFilter(new CommunicationsFilter.DeviceFilter(list));
filter.addAndFilter(new CommunicationsFilter.AccountTypeFilter(typeList));
// This list should just have 1 item in it
List<AccountDeviceInstance> adiList = manager.getAccountDeviceInstancesWithRelationships(filter);
if( adiList != null && !adiList.isEmpty() ) {
deviceID = adiList.get(0).getDeviceId();
} else {
deviceID = "";
}
deviceIDMap.put(dataSourceName, deviceID);
}
return (deviceID != null ? deviceID : "");
}
/**
* ChildFactory key class which contains a BlackboardArtifact and its
* data source deviceID
*/
final class CallLogNodeKey{
private final BlackboardArtifact artifact;
private final String deviceID;
private CallLogNodeKey(BlackboardArtifact artifact, String deviceID) {
this.artifact = artifact;
this.deviceID = deviceID;
}
/**
* Get the BlackboardArtifact for this key
*
* @return BlackboardArtifact instance
*/
BlackboardArtifact getArtifact() {
return artifact;
}
/**
* Gets the BlackboardArtifact data source device ID.
*
* @return String device id.
*/
String getDeviceID() {
return deviceID;
}
}
/**
* A comparator for CallLogNodeKey objects
*/
final class CallLogComparator implements Comparator<CallLogNodeKey>{
final BlackboardArtifactDateComparator comparator;
CallLogComparator(int direction) {
comparator = new BlackboardArtifactDateComparator(direction);
}
@Override
public int compare(CallLogNodeKey key1, CallLogNodeKey key2) {
return comparator.compare(key1.getArtifact(), key2.getArtifact());
}
}
}

View File

@ -18,7 +18,6 @@
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.TimeZone;
import java.util.logging.Level;
import javax.swing.Action;
import org.apache.commons.lang3.StringUtils;
@ -27,20 +26,18 @@ import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_TO;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT;
import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME;
import org.sleuthkit.datamodel.TimeUtilities;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.communications.Utils;
import static org.sleuthkit.autopsy.communications.relationships.RelationshipsNodeUtilities.getAttributeDisplayString;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE;
/**
* Wraps a BlackboardArtifact as an AbstractNode for use in an OutlookView
@ -48,7 +45,6 @@ import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
class MessageNode extends BlackboardArtifactNode {
public static final String UNTHREADED_ID = "<UNTHREADED>";
public static final String CALL_LOG_ID = "<CALLLOG>";
private static final Logger logger = Logger.getLogger(MessageNode.class.getName());
@ -88,92 +84,45 @@ class MessageNode extends BlackboardArtifactNode {
sheetSet.put(new NodeProperty<>("Type", Bundle.MessageNode_Node_Property_Type(), "", getDisplayName())); //NON-NLS
final BlackboardArtifact artifact = getArtifact();
if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()) {
sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",CALL_LOG_ID)); //NON-NLS
} else {
sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",threadID == null ? UNTHREADED_ID : threadID)); //NON-NLS
}
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
if (null != fromID) {
//Consider refactoring this to reduce boilerplate
switch (fromID) {
case TSK_EMAIL_MSG:
sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "",
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_FROM), " \t\n;"))); //NON-NLS
sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "",
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_TO), " \t\n;"))); //NON-NLS
sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "",
getAttributeDisplayString(artifact, TSK_DATETIME_SENT))); //NON-NLS
sheetSet.put(new NodeProperty<>("Subject", Bundle.MessageNode_Node_Property_Subject(), "",
getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS
try {
sheetSet.put(new NodeProperty<>("Attms", Bundle.MessageNode_Node_Property_Attms(), "", artifact.getChildrenCount())); //NON-NLS
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS
}
break;
case TSK_MESSAGE:
sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM))); //NON-NLS
sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO))); //NON-NLS
sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "",
getAttributeDisplayString(artifact, TSK_DATETIME))); //NON-NLS
sheetSet.put(new NodeProperty<>("Subject", Bundle.MessageNode_Node_Property_Subject(), "",
getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS
try {
sheetSet.put(new NodeProperty<>("Attms", Bundle.MessageNode_Node_Property_Attms(), "", artifact.getChildrenCount())); //NON-NLS
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS
}
break;
case TSK_CALLLOG:
sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM))); //NON-NLS
sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO))); //NON-NLS
sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "",
getAttributeDisplayString(artifact, TSK_DATETIME_START))); //NON-NLS
break;
default:
break;
}
if(fromID == null ||
(fromID != TSK_EMAIL_MSG &&
fromID != TSK_MESSAGE)) {
return sheet;
}
return sheet;
}
/**
*
* Get the display string for the attribute of the given type from the given
* artifact.
*
* @param artifact the value of artifact
* @param attributeType the value of TSK_SUBJECT1
*
* @return The display string, or an empty string if there is no such
* attribute or an an error.
*/
private static String getAttributeDisplayString(final BlackboardArtifact artifact, final BlackboardAttribute.ATTRIBUTE_TYPE attributeType) {
sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",threadID == null ? UNTHREADED_ID : threadID)); //NON-NLS
sheetSet.put(new NodeProperty<>("Subject", Bundle.MessageNode_Node_Property_Subject(), "",
getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS
try {
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(attributeType.getTypeID())));
if (attribute == null) {
return "";
} else if (attributeType.getValueType() == DATETIME) {
return TimeUtilities.epochToTime(attribute.getValueLong(),
TimeZone.getTimeZone(Utils.getUserPreferredZoneId()));
} else {
return attribute.getDisplayString();
}
} catch (TskCoreException tskCoreException) {
logger.log(Level.WARNING, "Error getting attribute value.", tskCoreException); //NON-NLS
return "";
sheetSet.put(new NodeProperty<>("Attms", Bundle.MessageNode_Node_Property_Attms(), "", artifact.getChildrenCount())); //NON-NLS
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS
}
switch (fromID) {
case TSK_EMAIL_MSG:
sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "",
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_FROM), " \t\n;"))); //NON-NLS
sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "",
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_TO), " \t\n;"))); //NON-NLS
sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "",
getAttributeDisplayString(artifact, TSK_DATETIME_SENT))); //NON-NLS
break;
case TSK_MESSAGE:
sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM))); //NON-NLS
sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO))); //NON-NLS
sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "",
getAttributeDisplayString(artifact, TSK_DATETIME))); //NON-NLS
break;
default:
break;
}
return sheet;
}
/**

View File

@ -229,11 +229,7 @@ public class MessageViewer extends JPanel implements RelationshipsViewer {
if (!subject.isEmpty()) {
threadNameLabel.setText(subject);
} else {
if (threadIDList.contains(MessageNode.CALL_LOG_ID)) {
threadNameLabel.setText(Bundle.MessageViewer_viewMessage_calllogs());
} else {
threadNameLabel.setText(Bundle.MessageViewer_viewMessage_unthreaded());
}
threadNameLabel.setText(Bundle.MessageViewer_viewMessage_unthreaded());
}
showMessagesPane();

View File

@ -91,7 +91,6 @@ public class MessagesChildNodeFactory extends ChildFactory<BlackboardArtifact>{
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID());
if (fromID != BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG
&& fromID != BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG
&& fromID != BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) {
continue;
}
@ -100,12 +99,8 @@ public class MessagesChildNodeFactory extends ChildFactory<BlackboardArtifact>{
// To achive this assign any artifact that does not have a threadID
// the "UNTHREADED_ID"
// All call logs will default to a single call logs thread
String artifactThreadID;
if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG) {
artifactThreadID = MessageNode.CALL_LOG_ID;
} else {
artifactThreadID = MessageNode.UNTHREADED_ID;
}
String artifactThreadID = MessageNode.UNTHREADED_ID;
BlackboardAttribute attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID));
if(attribute != null) {
@ -115,7 +110,6 @@ public class MessagesChildNodeFactory extends ChildFactory<BlackboardArtifact>{
if(threadIDs == null || threadIDs.contains(artifactThreadID)) {
list.add(bba);
}
}
} catch (TskCoreException ex) {

View File

@ -11,6 +11,7 @@
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>

View File

@ -30,12 +30,6 @@ import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
public final class RelationshipBrowser extends JPanel implements Lookup.Provider {
private SelectionInfo currentSelection;
private final MessageViewer messagesViewer;
private final ContactsViewer contactsViewer;
private final SummaryViewer summaryViewer;
private final MediaViewer mediaViewer;
private final ModifiableProxyLookup proxyLookup;
/**
@ -43,15 +37,18 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
*/
public RelationshipBrowser() {
initComponents();
messagesViewer = new MessageViewer();
contactsViewer = new ContactsViewer();
summaryViewer = new SummaryViewer();
mediaViewer = new MediaViewer();
MessageViewer messagesViewer = new MessageViewer();
ContactsViewer contactsViewer = new ContactsViewer();
SummaryViewer summaryViewer = new SummaryViewer();
MediaViewer mediaViewer = new MediaViewer();
CallLogViewer callLogViewer = new CallLogViewer();
proxyLookup = new ModifiableProxyLookup(messagesViewer.getLookup());
tabPane.add(summaryViewer.getDisplayName(), summaryViewer);
tabPane.add(messagesViewer.getDisplayName(), messagesViewer);
tabPane.add(callLogViewer.getDisplayName(), callLogViewer);
tabPane.add(contactsViewer.getDisplayName(), contactsViewer);
tabPane.add(mediaViewer.getDisplayName(), mediaViewer);
}

View File

@ -0,0 +1,71 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.TimeZone;
import java.util.logging.Level;
import org.sleuthkit.autopsy.communications.Utils;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME;
import org.sleuthkit.datamodel.TimeUtilities;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A set of reusable utility functions for the Relationships package.
*
*/
final class RelationshipsNodeUtilities {
private static final Logger logger = Logger.getLogger(RelationshipsNodeUtilities.class.getName());
// Here to make codacy happy
private RelationshipsNodeUtilities(){
}
/**
*
* Get the display string for the attribute of the given type from the given
* artifact.
*
* @param artifact the value of artifact
* @param attributeType the value of TSK_SUBJECT1
*
* @return The display string, or an empty string if there is no such
* attribute or an an error.
*/
static String getAttributeDisplayString(final BlackboardArtifact artifact, final BlackboardAttribute.ATTRIBUTE_TYPE attributeType) {
try {
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(attributeType.getTypeID())));
if (attribute == null) {
return "";
} else if (attributeType.getValueType() == DATETIME) {
return TimeUtilities.epochToTime(attribute.getValueLong(),
TimeZone.getTimeZone(Utils.getUserPreferredZoneId()));
} else {
return attribute.getDisplayString();
}
} catch (TskCoreException tskCoreException) {
logger.log(Level.WARNING, "Error getting attribute value.", tskCoreException); //NON-NLS
return "";
}
}
}

View File

@ -118,19 +118,13 @@ final class ThreadChildNodeFactory extends ChildFactory<BlackboardArtifact> {
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID());
if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG
|| fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG
|| fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) {
// We want email and message artifacts that do not have "threadIDs" to appear as one thread in the UI
// To achive this assign any artifact that does not have a threadID
// the "UNTHREADED_ID"
// All call logs will default to a single call logs thread
String threadID;
if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG) {
threadID = MessageNode.CALL_LOG_ID;
} else {
threadID = MessageNode.UNTHREADED_ID;
}
String threadID = MessageNode.UNTHREADED_ID;
BlackboardAttribute attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID));
if(attribute != null) {
@ -202,41 +196,8 @@ final class ThreadChildNodeFactory extends ChildFactory<BlackboardArtifact> {
if (attribute != null) {
return new ThreadNode(bba, attribute.getValueString(), preferredAction);
} else {
if (bba.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()) {
return new CallLogNode();
} else {
// Only one of these should occur.
return new UnthreadedNode();
}
}
}
/**
* This node represents the "call log" thread.
*/
final class CallLogNode extends AbstractNode {
/**
* Construct an instance of a CallLogNode.
*/
CallLogNode() {
super(Children.LEAF);
setDisplayName("Call Logs");
this.setIconBaseWithExtension("org/sleuthkit/autopsy/communications/images/unthreaded.png" );
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
// Give this node a threadID of "CALL_LOG_ID"
sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",MessageNode.CALL_LOG_ID));
return sheet;
// Only one of these should occur.
return new UnthreadedNode();
}
}