Merge pull request #3274 from sleuthkit/accounts_relationships

907: merge account_relationships to develop
This commit is contained in:
Richard Cordovano 2017-12-07 09:32:50 -05:00 committed by GitHub
commit 35c4939ace
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
71 changed files with 3938 additions and 365 deletions

View File

@ -22,5 +22,6 @@
<dependency conf="core->default" org="org.apache.commons" name="commons-dbcp2" rev="2.1.1"/> <dependency conf="core->default" org="org.apache.commons" name="commons-dbcp2" rev="2.1.1"/>
<dependency conf="core->default" org="org.apache.commons" name="commons-pool2" rev="2.4.2"/> <dependency conf="core->default" org="org.apache.commons" name="commons-pool2" rev="2.4.2"/>
<dependency conf="core->default" org="org.jsoup" name="jsoup" rev="1.10.3"/>
</dependencies> </dependencies>
</ivy-module> </ivy-module>

View File

@ -5,6 +5,7 @@ file.reference.commons-dbcp2-2.1.1.jar=release\\modules\\ext\\commons-dbcp2-2.1.
file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.2.jar file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.2.jar
file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar
file.reference.jsoup-1.10.3.jar=release/modules/ext/jsoup-1.10.3.jar
file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar
file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar
file.reference.metadata-extractor-2.9.1.jar=release/modules/ext/metadata-extractor-2.9.1.jar file.reference.metadata-extractor-2.9.1.jar=release/modules/ext/metadata-extractor-2.9.1.jar

View File

@ -320,6 +320,10 @@
<package>org.sleuthkit.autopsy.report</package> <package>org.sleuthkit.autopsy.report</package>
<package>org.sleuthkit.datamodel</package> <package>org.sleuthkit.datamodel</package>
</public-packages> </public-packages>
<class-path-extension>
<runtime-relative-path>ext/xmpcore-5.1.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/xmpcore-5.1.2.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/zookeeper-3.4.6.jar</runtime-relative-path> <runtime-relative-path>ext/zookeeper-3.4.6.jar</runtime-relative-path>
<binary-origin>release/modules/ext/zookeeper-3.4.6.jar</binary-origin> <binary-origin>release/modules/ext/zookeeper-3.4.6.jar</binary-origin>
@ -335,6 +339,10 @@
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/Tsk_DataModel_PostgreSQL.jar</runtime-relative-path> <runtime-relative-path>ext/Tsk_DataModel_PostgreSQL.jar</runtime-relative-path>
<binary-origin>release/modules/ext/Tsk_DataModel_PostgreSQL.jar</binary-origin> <binary-origin>release/modules/ext/Tsk_DataModel_PostgreSQL.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/StixLib.jar</runtime-relative-path>
<binary-origin>release/modules/ext/StixLib.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/opencv-248.jar</runtime-relative-path> <runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
@ -344,6 +352,10 @@
<runtime-relative-path>ext/curator-framework-2.8.0.jar</runtime-relative-path> <runtime-relative-path>ext/curator-framework-2.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/curator-framework-2.8.0.jar</binary-origin> <binary-origin>release/modules/ext/curator-framework-2.8.0.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/curator-client-2.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/curator-client-2.8.0.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/commons-dbcp2-2.1.1.jar</runtime-relative-path> <runtime-relative-path>ext/commons-dbcp2-2.1.1.jar</runtime-relative-path>
<binary-origin>release\modules\ext\commons-dbcp2-2.1.1.jar</binary-origin> <binary-origin>release\modules\ext\commons-dbcp2-2.1.1.jar</binary-origin>
@ -356,6 +368,14 @@
<runtime-relative-path>ext/jython-standalone-2.7.0.jar</runtime-relative-path> <runtime-relative-path>ext/jython-standalone-2.7.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jython-standalone-2.7.0.jar</binary-origin> <binary-origin>release/modules/ext/jython-standalone-2.7.0.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/activemq-all-5.11.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/activemq-all-5.11.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
<binary-origin>release/modules/ext/opencv-248.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/sevenzipjbinding.jar</runtime-relative-path> <runtime-relative-path>ext/sevenzipjbinding.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sevenzipjbinding.jar</binary-origin> <binary-origin>release/modules/ext/sevenzipjbinding.jar</binary-origin>
@ -377,12 +397,12 @@
<binary-origin>release/modules/ext/xmpcore-5.1.2.jar</binary-origin> <binary-origin>release/modules/ext/xmpcore-5.1.2.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/StixLib.jar</runtime-relative-path> <runtime-relative-path>ext/sevenzipjbinding-AllPlatforms.jar</runtime-relative-path>
<binary-origin>release/modules/ext/StixLib.jar</binary-origin> <binary-origin>release/modules/ext/sevenzipjbinding-AllPlatforms.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/curator-client-2.8.0.jar</runtime-relative-path> <runtime-relative-path>ext/commons-pool2-2.4.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/curator-client-2.8.0.jar</binary-origin> <binary-origin>release\modules\ext\commons-pool2-2.4.2.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/sqlite-jdbc-3.8.11.jar</runtime-relative-path> <runtime-relative-path>ext/sqlite-jdbc-3.8.11.jar</runtime-relative-path>
@ -392,18 +412,14 @@
<runtime-relative-path>ext/activemq-all-5.11.1.jar</runtime-relative-path> <runtime-relative-path>ext/activemq-all-5.11.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/activemq-all-5.11.1.jar</binary-origin> <binary-origin>release/modules/ext/activemq-all-5.11.1.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jsoup-1.10.3.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jsoup-1.10.3.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/Rejistry-1.0-SNAPSHOT.jar</runtime-relative-path> <runtime-relative-path>ext/Rejistry-1.0-SNAPSHOT.jar</runtime-relative-path>
<binary-origin>release/modules/ext/Rejistry-1.0-SNAPSHOT.jar</binary-origin> <binary-origin>release/modules/ext/Rejistry-1.0-SNAPSHOT.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sevenzipjbinding-AllPlatforms.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sevenzipjbinding-AllPlatforms.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/commons-pool2-2.4.2.jar</runtime-relative-path>
<binary-origin>release\modules\ext\commons-pool2-2.4.2.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/metadata-extractor-2.9.1.jar</runtime-relative-path> <runtime-relative-path>ext/metadata-extractor-2.9.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/metadata-extractor-2.9.1.jar</binary-origin> <binary-origin>release/modules/ext/metadata-extractor-2.9.1.jar</binary-origin>
@ -420,6 +436,10 @@
<runtime-relative-path>ext/c3p0-0.9.5.jar</runtime-relative-path> <runtime-relative-path>ext/c3p0-0.9.5.jar</runtime-relative-path>
<binary-origin>release/modules/ext/c3p0-0.9.5.jar</binary-origin> <binary-origin>release/modules/ext/c3p0-0.9.5.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/c3p0-0.9.5.jar</runtime-relative-path>
<binary-origin>release/modules/ext/c3p0-0.9.5.jar</binary-origin>
</class-path-extension>
</data> </data>
</configuration> </configuration>
</project> </project>

View File

@ -76,6 +76,7 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent; import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.ReportAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ReportAddedEvent;
import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.casemodule.services.Services;
import org.sleuthkit.autopsy.communications.OpenCommVisualizationToolAction;
import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CategoryNode; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CategoryNode;
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException;
@ -1050,6 +1051,7 @@ public class Case {
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true); CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true);
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true); CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true);
CallableSystemAction.get(OpenTimelineAction.class).setEnabled(true); CallableSystemAction.get(OpenTimelineAction.class).setEnabled(true);
CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(true);
CallableSystemAction.get(OpenOutputFolderAction.class).setEnabled(false); CallableSystemAction.get(OpenOutputFolderAction.class).setEnabled(false);
/* /*
@ -1092,24 +1094,13 @@ public class Case {
/* /*
* Disable the case-specific menu items. * Disable the case-specific menu items.
*/ */
CallableSystemAction CallableSystemAction.get(AddImageAction.class).setEnabled(false);
.get(AddImageAction.class CallableSystemAction.get(CaseCloseAction.class).setEnabled(false);
).setEnabled(false); CallableSystemAction.get(CasePropertiesAction.class).setEnabled(false);
CallableSystemAction CallableSystemAction.get(CaseDeleteAction.class).setEnabled(false);
.get(CaseCloseAction.class CallableSystemAction.get(OpenTimelineAction.class).setEnabled(false);
).setEnabled(false); CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(false);
CallableSystemAction CallableSystemAction.get(OpenOutputFolderAction.class).setEnabled(false);
.get(CasePropertiesAction.class
).setEnabled(false);
CallableSystemAction
.get(CaseDeleteAction.class
).setEnabled(false);
CallableSystemAction
.get(OpenTimelineAction.class
).setEnabled(false);
CallableSystemAction
.get(OpenOutputFolderAction.class
).setEnabled(false);
/* /*
* Clear the notifications in the notfier component in the lower * Clear the notifications in the notfier component in the lower

View File

@ -0,0 +1,78 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 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;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AccountDeviceInstance;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.CommunicationsFilter;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.TskCoreException;
/**
* 'Root' Node for the Account/Messages area. Has children which are all the
* relationships of all the accounts in this node.
*
*/
class AccountDetailsNode extends AbstractNode {
private final static Logger logger = Logger.getLogger(AccountDetailsNode.class.getName());
AccountDetailsNode(Set<AccountDeviceInstance> accountDeviceInstances, CommunicationsFilter filter, CommunicationsManager commsManager) {
super(Children.create(new AccountRelationshipChildren(accountDeviceInstances, commsManager, filter), true));
}
/**
* Children object for the relationships that the accounts are part of.
*/
private static class AccountRelationshipChildren extends ChildFactory<BlackboardArtifact> {
private final Set<AccountDeviceInstance> accountDeviceInstances;
private final CommunicationsManager commsManager;
private final CommunicationsFilter filter;
private AccountRelationshipChildren(Set<AccountDeviceInstance> accountDeviceInstances, CommunicationsManager commsManager, CommunicationsFilter filter) {
this.accountDeviceInstances = accountDeviceInstances;
this.commsManager = commsManager;
this.filter = filter;
}
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
try {
list.addAll(commsManager.getRelationshipSources(accountDeviceInstances, filter));
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting communications", ex);
}
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact t) {
return new RelationShipNode(t);
}
}
}

View File

@ -0,0 +1,54 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 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;
import org.sleuthkit.datamodel.AccountDeviceInstance;
import org.sleuthkit.datamodel.CommunicationsFilter;
/**
* Key for AccountDeviceInstance node.
*
* Encapsulates a AccountDeviceInstance, and CommunicationsFilter.
*/
class AccountDeviceInstanceKey {
private final AccountDeviceInstance accountDeviceInstance;
private final CommunicationsFilter filter;
private final long messageCount;
AccountDeviceInstanceKey(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter, long msgCount) {
this.accountDeviceInstance = accountDeviceInstance;
this.filter = filter;
this.messageCount = msgCount;
}
AccountDeviceInstance getAccountDeviceInstance() {
return accountDeviceInstance;
}
CommunicationsFilter getCommunicationsFilter() {
return filter;
}
long getMessageCount() {
return messageCount;
}
}

View File

@ -0,0 +1,40 @@
<?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="false"/>
<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"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="outlineView" pref="400" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="outlineView" pref="300" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="org.openide.explorer.view.OutlineView" name="outlineView">
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,129 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 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;
import java.awt.Component;
import javax.swing.JPanel;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellRenderer;
import org.netbeans.swing.outline.DefaultOutlineModel;
import org.netbeans.swing.outline.Outline;
import org.openide.explorer.ExplorerManager;
/**
* A panel that goes in the Browse tab of the Communications Visualization Tool.
* Hosts an OutlineView that shows information about Accounts.
*/
public class AccountsBrowser extends JPanel {
private static final long serialVersionUID = 1L;
private final Outline outline;
private ExplorerManager em;
/**
* Creates new form AccountsBrowser
*/
public AccountsBrowser() {
initComponents();
outline = outlineView.getOutline();
outlineView.setPropertyColumns(
"device", Bundle.AccountNode_device(),
"type", Bundle.AccountNode_accountType(),
"count", Bundle.AccountNode_messageCount()
);
outline.setRootVisible(false);
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AccountNode_accountName());
outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
outline.setColumnSorted(3, false, 1); //it would be nice if the column index wasn't hardcoded
}
@Override
public void addNotify() {
super.addNotify();
em = ExplorerManager.find(this);
em.addPropertyChangeListener(evt -> {
if (ExplorerManager.PROP_ROOT_CONTEXT.equals(evt.getPropertyName())) {
SwingUtilities.invokeLater(this::setColumnWidths);
} else if (ExplorerManager.PROP_EXPLORED_CONTEXT.equals(evt.getPropertyName())) {
SwingUtilities.invokeLater(this::setColumnWidths);
}
});
}
private void setColumnWidths() {
int margin = 4;
int padding = 8;
final int rows = Math.min(100, outline.getRowCount());
for (int column = 0; column < outline.getModel().getColumnCount(); column++) {
int columnWidthLimit = 500;
int columnWidth = 0;
// find the maximum width needed to fit the values for the first 100 rows, at most
for (int row = 0; row < rows; row++) {
TableCellRenderer renderer = outline.getCellRenderer(row, column);
Component comp = outline.prepareRenderer(renderer, row, column);
columnWidth = Math.max(comp.getPreferredSize().width, columnWidth);
}
columnWidth += 2 * margin + padding; // add margin and regular padding
columnWidth = Math.min(columnWidth, columnWidthLimit);
outline.getColumnModel().getColumn(column).setPreferredWidth(columnWidth);
}
}
/**
* 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() {
outlineView = new org.openide.explorer.view.OutlineView();
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.openide.explorer.view.OutlineView outlineView;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,142 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 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;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.AccountDeviceInstance;
import org.sleuthkit.datamodel.CommunicationsFilter;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
class AccountsRootChildren extends ChildFactory<AccountDeviceInstanceKey> {
private static final Logger logger = Logger.getLogger(AccountsRootChildren.class.getName());
private final CommunicationsManager commsManager;
private final CommunicationsFilter commsFilter;
AccountsRootChildren(CommunicationsManager commsManager, CommunicationsFilter commsFilter) {
super();
this.commsManager = commsManager;
this.commsFilter = commsFilter;
}
@Override
protected boolean createKeys(List<AccountDeviceInstanceKey> list) {
List<AccountDeviceInstanceKey> accountDeviceInstanceKeys = new ArrayList<>();
try {
for (AccountDeviceInstance adi : commsManager.getAccountDeviceInstancesWithRelationships(commsFilter)) {
long communicationsCount = commsManager.getRelationshipSourcesCount(adi, commsFilter);
accountDeviceInstanceKeys.add(new AccountDeviceInstanceKey(adi, commsFilter, communicationsCount));
};
} catch (TskCoreException tskCoreException) {
logger.log(Level.SEVERE, "Error getting filtered account device instances", tskCoreException);
}
list.addAll(accountDeviceInstanceKeys);
return true;
}
@Override
protected Node createNodeForKey(AccountDeviceInstanceKey key) {
return new AccountDeviceInstanceNode(key, commsManager);
}
/**
* Node to represent an Account in the AccountsBrowser
*/
static class AccountDeviceInstanceNode extends AbstractNode {
private final AccountDeviceInstanceKey accountDeviceInstanceKey;
private final CommunicationsManager commsManager;
private final Account account;
private AccountDeviceInstanceNode(AccountDeviceInstanceKey accountDeviceInstanceKey, CommunicationsManager commsManager) {
super(Children.LEAF, Lookups.fixed(accountDeviceInstanceKey, commsManager));
this.accountDeviceInstanceKey = accountDeviceInstanceKey;
this.commsManager = commsManager;
this.account = accountDeviceInstanceKey.getAccountDeviceInstance().getAccount();
setName(account.getTypeSpecificID());
setIconBaseWithExtension("org/sleuthkit/autopsy/communications/images/" + Utils.getIconFileName(account.getAccountType()));
}
public AccountDeviceInstance getAccountDeviceInstance() {
return accountDeviceInstanceKey.getAccountDeviceInstance();
}
public CommunicationsManager getCommsManager() {
return commsManager;
}
public CommunicationsFilter getFilter() {
return accountDeviceInstanceKey.getCommunicationsFilter();
}
@Override
@NbBundle.Messages(value = {"AccountNode.device=Device",
"AccountNode.accountName=Account",
"AccountNode.accountType=Type",
"AccountNode.messageCount=Msgs"})
protected Sheet createSheet() {
Sheet s = super.createSheet();
Sheet.Set properties = s.get(Sheet.PROPERTIES);
if (properties == null) {
properties = Sheet.createPropertiesSet();
s.put(properties);
}
properties.put(new NodeProperty<>("type", Bundle.AccountNode_accountType(), "type",
account.getAccountType().getDisplayName())); // NON-NLS
properties.put(new NodeProperty<>("count", Bundle.AccountNode_messageCount(), "count",
accountDeviceInstanceKey.getMessageCount())); // NON-NLS
properties.put(new NodeProperty<>("device", Bundle.AccountNode_device(), "device",
getDataSourceName())); // NON-NLS
return s;
}
private String getDataSourceName() {
try {
final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase();
for (DataSource dataSource : sleuthkitCase.getDataSources()) {
if (dataSource.getDeviceId().equals(getAccountDeviceInstance().getDeviceId())) {
return sleuthkitCase.getContentById(dataSource.getId()).getName();
}
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting datasource name, falling back on device ID.", ex);
}
return getAccountDeviceInstance().getDeviceId();
}
}
}

View File

@ -0,0 +1,14 @@
CVTTopComponent.TabConstraints.tabTitle=Visualize
CVTTopComponent.accountsBrowser.TabConstraints.tabTitle=Browse
FiltersPanel.applyFiltersButton.text=Apply
FiltersPanel.devicesLabel.text=Devices:
FiltersPanel.accountTypesLabel.text=Account Types:
FiltersPanel.filtersTitleLabel.text=Filters
FiltersPanel.unCheckAllAccountTypesButton.text=Uncheck All
FiltersPanel.checkAllAccountTypesButton.text=Check All
FiltersPanel.unCheckAllDevicesButton.text=Uncheck All
FiltersPanel.checkAllDevicesButton.text=Check All
FiltersPanel.dateRangeLabel.text=Date Range:
FiltersPanel.startCheckBox.text=Start:
FiltersPanel.endCheckBox.text=End:
FiltersPanel.refreshButton.text=Refresh

View File

@ -0,0 +1,120 @@
<?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"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Component id="filtersPane" min="-2" pref="250" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="splitPane" pref="1339" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="filtersPane" max="32767" attributes="0"/>
<Component id="splitPane" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="splitPane">
<Properties>
<Property name="dividerLocation" type="int" value="400"/>
<Property name="resizeWeight" type="double" value="0.7"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JTabbedPane" name="browseVisualizeTabPane">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="18" style="0"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
<JSplitPaneConstraints position="left"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
<SubComponents>
<Component class="org.sleuthkit.autopsy.communications.AccountsBrowser" name="accountsBrowser">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="Browse">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="CVTTopComponent.accountsBrowser.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="tabIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/table.png"/>
</Property>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
</Component>
<Container class="javax.swing.JPanel" name="jPanel1">
<Properties>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="Visualize">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="CVTTopComponent.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="tabIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/emblem-web.png"/>
</Property>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="397" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="725" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Component class="org.sleuthkit.autopsy.communications.FiltersPanel" name="filtersPane">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[256, 495]"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,158 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 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;
import java.util.List;
import java.util.stream.Collectors;
import org.openide.explorer.ExplorerManager;
import org.openide.util.NbBundle;
import org.openide.windows.Mode;
import org.openide.windows.RetainLocation;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
/**
* Top component which displays the Communications Visualization Tool.
*/
@TopComponent.Description(
preferredID = "CVTTopComponent",
//iconBase="SET/PATH/TO/ICON/HERE", //use this to put icon in window title area,
persistenceType = TopComponent.PERSISTENCE_NEVER)
@TopComponent.Registration(mode = "cvt", openAtStartup = false)
@RetainLocation("cvt")
@NbBundle.Messages("CVTTopComponent.name= Communications Visualization")
public final class CVTTopComponent extends TopComponent implements ExplorerManager.Provider {
private static final long serialVersionUID = 1L;
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
private final ExplorerManager em = new ExplorerManager();
public CVTTopComponent() {
initComponents();
browseVisualizeTabPane.setEnabledAt(1, false);
setName(Bundle.CVTTopComponent_name());
splitPane.setRightComponent(new MessageBrowser());
}
/**
* 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.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
splitPane = new javax.swing.JSplitPane();
browseVisualizeTabPane = new javax.swing.JTabbedPane();
accountsBrowser = new org.sleuthkit.autopsy.communications.AccountsBrowser();
jPanel1 = new javax.swing.JPanel();
filtersPane = new org.sleuthkit.autopsy.communications.FiltersPanel();
splitPane.setDividerLocation(400);
splitPane.setResizeWeight(0.7);
browseVisualizeTabPane.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
browseVisualizeTabPane.addTab(org.openide.util.NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.accountsBrowser.TabConstraints.tabTitle"), new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/table.png")), accountsBrowser); // NOI18N
jPanel1.setName(""); // NOI18N
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 397, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 725, Short.MAX_VALUE)
);
browseVisualizeTabPane.addTab(org.openide.util.NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.TabConstraints.tabTitle"), new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/emblem-web.png")), jPanel1); // NOI18N
splitPane.setLeftComponent(browseVisualizeTabPane);
filtersPane.setMinimumSize(new java.awt.Dimension(256, 495));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(6, 6, 6)
.addComponent(filtersPane, javax.swing.GroupLayout.PREFERRED_SIZE, 250, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(splitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1339, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(6, 6, 6)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(filtersPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(splitPane))
.addGap(5, 5, 5))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.communications.AccountsBrowser accountsBrowser;
private javax.swing.JTabbedPane browseVisualizeTabPane;
private org.sleuthkit.autopsy.communications.FiltersPanel filtersPane;
private javax.swing.JPanel jPanel1;
private javax.swing.JSplitPane splitPane;
// End of variables declaration//GEN-END:variables
@Override
public void componentOpened() {
super.componentOpened();
WindowManager.getDefault().setTopComponentFloating(this, true);
}
@Override
public ExplorerManager getExplorerManager() {
return em;
}
@Override
public void open() {
super.open();
/*
* when the window is (re)opened make sure the filters and accounts are
* in an up to date and consistent state.
*
* Re-applying the filters means we will lose the selection...
*/
filtersPane.updateAndApplyFilters();
}
@Override
public List<Mode> availableModes(List<Mode> modes) {
/*
* This looks like the right thing to do, but online discussions seems
* to indicate this method is effectively deprecated. A break point
* placed here was never hit.
*/
return modes.stream().filter(mode -> mode.getName().equals("cvt"))
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,364 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" 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="false"/>
<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="18"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jPanel3" max="32767" attributes="0"/>
<Component id="jPanel2" alignment="1" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="filtersTitleLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="applyFiltersButton" min="-2" pref="83" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="refreshButton" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="jPanel4" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="filtersTitleLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="applyFiltersButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="refreshButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" min="-2" max="-2" attributes="0"/>
<Component id="jPanel3" max="32767" attributes="0"/>
<EmptySpace type="separate" min="-2" max="-2" attributes="0"/>
<Component id="jPanel2" max="32767" attributes="0"/>
<EmptySpace type="separate" min="-2" max="-2" attributes="0"/>
<Component id="jPanel4" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="21" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="applyFiltersButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/tick.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.applyFiltersButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="null"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="filtersTitleLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/funnel.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.filtersTitleLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="16" style="0"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="jPanel2">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="accountTypesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="jScrollPane3" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="unCheckAllAccountTypesButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="checkAllAccountTypesButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="accountTypesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="jScrollPane3" pref="245" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="checkAllAccountTypesButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="unCheckAllAccountTypesButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="unCheckAllAccountTypesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.unCheckAllAccountTypesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="unCheckAllAccountTypesButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="accountTypesLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/accounts.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.accountTypesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="checkAllAccountTypesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.checkAllAccountTypesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="checkAllAccountTypesButtonActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane3">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="accountTypePane">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
<Property name="axis" type="int" value="1"/>
</Layout>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="jPanel3">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="devicesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="unCheckAllDevicesButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="checkAllDevicesButton" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="jScrollPane2" alignment="1" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="devicesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane2" pref="96" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="checkAllDevicesButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="unCheckAllDevicesButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="5" pref="5" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="unCheckAllDevicesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.unCheckAllDevicesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="unCheckAllDevicesButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="devicesLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/image.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.devicesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="checkAllDevicesButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.checkAllDevicesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="checkAllDevicesButtonActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane2">
<Properties>
<Property name="horizontalScrollBarPolicy" type="int" value="31"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[27, 75]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="devicesPane">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[4, 100]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
<Property name="axis" type="int" value="1"/>
</Layout>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="jPanel4">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="dateRangeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="endCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="endDatePicker" min="-2" pref="163" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="startCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="startDatePicker" min="-2" pref="162" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="dateRangeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="startDatePicker" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="startCheckBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="endDatePicker" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="endCheckBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="com.github.lgooddatepicker.components.DatePicker" name="startDatePicker">
<Properties>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="dateRangeLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/calendar.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.dateRangeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="startCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.startCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="startCheckBoxStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="endCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.endCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="endCheckBoxStateChanged"/>
</Events>
</Component>
<Component class="com.github.lgooddatepicker.components.DatePicker" name="endDatePicker">
<Properties>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="refreshButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.refreshButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,556 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 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;
import com.google.common.collect.ImmutableSet;
import java.beans.PropertyChangeListener;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.swing.JCheckBox;
import org.openide.explorer.ExplorerManager;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import static org.sleuthkit.autopsy.casemodule.Case.Events.CURRENT_CASE;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.ingest.IngestManager;
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.DATA_ADDED;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.CommunicationsFilter;
import org.sleuthkit.datamodel.CommunicationsFilter.AccountTypeFilter;
import org.sleuthkit.datamodel.CommunicationsFilter.DateRangeFilter;
import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.DataSource;
import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG;
import static org.sleuthkit.datamodel.Relationship.Type.MESSAGE;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Panel that holds the Filter control widgets and translates user filtering
* changes into queries against the CommunicationsManager.
*/
final public class FiltersPanel extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(FiltersPanel.class.getName());
private static final long serialVersionUID = 1L;
private ExplorerManager em;
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
private final Map<Account.Type, JCheckBox> accountTypeMap = new HashMap<>();
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
private final Map<String, JCheckBox> devicesMap = new HashMap<>();
private final PropertyChangeListener ingestListener;
@NbBundle.Messages({"refreshText=Refresh Results",
"applyText=Apply"})
public FiltersPanel() {
initComponents();
startDatePicker.setDate(LocalDate.now().minusWeeks(3));
endDatePicker.setDateToToday();
startDatePicker.getSettings().setVetoPolicy(
//no end date, or start is before end
startDate -> endCheckBox.isSelected() == false
|| startDate.compareTo(endDatePicker.getDate()) <= 0
);
endDatePicker.getSettings().setVetoPolicy(
//no start date, or end is after start
endDate -> startCheckBox.isSelected() == false
|| endDate.compareTo(startDatePicker.getDate()) >= 0
);
updateTimeZone();
updateFilters();
UserPreferences.addChangeListener(preferenceChangeEvent -> {
if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME)) {
updateTimeZone();
}
});
this.ingestListener = pce -> {
String eventType = pce.getPropertyName();
if (eventType.equals(DATA_ADDED.toString())) {
updateFilters();
refreshButton.setEnabled(true);
}
};
applyFiltersButton.addActionListener(e -> applyFilters());
refreshButton.addActionListener(e -> applyFilters());
}
/**
* Update the filter widgets, and apply them.
*/
void updateAndApplyFilters() {
updateFilters();
if (em != null) {
applyFilters();
}
}
private void updateTimeZone() {
dateRangeLabel.setText("Date Range ( " + Utils.getUserPreferredZoneId().toString() + "):");
}
private void updateFilters() {
updateAccountTypeFilter();
updateDeviceFilter();
}
@Override
public void addNotify() {
super.addNotify();
/*
* Since we get the exploreremanager from the parent JComponenet, wait
* till this FiltersPanel is actaully added to a parent.
*/
em = ExplorerManager.find(this);
IngestManager.getInstance().addIngestModuleEventListener(ingestListener);
Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> {
devicesMap.clear();
devicesPane.removeAll();
});
}
@Override
public void removeNotify() {
super.removeNotify();
IngestManager.getInstance().removeIngestModuleEventListener(ingestListener);
}
/**
* Populate the Account Types filter widgets
*/
private void updateAccountTypeFilter() {
//TODO: something like this commented code could be used to show only
//the account types that are found:
//final CommunicationsManager communicationsManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
//List<Account.Type> accountTypesInUse = communicationsManager.getAccountTypesInUse();
//accountTypesInUSe.forEach(...)
Account.Type.PREDEFINED_ACCOUNT_TYPES.forEach(type -> {
if (type.equals(Account.Type.CREDIT_CARD)) {
//don't show a check box for credit cards
} else if (type.equals(Account.Type.DEVICE)) {
//don't show a check box fro device
} else {
accountTypeMap.computeIfAbsent(type, t -> {
final JCheckBox jCheckBox = new JCheckBox(
"<html><table cellpadding=0><tr><td><img src=\""
+ FiltersPanel.class.getResource("/org/sleuthkit/autopsy/communications/images/"
+ Utils.getIconFileName(type))
+ "\"/></td><td width=" + 3 + "><td>" + type.getDisplayName() + "</td></tr></table></html>",
true
);
accountTypePane.add(jCheckBox);
return jCheckBox;
});
}
}
);
}
/**
* Populate the devices filter widgets
*/
private void updateDeviceFilter() {
try {
final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase();
for (DataSource dataSource : sleuthkitCase.getDataSources()) {
String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName();
//store the device id in the map, but display a datasource name in the UI.
devicesMap.computeIfAbsent(dataSource.getDeviceId(), ds -> {
final JCheckBox jCheckBox = new JCheckBox(dsName, false);
devicesPane.add(jCheckBox);
return jCheckBox;
});
};
} catch (IllegalStateException ex) {
logger.log(Level.WARNING, "Communications Visualization Tool opened with no open case.", ex);
} catch (TskCoreException tskCoreException) {
logger.log(Level.SEVERE, "There was a error loading the datasources for the case.", tskCoreException);
}
}
/**
* 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() {
applyFiltersButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/tick.png"))); // NOI18N
applyFiltersButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.applyFiltersButton.text")); // NOI18N
applyFiltersButton.setPreferredSize(null);
filtersTitleLabel.setFont(new java.awt.Font("Tahoma", 0, 16)); // NOI18N
filtersTitleLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/funnel.png"))); // NOI18N
filtersTitleLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.filtersTitleLabel.text")); // NOI18N
unCheckAllAccountTypesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.unCheckAllAccountTypesButton.text")); // NOI18N
unCheckAllAccountTypesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
unCheckAllAccountTypesButtonActionPerformed(evt);
}
});
accountTypesLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/accounts.png"))); // NOI18N
accountTypesLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.accountTypesLabel.text")); // NOI18N
checkAllAccountTypesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.checkAllAccountTypesButton.text")); // NOI18N
checkAllAccountTypesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
checkAllAccountTypesButtonActionPerformed(evt);
}
});
accountTypePane.setLayout(new javax.swing.BoxLayout(accountTypePane, javax.swing.BoxLayout.Y_AXIS));
jScrollPane3.setViewportView(accountTypePane);
javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
jPanel2.setLayout(jPanel2Layout);
jPanel2Layout.setHorizontalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel2Layout.createSequentialGroup()
.addComponent(accountTypesLabel)
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(jPanel2Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jScrollPane3)
.addGroup(jPanel2Layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(unCheckAllAccountTypesButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(checkAllAccountTypesButton)))))
.addGap(0, 0, 0))
);
jPanel2Layout.setVerticalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addComponent(accountTypesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 245, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(checkAllAccountTypesButton)
.addComponent(unCheckAllAccountTypesButton)))
);
unCheckAllDevicesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.unCheckAllDevicesButton.text")); // NOI18N
unCheckAllDevicesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
unCheckAllDevicesButtonActionPerformed(evt);
}
});
devicesLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/image.png"))); // NOI18N
devicesLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.devicesLabel.text")); // NOI18N
checkAllDevicesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.checkAllDevicesButton.text")); // NOI18N
checkAllDevicesButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
checkAllDevicesButtonActionPerformed(evt);
}
});
jScrollPane2.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
jScrollPane2.setMinimumSize(new java.awt.Dimension(27, 75));
devicesPane.setMinimumSize(new java.awt.Dimension(4, 100));
devicesPane.setLayout(new javax.swing.BoxLayout(devicesPane, javax.swing.BoxLayout.Y_AXIS));
jScrollPane2.setViewportView(devicesPane);
javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
jPanel3.setLayout(jPanel3Layout);
jPanel3Layout.setHorizontalGroup(
jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel3Layout.createSequentialGroup()
.addComponent(devicesLabel)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(jPanel3Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel3Layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(unCheckAllDevicesButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(checkAllDevicesButton))
.addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
);
jPanel3Layout.setVerticalGroup(
jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel3Layout.createSequentialGroup()
.addComponent(devicesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 96, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(checkAllDevicesButton)
.addComponent(unCheckAllDevicesButton))
.addGap(5, 5, 5))
);
startDatePicker.setEnabled(false);
dateRangeLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/calendar.png"))); // NOI18N
dateRangeLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.dateRangeLabel.text")); // NOI18N
startCheckBox.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.startCheckBox.text")); // NOI18N
startCheckBox.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
startCheckBoxStateChanged(evt);
}
});
endCheckBox.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.endCheckBox.text")); // NOI18N
endCheckBox.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
endCheckBoxStateChanged(evt);
}
});
endDatePicker.setEnabled(false);
javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4);
jPanel4.setLayout(jPanel4Layout);
jPanel4Layout.setHorizontalGroup(
jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel4Layout.createSequentialGroup()
.addComponent(dateRangeLabel)
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(jPanel4Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel4Layout.createSequentialGroup()
.addComponent(endCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(endDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, 163, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(jPanel4Layout.createSequentialGroup()
.addComponent(startCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(startDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, 162, javax.swing.GroupLayout.PREFERRED_SIZE))))
);
jPanel4Layout.setVerticalGroup(
jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel4Layout.createSequentialGroup()
.addComponent(dateRangeLabel)
.addGap(6, 6, 6)
.addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(startDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(startCheckBox))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(endDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(endCheckBox)))
);
refreshButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png"))); // NOI18N
refreshButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.refreshButton.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, 0)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jPanel2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(filtersTitleLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(applyFiltersButton, javax.swing.GroupLayout.PREFERRED_SIZE, 83, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(refreshButton))
.addComponent(jPanel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, 0)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(filtersTitleLabel)
.addComponent(applyFiltersButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(refreshButton))
.addGap(18, 18, 18)
.addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGap(18, 18, 18)
.addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGap(18, 18, 18)
.addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(21, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
/**
* Query for accounts using the selected filters, and send the results to
* the AccountsBrowser via the ExplorerManager.
*/
private void applyFilters() {
CommunicationsFilter commsFilter = new CommunicationsFilter();
commsFilter.addAndFilter(getDeviceFilter());
commsFilter.addAndFilter(getAccountTypeFilter());
commsFilter.addAndFilter(getDateRangeFilter());
commsFilter.addAndFilter(new CommunicationsFilter.RelationshipTypeFilter(
ImmutableSet.of(CALL_LOG, MESSAGE)));
try {
final CommunicationsManager commsManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
em.setRootContext(new AbstractNode(Children.create(new AccountsRootChildren(commsManager, commsFilter), true)));
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "There was an error getting the CommunicationsManager for the current case.", ex);
}
refreshButton.setEnabled(false);
}
/**
* Get a DeviceFilter that matches the state of the UI widgets.
*
* @return a DeviceFilter
*/
private DeviceFilter getDeviceFilter() {
DeviceFilter deviceFilter = new DeviceFilter(
devicesMap.entrySet().stream()
.filter(entry -> entry.getValue().isSelected())
.map(Entry::getKey)
.collect(Collectors.toSet()));
return deviceFilter;
}
/**
* Get an AccountTypeFilter that matches the state of the UI widgets
*
* @return an AccountTypeFilter
*/
private AccountTypeFilter getAccountTypeFilter() {
AccountTypeFilter accountTypeFilter = new AccountTypeFilter(accountTypeMap.entrySet().stream()
.filter(entry -> entry.getValue().isSelected())
.map(entry -> entry.getKey()).collect(Collectors.toSet()));
return accountTypeFilter;
}
private DateRangeFilter getDateRangeFilter() {
ZoneId zone = Utils.getUserPreferredZoneId();
long start = startDatePicker.isEnabled() ? startDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0;
long end = endDatePicker.isEnabled() ? endDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0;
return new DateRangeFilter(start, end);
}
/**
* Set the selection state of all the account type check boxes
*
* @param selected The selection state to set the check boxes to.
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
private void setAllAccountTypesSelected(boolean selected) {
setAllSelected(accountTypeMap, selected);
}
/**
* Set the selection state of all the device check boxes
*
* @param selected The selection state to set the check boxes to.
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
private void setAllDevicesSelected(boolean selected) {
setAllSelected(devicesMap, selected);
}
/**
* Helper method that sets all the checkboxes in the given map to the given
* selection state.
*
* @param map A map from anything to JCheckBoxes.
* @param selected The selection state to set all the checkboxes to.
*/
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
private void setAllSelected(Map<?, JCheckBox> map, boolean selected) {
map.values().forEach(box -> box.setSelected(selected));
}
private void unCheckAllAccountTypesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_unCheckAllAccountTypesButtonActionPerformed
setAllAccountTypesSelected(false);
}//GEN-LAST:event_unCheckAllAccountTypesButtonActionPerformed
private void checkAllAccountTypesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkAllAccountTypesButtonActionPerformed
setAllAccountTypesSelected(true);
}//GEN-LAST:event_checkAllAccountTypesButtonActionPerformed
private void unCheckAllDevicesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_unCheckAllDevicesButtonActionPerformed
setAllDevicesSelected(false);
}//GEN-LAST:event_unCheckAllDevicesButtonActionPerformed
private void checkAllDevicesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkAllDevicesButtonActionPerformed
setAllDevicesSelected(true);
}//GEN-LAST:event_checkAllDevicesButtonActionPerformed
private void startCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_startCheckBoxStateChanged
startDatePicker.setEnabled(startCheckBox.isSelected());
}//GEN-LAST:event_startCheckBoxStateChanged
private void endCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_endCheckBoxStateChanged
endDatePicker.setEnabled(endCheckBox.isSelected());
}//GEN-LAST:event_endCheckBoxStateChanged
// Variables declaration - do not modify//GEN-BEGIN:variables
private final javax.swing.JPanel accountTypePane = new javax.swing.JPanel();
private final javax.swing.JLabel accountTypesLabel = new javax.swing.JLabel();
private final javax.swing.JButton applyFiltersButton = new javax.swing.JButton();
private final javax.swing.JButton checkAllAccountTypesButton = new javax.swing.JButton();
private final javax.swing.JButton checkAllDevicesButton = new javax.swing.JButton();
private final javax.swing.JLabel dateRangeLabel = new javax.swing.JLabel();
private final javax.swing.JLabel devicesLabel = new javax.swing.JLabel();
private final javax.swing.JPanel devicesPane = new javax.swing.JPanel();
private final javax.swing.JCheckBox endCheckBox = new javax.swing.JCheckBox();
private final com.github.lgooddatepicker.components.DatePicker endDatePicker = new com.github.lgooddatepicker.components.DatePicker();
private final javax.swing.JLabel filtersTitleLabel = new javax.swing.JLabel();
private final javax.swing.JPanel jPanel2 = new javax.swing.JPanel();
private final javax.swing.JPanel jPanel3 = new javax.swing.JPanel();
private final javax.swing.JPanel jPanel4 = new javax.swing.JPanel();
private final javax.swing.JScrollPane jScrollPane2 = new javax.swing.JScrollPane();
private final javax.swing.JScrollPane jScrollPane3 = new javax.swing.JScrollPane();
private final javax.swing.JButton refreshButton = new javax.swing.JButton();
private final javax.swing.JCheckBox startCheckBox = new javax.swing.JCheckBox();
private final com.github.lgooddatepicker.components.DatePicker startDatePicker = new com.github.lgooddatepicker.components.DatePicker();
private final javax.swing.JButton unCheckAllAccountTypesButton = new javax.swing.JButton();
private final javax.swing.JButton unCheckAllDevicesButton = new javax.swing.JButton();
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,56 @@
<?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="false"/>
<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"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="splitPane" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="splitPane" pref="1083" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="splitPane">
<Properties>
<Property name="dividerLocation" type="int" value="400"/>
<Property name="dividerSize" type="int" value="10"/>
<Property name="orientation" type="int" value="0"/>
<Property name="resizeWeight" type="double" value="0.5"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
<SubComponents>
<Component class="org.sleuthkit.autopsy.communications.MessageDataContent" name="messageDataContent">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
<JSplitPaneConstraints position="bottom"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,155 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 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;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.openide.explorer.ExplorerManager;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.communications.AccountsRootChildren.AccountDeviceInstanceNode;
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
import org.sleuthkit.datamodel.AccountDeviceInstance;
import org.sleuthkit.datamodel.CommunicationsFilter;
import org.sleuthkit.datamodel.CommunicationsManager;
/**
* The right hand side of the CVT. Has a DataResultPanel to show messages and
* other account details, and a ContentViewer to show individual
*/
final class MessageBrowser extends javax.swing.JPanel implements ExplorerManager.Provider {
private static final long serialVersionUID = 1L;
private final DataResultPanel messagesResultPanel;
private final ExplorerManager explorerManager = new ExplorerManager();
private final DataResultViewerTable dataResultViewerTable = new DataResultViewerTable(explorerManager, "Messages");
;
MessageBrowser() {
initComponents();
//create an uninitialized DataResultPanel so we can control the ResultViewers that get added.
messagesResultPanel = DataResultPanel.createInstanceUninitialized("Account", "", Node.EMPTY, 0, messageDataContent);
splitPane.setTopComponent(messagesResultPanel);
splitPane.setBottomComponent(messageDataContent);
}
@Override
public void addNotify() {
super.addNotify();
ExplorerManager parentExplorereManager = ExplorerManager.find(this);
parentExplorereManager.addPropertyChangeListener(pce -> {
if (pce.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
final Node[] selectedNodes = parentExplorereManager.getSelectedNodes();
messagesResultPanel.setNumMatches(0);
messagesResultPanel.setNode(null);
if (selectedNodes.length == 0) {
//reset panel when there is no selection
messagesResultPanel.setPath("");
} else {
AccountDeviceInstanceNode adiNode = (AccountDeviceInstanceNode) selectedNodes[0];
CommunicationsFilter filter = adiNode.getFilter();
CommunicationsManager commsManager = adiNode.getCommsManager();
final Set<AccountDeviceInstance> accountDeviceInstances;
if (selectedNodes.length == 1) {
final AccountDeviceInstance accountDeviceInstance = adiNode.getAccountDeviceInstance();
accountDeviceInstances = Collections.singleton(accountDeviceInstance);
messagesResultPanel.setPath(accountDeviceInstance.getAccount().getTypeSpecificID());
} else {
accountDeviceInstances = Stream.of(selectedNodes)
.map(node -> (AccountDeviceInstanceNode) node)
.map(AccountDeviceInstanceNode::getAccountDeviceInstance)
.collect(Collectors.toSet());
messagesResultPanel.setPath(selectedNodes.length + " accounts");
}
AccountDetailsNode accountDetailsNode =
new AccountDetailsNode(accountDeviceInstances, filter, commsManager);
TableFilterNode wrappedNode =
new TableFilterNode(new DataResultFilterNode(accountDetailsNode, parentExplorereManager), true);
messagesResultPanel.setNode(wrappedNode);
}
}
});
//add the required result viewers and THEN open the panel
if (messagesResultPanel.getViewers().contains(dataResultViewerTable) == false) {
messagesResultPanel.addResultViewer(dataResultViewerTable);
}
messagesResultPanel.open();
}
@Override
public ExplorerManager getExplorerManager() {
return explorerManager;
}
/**
* 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() {
splitPane = new javax.swing.JSplitPane();
messageDataContent = new org.sleuthkit.autopsy.communications.MessageDataContent();
splitPane.setDividerLocation(400);
splitPane.setDividerSize(10);
splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
splitPane.setResizeWeight(0.5);
splitPane.setBottomComponent(messageDataContent);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(splitPane))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(splitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1083, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.communications.MessageDataContent messageDataContent;
private javax.swing.JSplitPane splitPane;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,37 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 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;
import java.beans.PropertyChangeEvent;
import org.sleuthkit.autopsy.contentviewers.MessageContentViewer;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
/**
* Extends MessageContentViewer so that it implements DataContent and can be set
* as the only ContentViewer for a DataResultPanel
*/
public class MessageDataContent extends MessageContentViewer implements DataContent {
private static final long serialVersionUID = 1L;
@Override
public void propertyChange(PropertyChangeEvent evt) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}

View File

@ -0,0 +1,107 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 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;
import java.awt.Component;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.awt.ActionRegistration;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.actions.CallableSystemAction;
import org.openide.util.actions.Presenter;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
/**
* Action that opens the CVT. Available through the Tools menu and the main
* toolbar.
*/
@ActionID(category = "Tools",
id = "org.sleuthkit.autopsy.communicationsVisualization.OpenCVTAction")
@ActionRegistration(displayName = "#CTL_OpenCVTAction", lazy = false)
@ActionReferences(value = {
@ActionReference(path = "Menu/Tools", position = 102)
, @ActionReference(path = "Toolbars/Case", position = 102)})
@Messages("CTL_OpenCVTAction=Visualize Communications")
public final class OpenCommVisualizationToolAction extends CallableSystemAction implements Presenter.Toolbar {
private static final long serialVersionUID = 1L;
private final JButton toolbarButton = new JButton(getName(),
new ImageIcon(getClass().getResource("images/emblem-web24.png"))); //NON-NLS
public OpenCommVisualizationToolAction() {
toolbarButton.addActionListener(actionEvent -> performAction());
setEnabled(false); //disabled by default. Will be enabled in Case.java when a case is opened.
}
@Override
public void performAction() {
final TopComponent tc = WindowManager.getDefault().findTopComponent("CVTTopComponent");
if (tc != null) {
if (tc.isOpened() == false) {
tc.open();
}
tc.toFront();
tc.requestActive();
}
}
/**
* Set this action to be enabled/disabled
*
* @param value whether to enable this action or not
*/
@Override
public void setEnabled(boolean value) {
super.setEnabled(value);
toolbarButton.setEnabled(value);
}
@Override
@NbBundle.Messages("OpenCVTAction.displayName=Communications Visualizaton")
public String getName() {
return Bundle.OpenCVTAction_displayName();
}
/**
* Returns the toolbar component of this action
*
* @return component the toolbar button
*/
@Override
public Component getToolbarPresenter() {
return toolbarButton;
}
@Override
public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}
@Override
public boolean asynchronous() {
return false; // run on edt
}
}

View File

@ -0,0 +1,147 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 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;
import java.util.TimeZone;
import java.util.logging.Level;
import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
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;
/**
* Node for a relationship, as represented by a BlackboardArtifact.
*/
public class RelationShipNode extends BlackboardArtifactNode {
private static final Logger logger = Logger.getLogger(RelationShipNode.class.getName());
public RelationShipNode(BlackboardArtifact artifact) {
super(artifact);
final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s");
String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message");
setDisplayName(removeEndIgnoreCase.isEmpty() ? stripEnd : removeEndIgnoreCase);
}
@Override
protected Sheet createSheet() {
Sheet s = new Sheet();
Sheet.Set ss = s.get(Sheet.PROPERTIES);
if (ss == null) {
ss = Sheet.createPropertiesSet();
s.put(ss);
}
ss.put(new NodeProperty<>("Type", "Type", "Type", getDisplayName()));
final BlackboardArtifact artifact = getArtifact();
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(getArtifact().getArtifactTypeID());
if (null != fromID) {
//Consider refactoring this to reduce boilerplate
switch (fromID) {
case TSK_EMAIL_MSG:
ss.put(new NodeProperty<>("From", "From", "From",
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_FROM), " \t\n;")));
ss.put(new NodeProperty<>("To", "To", "To",
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_TO), " \t\n;")));
ss.put(new NodeProperty<>("Date", "Date", "Date",
getAttributeDisplayString(artifact, TSK_DATETIME_SENT)));
ss.put(new NodeProperty<>("Subject", "Subject", "Subject",
getAttributeDisplayString(artifact, TSK_SUBJECT)));
try {
ss.put(new NodeProperty<>("Attms", "Attms", "Attms", artifact.getChildrenCount()));
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex);
}
break;
case TSK_MESSAGE:
ss.put(new NodeProperty<>("From", "From", "From",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM)));
ss.put(new NodeProperty<>("To", "To", "To",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO)));
ss.put(new NodeProperty<>("Date", "Date", "Date",
getAttributeDisplayString(artifact, TSK_DATETIME)));
ss.put(new NodeProperty<>("Subject", "Subject", "Subject",
getAttributeDisplayString(artifact, TSK_SUBJECT)));
try {
ss.put(new NodeProperty<>("Attms", "Attms", "Attms", artifact.getChildrenCount()));
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex);
}
break;
case TSK_CALLLOG:
ss.put(new NodeProperty<>("From", "From", "From",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM)));
ss.put(new NodeProperty<>("To", "To", "To",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO)));
ss.put(new NodeProperty<>("Date", "Date", "Date",
getAttributeDisplayString(artifact, TSK_DATETIME_START)));
break;
default:
break;
}
}
return s;
}
/**
*
* 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 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);
return "";
}
}
}

View File

@ -0,0 +1,72 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 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;
import java.time.ZoneId;
import java.time.ZoneOffset;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.datamodel.Account;
/**
* Utility class with helpers for dealing with accounts.
*/
class Utils {
private Utils() {
}
static ZoneId getUserPreferredZoneId() {
ZoneId zone = UserPreferences.displayTimesInLocalTime() ? ZoneOffset.systemDefault() : ZoneOffset.UTC;
return zone;
}
/**
* The file name of the icon for the given Account Type. Will not include
* the path but will include the extension.
*
* @return The file name of the icon for the given Account Type.
*/
static final String getIconFileName(Account.Type type) {
if (type.equals(Account.Type.CREDIT_CARD)) {
return "credit-card.png";
} else if (type.equals(Account.Type.DEVICE)) {
return "image.png";
} else if (type.equals(Account.Type.EMAIL)) {
return "email.png";
} else if (type.equals(Account.Type.FACEBOOK)) {
return "facebook.png";
} else if (type.equals(Account.Type.INSTAGRAM)) {
return "instagram.png";
} else if (type.equals(Account.Type.MESSAGING_APP)) {
return "messaging.png";
} else if (type.equals(Account.Type.PHONE)) {
return "phone.png";
} else if (type.equals(Account.Type.TWITTER)) {
return "twitter.png";
} else if (type.equals(Account.Type.WEBSITE)) {
return "web-file.png";
} else if (type.equals(Account.Type.WHATSAPP)) {
return "WhatsApp.png";
} else {
//there could be a default icon instead...
throw new IllegalArgumentException("Unknown Account.Type: " + type.getTypeName());
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 864 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 887 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 804 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 B

View File

@ -17,3 +17,19 @@ Metadata.toolTip=Displays metadata about the file.
Metadata.nodeText.nonFilePassedIn=Non-file passed in Metadata.nodeText.nonFilePassedIn=Non-file passed in
Metadata.nodeText.text=From The Sleuth Kit istat Tool\: Metadata.nodeText.text=From The Sleuth Kit istat Tool\:
Metadata.nodeText.exceptionNotice.text=Error getting file metadata\: Metadata.nodeText.exceptionNotice.text=Error getting file metadata\:
MessageContentViewer.rtfbodyScrollPane.TabConstraints.tabTitle=RTF
MessageContentViewer.headersScrollPane.TabConstraints.tabTitle=Headers
MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle=Text
MessageContentViewer.htmlPane.TabConstraints.tabTitle=HTML
MessageContentViewer.fromText.text=from address goes here
MessageContentViewer.fromLabel.text=From:
MessageContentViewer.datetimeText.text=date goes here
MessageContentViewer.toText.text=to list goes here
MessageContentViewer.toLabel.text=To:
MessageContentViewer.ccText.text=cc list goes here
MessageContentViewer.subjectLabel.text=Subject:
MessageContentViewer.subjectText.text=subject goes here
MessageContentViewer.directionText.text=direction
MessageContentViewer.ccLabel.text=CC:
MessageContentViewer.attachmentsPanel.TabConstraints.tabTitle=Attachments
MessageContentViewer.viewInNewWindowButton.text=View in New Window

View File

@ -0,0 +1,395 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" 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"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="msgbodyTabbedPane" max="32767" attributes="0"/>
<Component id="envelopePanel" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
<Component id="envelopePanel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="msgbodyTabbedPane" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="envelopePanel">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="cc" green="cc" red="cc" type="rgb"/>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="fromLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="toLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="toText" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="directionText" min="-2" pref="66" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="fromText" max="32767" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="datetimeText" min="-2" pref="140" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<Group type="102" attributes="0">
<Component id="ccLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
<Component id="ccText" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="subjectLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="subjectText" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="fromLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="datetimeText" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="fromText" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="toLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="toText" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="directionText" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="ccLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="ccText" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="subjectLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="subjectText" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="fromLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.fromLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="datetimeText">
<Properties>
<Property name="horizontalAlignment" type="int" value="4"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.datetimeText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="fromText">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.fromText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="toLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.toLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="toText">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.toText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="ccLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.ccLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="ccText">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.ccText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="subjectLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.subjectLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="subjectText">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.subjectText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="directionText">
<Properties>
<Property name="horizontalAlignment" type="int" value="4"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.directionText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JTabbedPane" name="msgbodyTabbedPane">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="headersScrollPane">
<Properties>
<Property name="horizontalScrollBarPolicy" type="int" value="31"/>
<Property name="verticalScrollBarPolicy" type="int" value="22"/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="Headers">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.headersScrollPane.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="headersTextArea">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="columns" type="int" value="20"/>
<Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="5"/>
<Property name="wrapStyleWord" type="boolean" value="true"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="textbodyScrollPane">
<Properties>
<Property name="horizontalScrollBarPolicy" type="int" value="31"/>
<Property name="verticalScrollBarPolicy" type="int" value="22"/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="Text">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="textbodyTextArea">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="5"/>
<Property name="wrapStyleWord" type="boolean" value="true"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="htmlPane">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="HTML">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.htmlPane.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="htmlScrollPane" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<EmptySpace pref="533" max="32767" attributes="0"/>
<Component id="showImagesToggleButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="showImagesToggleButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="htmlScrollPane" pref="333" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="htmlScrollPane">
<Properties>
<Property name="verticalScrollBarPolicy" type="int" value="22"/>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextPane" name="htmlbodyTextPane">
<Properties>
<Property name="editable" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JToggleButton" name="showImagesToggleButton">
<Properties>
<Property name="text" type="java.lang.String" value="Show Images"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showImagesToggleButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="rtfbodyScrollPane">
<Properties>
<Property name="verticalScrollBarPolicy" type="int" value="22"/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="RTF">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.rtfbodyScrollPane.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextPane" name="rtfbodyTextPane">
<Properties>
<Property name="editable" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="attachmentsPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JTabbedPaneConstraints tabName="Attachments">
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.attachmentsPanel.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</JTabbedPaneConstraints>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="viewInNewWindowButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
</Group>
<Component id="attachmentsScrollPane" alignment="1" pref="647" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="viewInNewWindowButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="attachmentsScrollPane" pref="333" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="viewInNewWindowButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.viewInNewWindowButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="viewInNewWindowButtonActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="attachmentsScrollPane">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,658 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 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.contentviewers;
import java.awt.Component;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.swing.text.JTextComponent;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.openide.explorer.ExplorerManager;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE;
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_RCVD;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CC;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF;
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_HEADERS;
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.ATTRIBUTE_TYPE.TSK_TEXT;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Shows SMS/MMS/EMail messages
*/
@ServiceProvider(service = DataContentViewer.class, position = 4)
public class MessageContentViewer extends javax.swing.JPanel implements DataContentViewer {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(MessageContentViewer.class.getName());
private static final int HDR_TAB_INDEX = 0;
private static final int TEXT_TAB_INDEX = 1;
private static final int HTML_TAB_INDEX = 2;
private static final int RTF_TAB_INDEX = 3;
private static final int ATTM_TAB_INDEX = 4;
private final List<JTextComponent> textAreas;
/**
* Artifact currently being displayed
*/
private BlackboardArtifact artifact;
private final DataResultPanel drp;
private final ExplorerManager drpExplorerManager;
/**
* Creates new MessageContentViewer
*/
public MessageContentViewer() {
initComponents();
drp = DataResultPanel.createInstanceUninitialized("Attachments", "", Node.EMPTY, 0, null);
attachmentsScrollPane.setViewportView(drp);
msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, true);
textAreas = Arrays.asList(headersTextArea, textbodyTextArea, htmlbodyTextPane, rtfbodyTextPane);
Utilities.configureTextPaneAsHtml(htmlbodyTextPane);
Utilities.configureTextPaneAsRtf(rtfbodyTextPane);
resetComponent();
drp.open();
drpExplorerManager = drp.getExplorerManager();
drpExplorerManager.addPropertyChangeListener(evt
-> viewInNewWindowButton.setEnabled(drpExplorerManager.getSelectedNodes().length == 1));
}
/**
* 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() {
envelopePanel = new javax.swing.JPanel();
fromLabel = new javax.swing.JLabel();
datetimeText = new javax.swing.JLabel();
fromText = new javax.swing.JLabel();
toLabel = new javax.swing.JLabel();
toText = new javax.swing.JLabel();
ccLabel = new javax.swing.JLabel();
ccText = new javax.swing.JLabel();
subjectLabel = new javax.swing.JLabel();
subjectText = new javax.swing.JLabel();
directionText = new javax.swing.JLabel();
msgbodyTabbedPane = new javax.swing.JTabbedPane();
headersScrollPane = new javax.swing.JScrollPane();
headersTextArea = new javax.swing.JTextArea();
textbodyScrollPane = new javax.swing.JScrollPane();
textbodyTextArea = new javax.swing.JTextArea();
htmlPane = new javax.swing.JPanel();
htmlScrollPane = new javax.swing.JScrollPane();
htmlbodyTextPane = new javax.swing.JTextPane();
showImagesToggleButton = new javax.swing.JToggleButton();
rtfbodyScrollPane = new javax.swing.JScrollPane();
rtfbodyTextPane = new javax.swing.JTextPane();
attachmentsPanel = new javax.swing.JPanel();
viewInNewWindowButton = new javax.swing.JButton();
attachmentsScrollPane = new javax.swing.JScrollPane();
envelopePanel.setBackground(new java.awt.Color(204, 204, 204));
org.openide.awt.Mnemonics.setLocalizedText(fromLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.fromLabel.text")); // NOI18N
datetimeText.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
org.openide.awt.Mnemonics.setLocalizedText(datetimeText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.datetimeText.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(fromText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.fromText.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(toLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.toLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(toText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.toText.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(ccLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.ccLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(ccText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.ccText.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(subjectLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.subjectLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(subjectText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.subjectText.text")); // NOI18N
directionText.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
org.openide.awt.Mnemonics.setLocalizedText(directionText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.directionText.text")); // NOI18N
javax.swing.GroupLayout envelopePanelLayout = new javax.swing.GroupLayout(envelopePanel);
envelopePanel.setLayout(envelopePanelLayout);
envelopePanelLayout.setHorizontalGroup(
envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(envelopePanelLayout.createSequentialGroup()
.addGap(5, 5, 5)
.addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(envelopePanelLayout.createSequentialGroup()
.addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(fromLabel)
.addComponent(toLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(envelopePanelLayout.createSequentialGroup()
.addComponent(toText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(directionText, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(envelopePanelLayout.createSequentialGroup()
.addComponent(fromText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(datetimeText, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addGroup(envelopePanelLayout.createSequentialGroup()
.addComponent(ccLabel)
.addGap(26, 26, 26)
.addComponent(ccText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(envelopePanelLayout.createSequentialGroup()
.addComponent(subjectLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(subjectText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGap(5, 5, 5))
);
envelopePanelLayout.setVerticalGroup(
envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(envelopePanelLayout.createSequentialGroup()
.addGap(5, 5, 5)
.addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(fromLabel)
.addComponent(datetimeText)
.addComponent(fromText))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(toLabel)
.addComponent(toText)
.addComponent(directionText))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(ccLabel)
.addComponent(ccText))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(subjectLabel)
.addComponent(subjectText))
.addGap(5, 5, 5))
);
headersScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
headersScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
headersTextArea.setEditable(false);
headersTextArea.setColumns(20);
headersTextArea.setLineWrap(true);
headersTextArea.setRows(5);
headersTextArea.setWrapStyleWord(true);
headersScrollPane.setViewportView(headersTextArea);
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.headersScrollPane.TabConstraints.tabTitle"), headersScrollPane); // NOI18N
textbodyScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
textbodyScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
textbodyTextArea.setEditable(false);
textbodyTextArea.setLineWrap(true);
textbodyTextArea.setRows(5);
textbodyTextArea.setWrapStyleWord(true);
textbodyScrollPane.setViewportView(textbodyTextArea);
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle"), textbodyScrollPane); // NOI18N
htmlScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
htmlbodyTextPane.setEditable(false);
htmlScrollPane.setViewportView(htmlbodyTextPane);
org.openide.awt.Mnemonics.setLocalizedText(showImagesToggleButton, "Show Images");
showImagesToggleButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showImagesToggleButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout htmlPaneLayout = new javax.swing.GroupLayout(htmlPane);
htmlPane.setLayout(htmlPaneLayout);
htmlPaneLayout.setHorizontalGroup(
htmlPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(htmlScrollPane)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, htmlPaneLayout.createSequentialGroup()
.addContainerGap(533, Short.MAX_VALUE)
.addComponent(showImagesToggleButton)
.addGap(3, 3, 3))
);
htmlPaneLayout.setVerticalGroup(
htmlPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(htmlPaneLayout.createSequentialGroup()
.addComponent(showImagesToggleButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(htmlScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 333, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.htmlPane.TabConstraints.tabTitle"), htmlPane); // NOI18N
rtfbodyScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
rtfbodyTextPane.setEditable(false);
rtfbodyScrollPane.setViewportView(rtfbodyTextPane);
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.rtfbodyScrollPane.TabConstraints.tabTitle"), rtfbodyScrollPane); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(viewInNewWindowButton, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.viewInNewWindowButton.text")); // NOI18N
viewInNewWindowButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
viewInNewWindowButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout attachmentsPanelLayout = new javax.swing.GroupLayout(attachmentsPanel);
attachmentsPanel.setLayout(attachmentsPanelLayout);
attachmentsPanelLayout.setHorizontalGroup(
attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(attachmentsPanelLayout.createSequentialGroup()
.addGap(0, 0, 0)
.addGroup(attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, attachmentsPanelLayout.createSequentialGroup()
.addComponent(viewInNewWindowButton)
.addGap(3, 3, 3))
.addComponent(attachmentsScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 647, Short.MAX_VALUE)))
);
attachmentsPanelLayout.setVerticalGroup(
attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(attachmentsPanelLayout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(viewInNewWindowButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(attachmentsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 333, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.attachmentsPanel.TabConstraints.tabTitle"), attachmentsPanel); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(5, 5, 5)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(msgbodyTabbedPane)
.addComponent(envelopePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGap(5, 5, 5))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(5, 5, 5)
.addComponent(envelopePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(msgbodyTabbedPane)
.addGap(5, 5, 5))
);
}// </editor-fold>//GEN-END:initComponents
@NbBundle.Messages({
"MessageContentViewer.showImagesToggleButton.hide.text=Hide Images",
"MessageContentViewer.showImagesToggleButton.text=Show Images"})
private void showImagesToggleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showImagesToggleButtonActionPerformed
try {
String htmlText = getAttributeValueSafe(artifact, TSK_EMAIL_CONTENT_HTML);
if (false == htmlText.isEmpty()) {
if (showImagesToggleButton.isSelected()) {
showImagesToggleButton.setText(Bundle.MessageContentViewer_showImagesToggleButton_hide_text());
this.htmlbodyTextPane.setText(wrapInHtmlBody(htmlText));
} else {
showImagesToggleButton.setText(Bundle.MessageContentViewer_showImagesToggleButton_text());
this.htmlbodyTextPane.setText(wrapInHtmlBody(cleanseHTML(htmlText)));
}
}
} catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "Failed to get attributes for email message.", ex); //NON-NLS
}
}//GEN-LAST:event_showImagesToggleButtonActionPerformed
private void viewInNewWindowButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewInNewWindowButtonActionPerformed
new NewWindowViewAction("View in new window", drpExplorerManager.getSelectedNodes()[0]).actionPerformed(evt);
}//GEN-LAST:event_viewInNewWindowButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JPanel attachmentsPanel;
private javax.swing.JScrollPane attachmentsScrollPane;
private javax.swing.JLabel ccLabel;
private javax.swing.JLabel ccText;
private javax.swing.JLabel datetimeText;
private javax.swing.JLabel directionText;
private javax.swing.JPanel envelopePanel;
private javax.swing.JLabel fromLabel;
private javax.swing.JLabel fromText;
private javax.swing.JScrollPane headersScrollPane;
private javax.swing.JTextArea headersTextArea;
private javax.swing.JPanel htmlPane;
private javax.swing.JScrollPane htmlScrollPane;
private javax.swing.JTextPane htmlbodyTextPane;
private javax.swing.JTabbedPane msgbodyTabbedPane;
private javax.swing.JScrollPane rtfbodyScrollPane;
private javax.swing.JTextPane rtfbodyTextPane;
private javax.swing.JToggleButton showImagesToggleButton;
private javax.swing.JLabel subjectLabel;
private javax.swing.JLabel subjectText;
private javax.swing.JScrollPane textbodyScrollPane;
private javax.swing.JTextArea textbodyTextArea;
private javax.swing.JLabel toLabel;
private javax.swing.JLabel toText;
private javax.swing.JButton viewInNewWindowButton;
// End of variables declaration//GEN-END:variables
@Override
public void setNode(Node node) {
if (node == null) {
resetComponent();
return;
}
artifact = node.getLookup().lookup(BlackboardArtifact.class);
if (artifact == null) {
resetComponent();
return;
}
if (artifact.getArtifactTypeID() == TSK_MESSAGE.getTypeID()) {
displayMsg();
} else if (artifact.getArtifactTypeID() == TSK_EMAIL_MSG.getTypeID()) {
displayEmailMsg();
} else {
resetComponent();
}
}
@Override
@NbBundle.Messages("MessageContentViewer.title=Message")
public String getTitle() {
return Bundle.MessageContentViewer_title();
}
@Override
@NbBundle.Messages("MessageContentViewer.toolTip=Displays messages.")
public String getToolTip() {
return Bundle.MessageContentViewer_toolTip();
}
@Override
public DataContentViewer createInstance() {
return new MessageContentViewer();
}
@Override
public Component getComponent() {
return this;
}
@Override
final public void resetComponent() {
// reset all fields
fromText.setText("");
fromLabel.setEnabled(false);
toText.setText("");
toLabel.setEnabled(false);
ccText.setText("");
ccLabel.setEnabled(false);
subjectText.setText("");
subjectLabel.setEnabled(false);
datetimeText.setText("");
datetimeText.setEnabled(false);
directionText.setText("");
directionText.setEnabled(false);
headersTextArea.setText("");
rtfbodyTextPane.setText("");
htmlbodyTextPane.setText("");
textbodyTextArea.setText("");
drp.setNode(null);
msgbodyTabbedPane.setEnabled(false);
}
@Override
public boolean isSupported(Node node) {
BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
return ((artifact != null)
&& ((artifact.getArtifactTypeID() == TSK_EMAIL_MSG.getTypeID())
|| (artifact.getArtifactTypeID() == TSK_MESSAGE.getTypeID())));
}
@Override
public int isPreferred(Node node) {
if (isSupported(node)) {
return 6;
}
return 0;
}
/**
* Configure the text area at the given index to show the content of the
* given type.
*
* @param type The ATTRIBUT_TYPE to show in the indexed tab.
* @param index The index of the text area to configure.
*
* @throws TskCoreException
*/
private void configureTextArea(BlackboardAttribute.ATTRIBUTE_TYPE type, int index) throws TskCoreException {
String attributeText = getAttributeValueSafe(artifact, type);
if (index == HTML_TAB_INDEX && StringUtils.isNotBlank(attributeText)) {
//special case for HTML, we need to 'cleanse' it
attributeText = wrapInHtmlBody(cleanseHTML(attributeText));
}
JTextComponent textComponent = textAreas.get(index);
textComponent.setText(attributeText);
textComponent.setCaretPosition(0); //make sure we start at the top
final boolean hasText = attributeText.length() > 0;
msgbodyTabbedPane.setEnabledAt(index, hasText);
if (hasText) {
msgbodyTabbedPane.setSelectedIndex(index);
}
}
private void enableCommonFields() {
msgbodyTabbedPane.setEnabled(true);
fromLabel.setEnabled(true);
toLabel.setEnabled(true);
subjectLabel.setEnabled(true);
datetimeText.setEnabled(true);
}
private void configureAttachments() throws TskCoreException {
//TODO: Replace this with code to get the actual attachements!
final Set<AbstractFile> attachments = artifact.getChildren().stream()
.filter(AbstractFile.class::isInstance)
.map(AbstractFile.class::cast)
.collect(Collectors.toSet());
final int numberOfAttachments = attachments.size();
msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, numberOfAttachments > 0);
msgbodyTabbedPane.setTitleAt(ATTM_TAB_INDEX, "Attachments (" + numberOfAttachments + ")");
drp.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(
new AttachmentsChildren(attachments)), null), true));
}
private static String wrapInHtmlBody(String htmlText) {
return "<html><body>" + htmlText + "</body></html>";
}
private void displayEmailMsg() {
enableCommonFields();
directionText.setEnabled(false);
ccLabel.setEnabled(true);
showImagesToggleButton.setText("Show Images");
showImagesToggleButton.setSelected(false);
try {
this.fromText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_FROM));
this.toText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_TO));
this.directionText.setText("");
this.ccText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_CC));
this.subjectText.setText(getAttributeValueSafe(artifact, TSK_SUBJECT));
this.datetimeText.setText(getAttributeValueSafe(artifact, TSK_DATETIME_RCVD));
configureTextArea(TSK_HEADERS, HDR_TAB_INDEX);
configureTextArea(TSK_EMAIL_CONTENT_PLAIN, TEXT_TAB_INDEX);
configureTextArea(TSK_EMAIL_CONTENT_HTML, HTML_TAB_INDEX);
configureTextArea(TSK_EMAIL_CONTENT_RTF, RTF_TAB_INDEX);
configureAttachments();
} catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "Failed to get attributes for email message.", ex); //NON-NLS
}
}
private void displayMsg() {
enableCommonFields();
directionText.setEnabled(true);
ccLabel.setEnabled(false);
try {
this.fromText.setText(getAttributeValueSafe(artifact, TSK_PHONE_NUMBER_FROM));
this.toText.setText(getAttributeValueSafe(artifact, TSK_PHONE_NUMBER_TO));
this.directionText.setText(getAttributeValueSafe(artifact, TSK_DIRECTION));
this.ccText.setText("");
this.subjectText.setText(getAttributeValueSafe(artifact, TSK_SUBJECT));
this.datetimeText.setText(getAttributeValueSafe(artifact, TSK_DATETIME));
msgbodyTabbedPane.setEnabledAt(HTML_TAB_INDEX, false);
msgbodyTabbedPane.setEnabledAt(RTF_TAB_INDEX, false);
msgbodyTabbedPane.setEnabledAt(HDR_TAB_INDEX, false);
msgbodyTabbedPane.setEnabledAt(HDR_TAB_INDEX, false);
configureTextArea(TSK_TEXT, TEXT_TAB_INDEX);
configureAttachments();
} catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "Failed to get attributes for message.", ex); //NON-NLS
}
}
private static String getAttributeValueSafe(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) throws TskCoreException {
return Optional.ofNullable(artifact.getAttribute(new BlackboardAttribute.Type(type)))
.map(BlackboardAttribute::getDisplayString)
.orElse("");
}
/**
* Cleans out input HTML string
*
* @param htmlInString The HTML string to cleanse
*
* @return The cleansed HTML String
*/
static private String cleanseHTML(String htmlInString) {
Document doc = Jsoup.parse(htmlInString);
//fix all img tags
doc.select("img[src]").forEach(img -> img.attr("src", ""));
return doc.html();
}
private static class AttachmentsChildren extends Children.Keys<AbstractFile> {
private final Set<AbstractFile> attachments;
AttachmentsChildren(Set<AbstractFile> attachments) {
this.attachments = attachments;
}
@Override
protected Node[] createNodes(AbstractFile t) {
return new Node[]{new AttachmentNode(t)};
}
@Override
protected void addNotify() {
super.addNotify();
setKeys(attachments);
}
}
/**
* Extension of FileNode customized for viewing attachments in the
* MessageContentViewer. It overrides createSheet() to customize what
* properties are shown in the table, and could also override getActions(),
* getPreferedAction(), etc.
*/
private static class AttachmentNode extends FileNode {
AttachmentNode(AbstractFile file) {
super(file, true);
}
@Override
protected Sheet createSheet() {
Sheet s = new Sheet();
Sheet.Set ss = s.get(Sheet.PROPERTIES);
if (ss == null) {
ss = Sheet.createPropertiesSet();
s.put(ss);
}
AbstractFile file = getContent();
ss.put(new NodeProperty<>("Name", "Name", "Name", file.getName()));
ss.put(new NodeProperty<>("Size", "Size", "Size", file.getSize()));
ss.put(new NodeProperty<>("Mime Type", "Mime Type", "Mime Type", StringUtils.defaultString(file.getMIMEType())));
ss.put(new NodeProperty<>("Known", "Known", "Known", file.getKnown().getName()));
addTagProperty(ss);
return s;
}
}
}

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.contentviewers;
import javax.swing.JTextPane; import javax.swing.JTextPane;
import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet; import javax.swing.text.html.StyleSheet;
import javax.swing.text.rtf.RTFEditorKit;
/** /**
* *
@ -47,4 +48,11 @@ public class Utilities {
styleSheet.addRule("th {font-family:Arial, 'ヒラギノ角ゴ Pro W3','Hiragino Kaku Gothic Pro','メイリオ',Meiryo,' Pゴシック','MS PGothic',sans-serif;font-size:14pt;overflow:hidden;padding-right:5px;padding-left:5px;font-weight:bold;}"); //NON-NLS styleSheet.addRule("th {font-family:Arial, 'ヒラギノ角ゴ Pro W3','Hiragino Kaku Gothic Pro','メイリオ',Meiryo,' Pゴシック','MS PGothic',sans-serif;font-size:14pt;overflow:hidden;padding-right:5px;padding-left:5px;font-weight:bold;}"); //NON-NLS
styleSheet.addRule("p {font-family:Arial, 'ヒラギノ角ゴ Pro W3','Hiragino Kaku Gothic Pro','メイリオ',Meiryo,' Pゴシック','MS PGothic',sans-serif;font-size:14pt;}"); //NON-NLS styleSheet.addRule("p {font-family:Arial, 'ヒラギノ角ゴ Pro W3','Hiragino Kaku Gothic Pro','メイリオ',Meiryo,' Pゴシック','MS PGothic',sans-serif;font-size:14pt;}"); //NON-NLS
} }
public static void configureTextPaneAsRtf(JTextPane pane) {
pane.setContentType("text/html;charset=UTF-8"); //NON-NLS
RTFEditorKit rtfkit = new RTFEditorKit();
pane.setEditorKit(rtfkit);
}
} }

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<mode version="2.4">
<name unique="cvt"/>
<kind type="editor"/>
<state type="separated"/>
<bounds x="76" y="68" width="996" height="672"/>
<frame state="0"/>
<empty-behavior permanent="false"/>
</mode>

View File

@ -443,6 +443,7 @@
<folder name="floatingLeftBottom"/> <folder name="floatingLeftBottom"/>
<file name="floatingLeftBottom.wsmode" url="floatingLeftBottomWsmode.xml"/> <file name="floatingLeftBottom.wsmode" url="floatingLeftBottomWsmode.xml"/>
<file name="timeline.wsmode" url="timelineWsmode.xml"/> <file name="timeline.wsmode" url="timelineWsmode.xml"/>
<file name="cvt.wsmode" url="cvtWsmode.xml"/>
</folder> </folder>
</folder> </folder>

View File

@ -20,12 +20,10 @@ package org.sleuthkit.autopsy.corecomponentinterfaces;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.windows.TopComponent;
/** /**
* The interface for the "bottom right component" window. * The interface for the "bottom right component" window.
* *
* @author jantonius
*/ */
public interface DataContent extends PropertyChangeListener { public interface DataContent extends PropertyChangeListener {

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013 Basis Technology Corp. * Copyright 2011-17 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -85,10 +85,13 @@ public interface DataResultViewer {
/** /**
* Set a custom content viewer to respond to selection events from this * Set a custom content viewer to respond to selection events from this
* result viewer. If not set, the default content viewer is user * result viewer. If not set, the default content viewer is used
* *
* @param contentViewer content viewer to respond to selection events from * @param contentViewer content viewer to respond to selection events from
* this viewer * this viewer
*
* @deprecated All implementations of this in the standard DataResultViewers are now no-ops.
*/ */
@Deprecated
public void setContentViewer(DataContent contentViewer); public void setContentViewer(DataContent contentViewer);
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013 Basis Technology Corp. * Copyright 2011-17 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -25,7 +25,6 @@ import javax.swing.JPanel;
import org.openide.explorer.ExplorerManager; import org.openide.explorer.ExplorerManager;
import org.openide.explorer.ExplorerManager.Provider; import org.openide.explorer.ExplorerManager.Provider;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -40,11 +39,6 @@ abstract class AbstractDataResultViewer extends JPanel implements DataResultView
private static final Logger logger = Logger.getLogger(AbstractDataResultViewer.class.getName()); private static final Logger logger = Logger.getLogger(AbstractDataResultViewer.class.getName());
protected transient ExplorerManager em; protected transient ExplorerManager em;
/**
* Content viewer to respond to selection events Either the main one, or
* custom one if set
*/
protected DataContent contentViewer;
/** /**
* This constructor is intended to allow an AbstractDataResultViewer to use * This constructor is intended to allow an AbstractDataResultViewer to use
@ -53,10 +47,11 @@ abstract class AbstractDataResultViewer extends JPanel implements DataResultView
* TopComponent has focus. The ExplorerManager must be present when the * TopComponent has focus. The ExplorerManager must be present when the
* object is constructed so that its child components can discover it using * object is constructed so that its child components can discover it using
* the ExplorerManager.find() method. * the ExplorerManager.find() method.
*
* @param explorerManager
*/ */
public AbstractDataResultViewer(ExplorerManager explorerManager) { AbstractDataResultViewer(ExplorerManager explorerManager) {
this.em = explorerManager; this.em = explorerManager;
initialize();
} }
/** /**
@ -65,14 +60,7 @@ abstract class AbstractDataResultViewer extends JPanel implements DataResultView
* context lookup. * context lookup.
*/ */
public AbstractDataResultViewer() { public AbstractDataResultViewer() {
em = new ExplorerManager(); this(new ExplorerManager());
initialize();
}
private void initialize() {
//DataContent is designed to return only the default viewer from lookup
//use the default one unless set otherwise
contentViewer = Lookup.getDefault().lookup(DataContent.class);
} }
@Override @Override
@ -115,8 +103,8 @@ abstract class AbstractDataResultViewer extends JPanel implements DataResultView
} }
} }
@Deprecated
@Override @Override
public void setContentViewer(DataContent contentViewer) { public void setContentViewer(DataContent contentViewer) {
this.contentViewer = contentViewer;
} }
} }

View File

@ -22,6 +22,7 @@ import java.awt.Cursor;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import javax.swing.JTabbedPane; import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
@ -64,7 +65,7 @@ import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo;
* normally docked into the lower right hand side of the main window, underneath * normally docked into the lower right hand side of the main window, underneath
* the results view. A custom content view may be specified instead. * the results view. A custom content view may be specified instead.
*/ */
public class DataResultPanel extends javax.swing.JPanel implements DataResult, ChangeListener { public class DataResultPanel extends javax.swing.JPanel implements DataResult, ChangeListener, ExplorerManager.Provider {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final int NO_TAB_SELECTED = -1; private static final int NO_TAB_SELECTED = -1;
@ -79,8 +80,8 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
private DataContent contentView; private DataContent contentView;
/** /**
* Constructs and opens a Swing JPanel with a JTabbedPane child component. * Constructs and opens a DataResultPanel with the given initial data, and
* The tabbed pane contains result viewers. * the default DataContent.
* *
* @param title The title for the panel. * @param title The title for the panel.
* @param pathText Descriptive text about the source of the nodes * @param pathText Descriptive text about the source of the nodes
@ -98,8 +99,8 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
} }
/** /**
* Constructs and opens a Swing JPanel with a JTabbedPane child component. * Constructs and opens a DataResultPanel with the given initial data, and a
* The tabbed pane contains result viewers. * custom DataContent.
* *
* @param title The title for the panel. * @param title The title for the panel.
* @param pathText Descriptive text about the source of the nodes * @param pathText Descriptive text about the source of the nodes
@ -119,9 +120,9 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
} }
/** /**
* Constructs a Swing JPanel with a JTabbedPane child component. The tabbed * Constructs a DataResultPanel with the given initial data, and a custom
* pane contains result viewers. The panel is NOT opened; the client of this * DataContent. The panel is NOT opened; the client of this method must call
* method must call open on the panel that is returned. * open on the panel that is returned.
* *
* @param title The title for the panel. * @param title The title for the panel.
* @param pathText Descriptive text about the source of the nodes * @param pathText Descriptive text about the source of the nodes
@ -159,42 +160,32 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
} }
/** /**
* Constructs a Swing JPanel with a JTabbedPane child component that * Constructs a DataResultPanel with the default DataContent
* contains result viewers (implementations of the DataResultViewer
* interface).
*/
private DataResultPanel() {
this.isMain = true;
initComponents();
}
/**
* Constructs a Swing JPanel with a JTabbedPane child component that
* contains result viewers (implementations of the DataResultViewer
* interface).
* *
* @param title The title for the panel. * @param title The title for the panel.
* @param isMain True if the DataResultPanel being constructed is the "main" * @param isMain True if the DataResultPanel being constructed is the "main"
* DataResultPanel. * DataResultPanel.
*/ */
DataResultPanel(String title, boolean isMain) { DataResultPanel(String title, boolean isMain) {
this(); this(isMain, Lookup.getDefault().lookup(DataContent.class));
setTitle(title);
}
private DataResultPanel(boolean isMain, DataContent contentView) {
this.isMain = isMain; this.isMain = isMain;
this.contentView = Lookup.getDefault().lookup(DataContent.class); this.contentView = contentView;
initComponents();
} }
/** /**
* Constructs a Swing JPanel with a JTabbedPane child component that * Constructs a DataResultPanel with the a custom DataContent.
* contains result viewers (implementations of the DataResultViewer
* interface).
* *
* @param title The title for the panel. * @param title The title for the panel.
* @param customContentView A content view to use in place of the default * @param customContentView A content view to use in place of the default
* content view. * content view.
*/ */
DataResultPanel(String title, DataContent customContentView) { DataResultPanel(String title, DataContent customContentView) {
this(title, false); this(false, customContentView);
this.contentView = customContentView;
} }
/** /**
@ -245,10 +236,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
* *
* @param resultViewer The result viewer. * @param resultViewer The result viewer.
*/ */
private void addResultViewer(DataResultViewer resultViewer) { public void addResultViewer(DataResultViewer resultViewer) {
if (null != contentView) {
resultViewer.setContentViewer(contentView);
}
resultViewers.add(resultViewer); resultViewers.add(resultViewer);
dataResultTabbedPanel.addTab(resultViewer.getTitle(), resultViewer.getComponent()); dataResultTabbedPanel.addTab(resultViewer.getTitle(), resultViewer.getComponent());
} }
@ -260,11 +248,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
*/ */
@Override @Override
public List<DataResultViewer> getViewers() { public List<DataResultViewer> getViewers() {
List<DataResultViewer> viewers = new ArrayList<>(); return Collections.unmodifiableList(resultViewers);
resultViewers.forEach((viewer) -> {
viewers.add(viewer);
});
return viewers;
} }
/** /**
@ -397,9 +381,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
* @param selectedNodes The nodes to be selected. * @param selectedNodes The nodes to be selected.
*/ */
public void setSelectedNodes(Node[] selectedNodes) { public void setSelectedNodes(Node[] selectedNodes) {
this.resultViewers.forEach((viewer) -> { this.resultViewers.forEach((viewer) -> viewer.setSelectedNodes(selectedNodes));
viewer.setSelectedNodes(selectedNodes);
});
} }
/** /**
@ -517,14 +499,10 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
explorerManager = null; explorerManager = null;
} }
this.resultViewers.forEach((viewer) -> { this.resultViewers.forEach((viewer) -> viewer.setNode(null));
viewer.setNode(null);
});
if (!this.isMain) { if (!this.isMain) {
this.resultViewers.forEach((viewer) -> { this.resultViewers.forEach(DataResultViewer::clearComponent);
viewer.clearComponent();
});
this.directoryTablePath.removeAll(); this.directoryTablePath.removeAll();
this.directoryTablePath = null; this.directoryTablePath = null;
this.numberMatchLabel.removeAll(); this.numberMatchLabel.removeAll();
@ -537,6 +515,11 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
} }
} }
@Override
public ExplorerManager getExplorerManager() {
return explorerManager;
}
/** /**
* Responds to node selection change events from the explorer manager. * Responds to node selection change events from the explorer manager.
*/ */
@ -563,9 +546,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
* Pass the selected nodes to all of the result viewers * Pass the selected nodes to all of the result viewers
* sharing this explorer manager. * sharing this explorer manager.
*/ */
resultViewers.forEach((viewer) -> { resultViewers.forEach((viewer) -> viewer.setSelectedNodes(selectedNodes));
viewer.setSelectedNodes(selectedNodes);
});
/* /*
* Passing null signals that either multiple nodes are * Passing null signals that either multiple nodes are

View File

@ -80,6 +80,9 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
@NbBundle.Messages("DataResultViewerTable.firstColLbl=Name") @NbBundle.Messages("DataResultViewerTable.firstColLbl=Name")
static private final String FIRST_COLUMN_LABEL = Bundle.DataResultViewerTable_firstColLbl(); static private final String FIRST_COLUMN_LABEL = Bundle.DataResultViewerTable_firstColLbl();
private static final Color TAGGED_COLOR = new Color(255, 255, 195); private static final Color TAGGED_COLOR = new Color(255, 255, 195);
private final String title;
/** /**
* The properties map: * The properties map:
* *
@ -108,17 +111,42 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
/** /**
* Listener for table model event and mouse clicks. * Listener for table model event and mouse clicks.
*/ */
private TableListener tableListener; private final TableListener tableListener;
/** /**
* Creates a DataResultViewerTable object that is compatible with node * Creates a DataResultViewerTable object that is compatible with node
* multiple selection actions. * multiple selection actions, and the default title.
* *
* @param explorerManager allow for explorer manager sharing * @param explorerManager allow for explorer manager sharing
*/ */
public DataResultViewerTable(ExplorerManager explorerManager) { public DataResultViewerTable(ExplorerManager explorerManager) {
this(explorerManager, Bundle.DataResultViewerTable_title());
}
/**
* Creates a DataResultViewerTable object that is compatible with node
* multiple selection actions, and a custom title.
*
* @param explorerManager allow for explorer manager sharing
* @param title The custom title.
*/
public DataResultViewerTable(ExplorerManager explorerManager, String title) {
super(explorerManager); super(explorerManager);
initialize(); this.title = title;
initComponents();
outlineView.setAllowedDragActions(DnDConstants.ACTION_NONE);
outline = outlineView.getOutline();
outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
outline.setRootVisible(false); // don't show the root node
outline.setDragEnabled(false);
outline.setDefaultRenderer(Object.class, new ColorTagCustomRenderer());
// add a listener so that when columns are moved, the new order is stored
tableListener = new TableListener();
outline.getColumnModel().addColumnModelListener(tableListener);
// the listener also moves columns back if user tries to move the first column out of place
outline.getTableHeader().addMouseListener(tableListener);
} }
/** /**
@ -126,26 +154,9 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
* multiple selection actions. * multiple selection actions.
*/ */
public DataResultViewerTable() { public DataResultViewerTable() {
initialize(); this(new ExplorerManager(),Bundle.DataResultViewerTable_title());
} }
private void initialize() {
initComponents();
outlineView.setAllowedDragActions(DnDConstants.ACTION_NONE);
outline = outlineView.getOutline();
outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
outline.setRootVisible(false); // don't show the root node
outline.setDragEnabled(false);
outline.setDefaultRenderer(Object.class, new ColorTagCustomRenderer());
// add a listener so that when columns are moved, the new order is stored
tableListener = new TableListener();
outline.getColumnModel().addColumnModelListener(tableListener);
// the listener also moves columns back if user tries to move the first column out of place
outline.getTableHeader().addMouseListener(tableListener);
}
/** /**
* Expand node * Expand node
@ -579,7 +590,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
@Override @Override
@NbBundle.Messages("DataResultViewerTable.title=Table") @NbBundle.Messages("DataResultViewerTable.title=Table")
public String getTitle() { public String getTitle() {
return Bundle.DataResultViewerTable_title(); return title;
} }
@Override @Override
@ -764,7 +775,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col); Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
// only override the color if a node is not selected // only override the color if a node is not selected
if (!isSelected) { if (currentRoot != null && !isSelected) {
Node node = currentRoot.getChildren().getNodeAt(table.convertRowIndexToModel(row)); Node node = currentRoot.getChildren().getNodeAt(table.convertRowIndexToModel(row));
boolean tagFound = false; boolean tagFound = false;
if (node != null) { if (node != null) {

View File

@ -61,6 +61,7 @@ public abstract class AbstractFsContentNode<T extends AbstractFile> extends Abst
} }
@Override @Override
@NbBundle.Messages("AbstractFsContentNode.noDesc.text=no description")
protected Sheet createSheet() { protected Sheet createSheet() {
Sheet s = super.createSheet(); Sheet s = super.createSheet();
Sheet.Set ss = s.get(Sheet.PROPERTIES); Sheet.Set ss = s.get(Sheet.PROPERTIES);
@ -72,7 +73,7 @@ public abstract class AbstractFsContentNode<T extends AbstractFile> extends Abst
Map<String, Object> map = new LinkedHashMap<>(); Map<String, Object> map = new LinkedHashMap<>();
fillPropertyMap(map, getContent()); fillPropertyMap(map, getContent());
final String NO_DESCR = NbBundle.getMessage(this.getClass(), "AbstractFsContentNode.noDesc.text"); final String NO_DESCR = Bundle.AbstractFsContentNode_noDesc_text();
for (AbstractFilePropertyType propType : AbstractFilePropertyType.values()) { for (AbstractFilePropertyType propType : AbstractFilePropertyType.values()) {
final String propString = propType.toString(); final String propString = propType.toString();
ss.put(new NodeProperty<>(propString, propString, NO_DESCR, map.get(propString))); ss.put(new NodeProperty<>(propString, propString, NO_DESCR, map.get(propString)));

View File

@ -2,7 +2,6 @@ OpenIDE-Module-Name=DataModel
AbstractContentChildren.CreateTSKNodeVisitor.exception.noNodeMsg=No Node defined for the given SleuthkitItem AbstractContentChildren.CreateTSKNodeVisitor.exception.noNodeMsg=No Node defined for the given SleuthkitItem
AbstractContentChildren.createAutopsyNodeVisitor.exception.noNodeMsg=No Node defined for the given DisplayableItem AbstractContentChildren.createAutopsyNodeVisitor.exception.noNodeMsg=No Node defined for the given DisplayableItem
AbstractContentNode.exception.cannotChangeSysName.msg=Cannot change the system name. AbstractContentNode.exception.cannotChangeSysName.msg=Cannot change the system name.
AbstractFsContentNode.noDesc.text=no description
ArtifactStringContent.getStr.srcFilePath.text=Source File Path ArtifactStringContent.getStr.srcFilePath.text=Source File Path
ArtifactStringContent.getStr.err=Error getting content ArtifactStringContent.getStr.err=Error getting content
ArtifactTypeNode.createSheet.artType.name=Artifact Type ArtifactTypeNode.createSheet.artType.name=Artifact Type

View File

@ -71,6 +71,7 @@ import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.AccountFileInstance;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
@ -294,13 +295,13 @@ final public class Accounts implements AutopsyVisitableItem {
@Override @Override
protected Node[] createNodes(String key) { protected Node[] createNodes(String key) {
try { try {
Account.Type accountType = Account.Type.valueOf(key); String accountType = key;
switch (accountType) { if (accountType.equals(Account.Type.CREDIT_CARD.getTypeName())) {
case CREDIT_CARD: return new Node[]{new CreditCardNumberAccountTypeNode()};
return new Node[]{new CreditCardNumberAccountTypeNode()}; } else {
default: return new Node[]{new DefaultAccountTypeNode(key)};
return new Node[]{new DefaultAccountTypeNode(key)};
} }
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {
LOGGER.log(Level.WARNING, "Unknown account type: {0}", key); LOGGER.log(Level.WARNING, "Unknown account type: {0}", key);
//Flesh out what happens with other account types here. //Flesh out what happens with other account types here.
@ -547,7 +548,7 @@ final public class Accounts implements AutopsyVisitableItem {
+ " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS + " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS
+ " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS
+ " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.name() + "'" //NON-NLS + " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
+ getRejectedArtifactFilterClause() + getRejectedArtifactFilterClause()
+ " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS + " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS
@ -607,7 +608,7 @@ final public class Accounts implements AutopsyVisitableItem {
+ " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS + " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS
+ " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS
+ " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.name() + "'" //NON-NLS + " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
+ getRejectedArtifactFilterClause() + getRejectedArtifactFilterClause()
+ " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo"; + " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo";
@ -1427,7 +1428,7 @@ final public class Accounts implements AutopsyVisitableItem {
final Collection<? extends BlackboardArtifact> artifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); final Collection<? extends BlackboardArtifact> artifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
artifacts.forEach(artifact -> { artifacts.forEach(artifact -> {
try { try {
skCase.setReviewStatus(artifact, newStatus); skCase.setReviewStatus(artifact, newStatus);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error changing artifact review status.", ex); //NON-NLS LOGGER.log(Level.SEVERE, "Error changing artifact review status.", ex); //NON-NLS
} }

View File

@ -990,7 +990,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
return; return;
} }
if (accountType.equals(Account.Type.CREDIT_CARD.name())) { if (accountType.equals(Account.Type.CREDIT_CARD.getTypeName())) {
Node accountNode = accountRootChilds.findChild(Account.Type.CREDIT_CARD.getDisplayName()); Node accountNode = accountRootChilds.findChild(Account.Type.CREDIT_CARD.getDisplayName());
if (accountNode == null) { if (accountNode == null) {
return; return;

View File

@ -170,21 +170,27 @@ class TableReportGenerator {
return "unknown"; return "unknown";
} }
}); });
for (String accountType : groupedArtifacts.keySet()) { for (String accountTypeStr : groupedArtifacts.keySet()) {
/* If the report is a ReportHTML, the data type name /* If the report is a ReportHTML, the data type name
* eventualy makes it to useDataTypeIcon which expects but * eventualy makes it to useDataTypeIcon which expects but
* does not require a artifact name, so we make a synthetic * does not require a artifact name, so we make a synthetic
* compund name by appending a ":" and the account type. * compund name by appending a ":" and the account type.
*/ */
String accountDisplayname = accountType; String accountDisplayname = accountTypeStr;
for (Account.Type acct : Account.Type.values()) { if (accountTypeStr != null) {
if (acct.equals(Account.Type.valueOf(accountType))) { try {
accountDisplayname = acct.getDisplayName(); Account.Type acctType = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().getAccountType(accountTypeStr);
break; if (acctType != null) {
accountDisplayname = acctType.getDisplayName();
}
}
catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Unable to get display name for account type " + accountTypeStr, ex);
} }
} }
final String compundDataTypeName = BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + accountDisplayname; final String compundDataTypeName = BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + accountDisplayname;
writeTableForDataType(new ArrayList<>(groupedArtifacts.get(accountType)), type, compundDataTypeName, comment); writeTableForDataType(new ArrayList<>(groupedArtifacts.get(accountTypeStr)), type, compundDataTypeName, comment);
} }
} else { } else {
//all other artifact types are sent to writeTableForDataType directly //all other artifact types are sent to writeTableForDataType directly

View File

@ -14,6 +14,7 @@
<!-- for file search --> <!-- for file search -->
<dependency conf="autopsy_core->*" org="org.jbundle.thin.base.screen" name="jcalendarbutton" rev="1.4.6"/> <dependency conf="autopsy_core->*" org="org.jbundle.thin.base.screen" name="jcalendarbutton" rev="1.4.6"/>
<dependency conf="autopsy_core->*" org="com.github.lgooddatepicker" name="LGoodDatePicker" rev="10.3.1"/>
<!-- commmon --> <!-- commmon -->
<dependency org="com.google.guava" name="guava" rev="19.0"/> <dependency org="com.google.guava" name="guava" rev="19.0"/>

View File

@ -53,6 +53,7 @@ file.reference.joda-time-2.4-javadoc.jar=release/modules/ext/joda-time-2.4-javad
file.reference.joda-time-2.4-sources.jar=release/modules/ext/joda-time-2.4-sources.jar file.reference.joda-time-2.4-sources.jar=release/modules/ext/joda-time-2.4-sources.jar
file.reference.joda-time-2.4.jar=release/modules/ext/joda-time-2.4.jar file.reference.joda-time-2.4.jar=release/modules/ext/joda-time-2.4.jar
file.reference.jsr305-1.3.9.jar=release/modules/ext/jsr305-1.3.9.jar file.reference.jsr305-1.3.9.jar=release/modules/ext/jsr305-1.3.9.jar
file.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1.jar
file.reference.log4j-1.2.17.jar=release/modules/ext/log4j-1.2.17.jar file.reference.log4j-1.2.17.jar=release/modules/ext/log4j-1.2.17.jar
file.reference.logkit-1.0.1.jar=release/modules/ext/logkit-1.0.1.jar file.reference.logkit-1.0.1.jar=release/modules/ext/logkit-1.0.1.jar
file.reference.mail-1.4.3.jar=release/modules/ext/mail-1.4.3.jar file.reference.mail-1.4.3.jar=release/modules/ext/mail-1.4.3.jar
@ -82,6 +83,7 @@ javadoc.reference.guava-19.0.jar=release/modules/ext/guava-19.0-javadoc.jar
javadoc.reference.jfxtras-common-8.0-r4.jar=release/modules/ext/jfxtras-common-8.0-r4-javadoc.jar javadoc.reference.jfxtras-common-8.0-r4.jar=release/modules/ext/jfxtras-common-8.0-r4-javadoc.jar
javadoc.reference.jfxtras-controls-8.0-r4.jar=release/modules/ext/jfxtras-controls-8.0-r4-javadoc.jar javadoc.reference.jfxtras-controls-8.0-r4.jar=release/modules/ext/jfxtras-controls-8.0-r4-javadoc.jar
javadoc.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4-javadoc.jar javadoc.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4-javadoc.jar
javadoc.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1-javadoc.jar
nbm.needs.restart=true nbm.needs.restart=true
source.reference.commons-csv-1.4.jar=release/modules/ext/commons-csv-1.4-sources.jar source.reference.commons-csv-1.4.jar=release/modules/ext/commons-csv-1.4-sources.jar
source.reference.commons-io-2.5.jar=release/modules/ext/commons-io-2.5-sources.jar source.reference.commons-io-2.5.jar=release/modules/ext/commons-io-2.5-sources.jar
@ -91,3 +93,4 @@ source.reference.guava-19.0.jar=release/modules/ext/guava-19.0-sources.jar
source.reference.jfxtras-common-8.0-r4.jar=release/modules/ext/jfxtras-common-8.0-r4-sources.jar source.reference.jfxtras-common-8.0-r4.jar=release/modules/ext/jfxtras-common-8.0-r4-sources.jar
source.reference.jfxtras-controls-8.0-r4.jar=release/modules/ext/jfxtras-controls-8.0-r4-sources.jar source.reference.jfxtras-controls-8.0-r4.jar=release/modules/ext/jfxtras-controls-8.0-r4-sources.jar
source.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4-sources.jar source.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4-sources.jar
source.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1-sources.jar

View File

@ -37,6 +37,9 @@
<package>com.apple.eawt</package> <package>com.apple.eawt</package>
<package>com.apple.eawt.event</package> <package>com.apple.eawt.event</package>
<package>com.apple.eio</package> <package>com.apple.eio</package>
<package>com.github.lgooddatepicker.components</package>
<package>com.github.lgooddatepicker.optionalusertools</package>
<package>com.github.lgooddatepicker.zinternaltools</package>
<package>com.github.mustachejava</package> <package>com.github.mustachejava</package>
<package>com.github.mustachejava.codes</package> <package>com.github.mustachejava.codes</package>
<package>com.github.mustachejava.functions</package> <package>com.github.mustachejava.functions</package>
@ -679,6 +682,10 @@
<runtime-relative-path>ext/compiler-0.9.1.jar</runtime-relative-path> <runtime-relative-path>ext/compiler-0.9.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/compiler-0.9.1.jar</binary-origin> <binary-origin>release/modules/ext/compiler-0.9.1.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/LGoodDatePicker-10.3.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/LGoodDatePicker-10.3.1.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/imageio-iff-3.2.jar</runtime-relative-path> <runtime-relative-path>ext/imageio-iff-3.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/imageio-iff-3.2.jar</binary-origin> <binary-origin>release/modules/ext/imageio-iff-3.2.jar</binary-origin>

View File

@ -1,7 +1,7 @@
""" """
Autopsy Forensic Browser Autopsy Forensic Browser
Copyright 2016 Basis Technology Corp. Copyright 2016-17 Basis Technology Corp.
Contact: carrier <at> sleuthkit <dot> org Contact: carrier <at> sleuthkit <dot> org
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
@ -44,10 +44,14 @@ from org.sleuthkit.datamodel import BlackboardAttribute
from org.sleuthkit.datamodel.BlackboardAttribute import ATTRIBUTE_TYPE from org.sleuthkit.datamodel.BlackboardAttribute import ATTRIBUTE_TYPE
from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import Content
from org.sleuthkit.datamodel import TskCoreException from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel import Account
from org.sleuthkit.datamodel import Relationship
import traceback import traceback
import general import general
deviceAccountInstance = None
""" """
Locates a variety of different call log databases, parses them, and populates the blackboard. Locates a variety of different call log databases, parses them, and populates the blackboard.
""" """
@ -82,6 +86,15 @@ class CallLogAnalyzer(general.AndroidComponentAnalyzer):
def analyze(self, dataSource, fileManager, context): def analyze(self, dataSource, fileManager, context):
try: try:
# Create a 'Device' account using the data source device id
datasourceObjId = dataSource.getDataSource().getId()
ds = Case.getCurrentCase().getSleuthkitCase().getDataSource(datasourceObjId)
deviceID = ds.getDeviceId()
global deviceAccountInstance
deviceAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.DEVICE, deviceID, general.MODULE_NAME, dataSource)
absFiles = fileManager.findFiles(dataSource, "logs.db") absFiles = fileManager.findFiles(dataSource, "logs.db")
absFiles.addAll(fileManager.findFiles(dataSource, "contacts.db")) absFiles.addAll(fileManager.findFiles(dataSource, "contacts.db"))
absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db")) absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db"))
@ -133,6 +146,13 @@ class CallLogAnalyzer(general.AndroidComponentAnalyzer):
attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name)) attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))
artifact.addAttributes(attributes) artifact.addAttributes(attributes)
# Create an account
calllogAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.PHONE, number, general.MODULE_NAME, abstractFile);
# create relationship between accounts
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(deviceAccountInstance, [calllogAccountInstance], artifact, Relationship.Type.CALL_LOG, date);
bbartifacts.append(artifact) bbartifacts.append(artifact)
try: try:

View File

@ -1,7 +1,7 @@
""" """
Autopsy Forensic Browser Autopsy Forensic Browser
Copyright 2016 Basis Technology Corp. Copyright 2016-17 Basis Technology Corp.
Contact: carrier <at> sleuthkit <dot> org Contact: carrier <at> sleuthkit <dot> org
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
@ -42,10 +42,14 @@ from org.sleuthkit.datamodel import BlackboardArtifact
from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import BlackboardAttribute
from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import Content
from org.sleuthkit.datamodel import TskCoreException from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel import Account
from org.sleuthkit.datamodel import Relationship
import traceback import traceback
import general import general
deviceAccountInstance = None
""" """
Locates a variety of different contacts databases, parses them, and populates the blackboard. Locates a variety of different contacts databases, parses them, and populates the blackboard.
""" """
@ -56,6 +60,15 @@ class ContactAnalyzer(general.AndroidComponentAnalyzer):
def analyze(self, dataSource, fileManager, context): def analyze(self, dataSource, fileManager, context):
try: try:
# Create a 'Device' account using the data source device id
datasourceObjId = dataSource.getDataSource().getId()
ds = Case.getCurrentCase().getSleuthkitCase().getDataSource(datasourceObjId)
deviceID = ds.getDeviceId()
global deviceAccountInstance
deviceAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance (Account.Type.DEVICE, deviceID, general.MODULE_NAME, dataSource)
absFiles = fileManager.findFiles(dataSource, "contacts.db") absFiles = fileManager.findFiles(dataSource, "contacts.db")
absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db")) absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db"))
if absFiles.isEmpty(): if absFiles.isEmpty():
@ -131,12 +144,21 @@ class ContactAnalyzer(general.AndroidComponentAnalyzer):
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name)) attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))
if mimetype == "vnd.android.cursor.item/phone_v2": if mimetype == "vnd.android.cursor.item/phone_v2":
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, general.MODULE_NAME, data1)) attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, general.MODULE_NAME, data1))
acctType = Account.Type.PHONE
else: else:
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, general.MODULE_NAME, data1)) attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, general.MODULE_NAME, data1))
acctType = Account.Type.EMAIL
artifact.addAttributes(attributes)
# Create an account instance
contactAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance (acctType, data1, general.MODULE_NAME, abstractFile);
# create relationship between accounts
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(deviceAccountInstance, [contactAccountInstance], artifact,Relationship.Type.CONTACT, 0);
oldName = name oldName = name
artifact.addAttributes(attributes)
bbartifacts.append(artifact) bbartifacts.append(artifact)
try: try:

View File

@ -42,10 +42,13 @@ from org.sleuthkit.datamodel import BlackboardArtifact
from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import BlackboardAttribute
from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import Content
from org.sleuthkit.datamodel import TskCoreException from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel import Account
import traceback import traceback
import general import general
deviceAccountInstance = None
""" """
Locates database for the Tango app and adds info to blackboard. Locates database for the Tango app and adds info to blackboard.
""" """
@ -56,6 +59,14 @@ class TangoMessageAnalyzer(general.AndroidComponentAnalyzer):
def analyze(self, dataSource, fileManager, context): def analyze(self, dataSource, fileManager, context):
try: try:
# Create a 'Device' account using the data source device id
datasourceObjId = dataSource.getDataSource().getId()
ds = Case.getCurrentCase().getSleuthkitCase().getDataSource(datasourceObjId)
deviceID = ds.getDeviceId()
global deviceAccountInstance
deviceAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.DEVICE, deviceID, general.MODULE_NAME, dataSource)
absFiles = fileManager.findFiles(dataSource, "tc.db") absFiles = fileManager.findFiles(dataSource, "tc.db")
for abstractFile in absFiles: for abstractFile in absFiles:
try: try:

View File

@ -1,7 +1,7 @@
""" """
Autopsy Forensic Browser Autopsy Forensic Browser
Copyright 2016 Basis Technology Corp. Copyright 2016-17 Basis Technology Corp.
Contact: carrier <at> sleuthkit <dot> org Contact: carrier <at> sleuthkit <dot> org
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
@ -43,10 +43,14 @@ from org.sleuthkit.datamodel import BlackboardArtifact
from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import BlackboardAttribute
from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import Content
from org.sleuthkit.datamodel import TskCoreException from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel import Account
from org.sleuthkit.datamodel import Relationship
import traceback import traceback
import general import general
deviceAccountInstance = None
""" """
Finds database with SMS/MMS messages and adds them to blackboard. Finds database with SMS/MMS messages and adds them to blackboard.
""" """
@ -57,6 +61,15 @@ class TextMessageAnalyzer(general.AndroidComponentAnalyzer):
def analyze(self, dataSource, fileManager, context): def analyze(self, dataSource, fileManager, context):
try: try:
# Create a 'Device' account using the data source device id
datasourceObjId = dataSource.getDataSource().getId()
ds = Case.getCurrentCase().getSleuthkitCase().getDataSource(datasourceObjId)
deviceID = ds.getDeviceId()
global deviceAccountInstance
deviceAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.DEVICE, deviceID, general.MODULE_NAME, dataSource)
absFiles = fileManager.findFiles(dataSource, "mmssms.db") absFiles = fileManager.findFiles(dataSource, "mmssms.db")
for abstractFile in absFiles: for abstractFile in absFiles:
try: try:
@ -108,6 +121,13 @@ class TextMessageAnalyzer(general.AndroidComponentAnalyzer):
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "SMS Message")) attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "SMS Message"))
artifact.addAttributes(attributes) artifact.addAttributes(attributes)
# Create an account
msgAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.PHONE, address, general.MODULE_NAME, abstractFile);
# create relationship between accounts
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(deviceAccountInstance, [msgAccountInstance], artifact,Relationship.Type.MESSAGE, date);
bbartifacts.append(artifact) bbartifacts.append(artifact)
try: try:
# index the artifact for keyword search # index the artifact for keyword search

View File

@ -1,7 +1,7 @@
""" """
Autopsy Forensic Browser Autopsy Forensic Browser
Copyright 2016 Basis Technology Corp. Copyright 2016-17 Basis Technology Corp.
Contact: carrier <at> sleuthkit <dot> org Contact: carrier <at> sleuthkit <dot> org
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
@ -39,10 +39,15 @@ from org.sleuthkit.datamodel import BlackboardArtifact
from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import BlackboardAttribute
from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import Content
from org.sleuthkit.datamodel import TskCoreException from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel import Account
from org.sleuthkit.datamodel import Relationship
import traceback import traceback
import general import general
wwfAccountType = None
deviceAccountInstance = None
""" """
Analyzes messages from Words With Friends Analyzes messages from Words With Friends
""" """
@ -53,6 +58,18 @@ class WWFMessageAnalyzer(general.AndroidComponentAnalyzer):
def analyze(self, dataSource, fileManager, context): def analyze(self, dataSource, fileManager, context):
try: try:
global wwfAccountType
wwfAccountType = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addAccountType("WWF", "Words with Friends")
# Create a 'Device' account using the data source device id
datasourceObjId = dataSource.getDataSource().getId()
ds = Case.getCurrentCase().getSleuthkitCase().getDataSource(datasourceObjId)
deviceID = ds.getDeviceId()
global deviceAccountInstance
deviceAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.DEVICE, deviceID, general.MODULE_NAME, dataSource)
absFiles = fileManager.findFiles(dataSource, "WordsFramework") absFiles = fileManager.findFiles(dataSource, "WordsFramework")
for abstractFile in absFiles: for abstractFile in absFiles:
try: try:
@ -98,6 +115,13 @@ class WWFMessageAnalyzer(general.AndroidComponentAnalyzer):
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Words With Friends Message")) attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Words With Friends Message"))
artifact.addAttributes(attributes) artifact.addAttributes(attributes)
# Create an account
wwfAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(wwfAccountType, user_id, general.MODULE_NAME, abstractFile);
# create relationship between accounts
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(deviceAccountInstance, [wwfAccountInstance], artifact,Relationship.Type.MESSAGE, created_at);
try: try:
# index the artifact for keyword search # index the artifact for keyword search
blackboard = Case.getCurrentCase().getServices().getBlackboard() blackboard = Case.getCurrentCase().getServices().getBlackboard()

View File

@ -173,7 +173,14 @@ public class ExtractedContentViewer implements DataContentViewer {
} }
} }
panel.updateControls(currentSource); panel.updateControls(currentSource);
setPanel(content.getName(), sources);
String contentName = "";
if (content != null) {
contentName = content.getName();
}
setPanel(contentName, sources);
} }
static private IndexedText getRawArtifactText(Lookup nodeLookup) throws TskCoreException { static private IndexedText getRawArtifactText(Lookup nodeLookup) throws TskCoreException {

View File

@ -222,9 +222,6 @@ class QueryResults {
* Post an artifact for the hit to the blackboard. * Post an artifact for the hit to the blackboard.
*/ */
BlackboardArtifact artifact = query.postKeywordHitToBlackboard(content, keyword, hit, snippet, query.getKeywordList().getName()); BlackboardArtifact artifact = query.postKeywordHitToBlackboard(content, keyword, hit, snippet, query.getKeywordList().getName());
if (null == artifact) {
logger.log(Level.SEVERE, "Error posting keyword hit artifact for keyword {0} in {1} to the blackboard", new Object[]{keyword.toString(), content}); //NON-NLS
}
/* /*
* Send an ingest inbox message for the hit. * Send an ingest inbox message for the hit.

View File

@ -36,7 +36,9 @@ import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList; import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.params.CursorMarkParams; import org.apache.solr.common.params.CursorMarkParams;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.autopsy.datamodel.CreditCards;
@ -46,6 +48,7 @@ import static org.sleuthkit.autopsy.keywordsearch.TermsComponentQuery.CREDIT_CAR
import static org.sleuthkit.autopsy.keywordsearch.TermsComponentQuery.KEYWORD_SEARCH_DOCUMENT_ID; import static org.sleuthkit.autopsy.keywordsearch.TermsComponentQuery.KEYWORD_SEARCH_DOCUMENT_ID;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.AccountFileInstance;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
@ -444,97 +447,30 @@ final class RegexQuery implements KeywordSearchQuery {
} }
/* /*
* Create either a "plain vanilla" keyword hit artifact with keyword and * Credit Card number hits are handled differently
* regex attributes, or a credit card account artifact with attributes */
* parsed from from the snippet for the hit and looked up based on the if (originalKeyword.getArtifactAttributeType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
* parsed bank identifcation number. createCCNAccount(content, foundKeyword, hit, snippet, listName);
return null;
}
/*
* Create a "plain vanilla" keyword hit artifact with keyword and
* regex attributes
*/ */
BlackboardArtifact newArtifact; BlackboardArtifact newArtifact;
Collection<BlackboardAttribute> attributes = new ArrayList<>(); Collection<BlackboardAttribute> attributes = new ArrayList<>();
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm())); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm()));
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, getQueryString())); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, getQueryString()));
try {
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT); try {
} catch (TskCoreException ex) { newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS } catch (TskCoreException ex) {
return null; LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
} return null;
} else {
/*
* Parse the credit card account attributes from the snippet for the
* hit.
*/
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE, MODULE_NAME, Account.Type.CREDIT_CARD.name()));
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
Matcher matcher = TermsComponentQuery.CREDIT_CARD_TRACK1_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack1Data(parsedTrackAttributeMap, matcher);
}
matcher = CREDIT_CARD_TRACK2_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack2Data(parsedTrackAttributeMap, matcher);
}
final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) {
if (hit.isArtifactHit()) {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS
} else {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getSolrObjectId())); //NON-NLS
}
return null;
}
attributes.addAll(parsedTrackAttributeMap.values());
/*
* Look up the bank name, scheme, etc. attributes for the bank
* indentification number (BIN).
*/
final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8));
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
if (binInfo != null) {
binInfo.getScheme().ifPresent(scheme
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme)));
binInfo.getCardType().ifPresent(cardType
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType)));
binInfo.getBrand().ifPresent(brand
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand)));
binInfo.getBankName().ifPresent(bankName
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName)));
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber)));
binInfo.getBankURL().ifPresent(url
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url)));
binInfo.getCountry().ifPresent(country
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country)));
binInfo.getBankCity().ifPresent(city
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city)));
}
/*
* If the hit is from unused or unallocated space, record the Solr
* document id to support showing just the chunk that contained the
* hit.
*/
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile) content;
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
}
}
/*
* Create an account artifact.
*/
try {
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT);
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error adding artifact for account to blackboard", ex); //NON-NLS
return null;
}
} }
if (StringUtils.isNotBlank(listName)) { if (StringUtils.isNotBlank(listName)) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName)); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
} }
@ -557,6 +493,113 @@ final class RegexQuery implements KeywordSearchQuery {
} }
} }
private void createCCNAccount(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName();
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
LOGGER.log(Level.SEVERE, "Keyword hit is not a credit card number"); //NON-NLS
return;
}
/*
* Create a credit card account with attributes
* parsed from the snippet for the hit and looked up based on the
* parsed bank identifcation number.
*/
Collection<BlackboardAttribute> attributes = new ArrayList<>();
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
Matcher matcher = TermsComponentQuery.CREDIT_CARD_TRACK1_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack1Data(parsedTrackAttributeMap, matcher);
}
matcher = CREDIT_CARD_TRACK2_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack2Data(parsedTrackAttributeMap, matcher);
}
final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) {
if (hit.isArtifactHit()) {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS
} else {
try {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getContentID())); //NON-NLS
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s' ", foundKeyword.getSearchTerm(), hit.getSnippet())); //NON-NLS
LOGGER.log(Level.SEVERE, "There was a error getting contentID for keyword hit.", ex); //NON-NLS
}
}
return;
}
attributes.addAll(parsedTrackAttributeMap.values());
/*
* Look up the bank name, scheme, etc. attributes for the bank
* indentification number (BIN).
*/
final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8));
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
if (binInfo != null) {
binInfo.getScheme().ifPresent(scheme
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme)));
binInfo.getCardType().ifPresent(cardType
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType)));
binInfo.getBrand().ifPresent(brand
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand)));
binInfo.getBankName().ifPresent(bankName
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName)));
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber)));
binInfo.getBankURL().ifPresent(url
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url)));
binInfo.getCountry().ifPresent(country
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country)));
binInfo.getBankCity().ifPresent(city
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city)));
}
/*
* If the hit is from unused or unallocated space, record the Solr
* document id to support showing just the chunk that contained the
* hit.
*/
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile) content;
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
}
}
if (StringUtils.isNotBlank(listName)) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
}
if (snippet != null) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW, MODULE_NAME, snippet));
}
hit.getArtifactID().ifPresent(artifactID
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactID))
);
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.REGEX.ordinal()));
/*
* Create an account instance.
*/
try {
AccountFileInstance ccAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.CREDIT_CARD, ccnAttribute.getValueString() , MODULE_NAME, content);
ccAccountInstance.addAttributes(attributes);
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error creating CCN account instance", ex); //NON-NLS
}
}
/** /**
* Parses the track 2 data from the snippet for a credit card account number * Parses the track 2 data from the snippet for a credit card account number
* hit and turns them into artifact attributes. * hit and turns them into artifact attributes.

View File

@ -32,11 +32,14 @@ import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.response.TermsResponse.Term; import org.apache.solr.client.solrj.response.TermsResponse.Term;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.autopsy.datamodel.CreditCards;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.AccountFileInstance;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
@ -342,98 +345,31 @@ final class TermsComponentQuery implements KeywordSearchQuery {
*/ */
@Override @Override
public BlackboardArtifact postKeywordHitToBlackboard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) { public BlackboardArtifact postKeywordHitToBlackboard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
/* /*
* Create either a "plain vanilla" keyword hit artifact with keyword and * CCN hits are handled specially
* regex attributes, or a credit card account artifact with attributes */
* parsed from from the snippet for the hit and looked up based on the if (originalKeyword.getArtifactAttributeType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
* parsed bank identifcation number. createCCNAccount(content, hit, snippet, listName);
return null;
}
/*
* Create a "plain vanilla" keyword hit artifact with keyword and regex
* attributes,
*/ */
BlackboardArtifact newArtifact; BlackboardArtifact newArtifact;
Collection<BlackboardAttribute> attributes = new ArrayList<>(); Collection<BlackboardAttribute> attributes = new ArrayList<>();
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm()));
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, originalKeyword.getSearchTerm()));
try { attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm()));
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, originalKeyword.getSearchTerm()));
} catch (TskCoreException ex) { try {
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
return null;
}
} else {
/*
* Parse the credit card account attributes from the snippet for the
* hit.
*/
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE, MODULE_NAME, Account.Type.CREDIT_CARD.name()));
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
Matcher matcher = CREDIT_CARD_TRACK1_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack1Data(parsedTrackAttributeMap, matcher);
}
matcher = CREDIT_CARD_TRACK2_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack2Data(parsedTrackAttributeMap, matcher);
}
final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) {
if (hit.isArtifactHit()) {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", searchTerm, hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS
} else {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", searchTerm, hit.getSnippet(), hit.getSolrObjectId())); //NON-NLS
}
return null;
}
attributes.addAll(parsedTrackAttributeMap.values());
/* } catch (TskCoreException ex) {
* Look up the bank name, scheme, etc. attributes for the bank LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
* indentification number (BIN). return null;
*/
final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8));
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
if (binInfo != null) {
binInfo.getScheme().ifPresent(scheme
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme)));
binInfo.getCardType().ifPresent(cardType
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType)));
binInfo.getBrand().ifPresent(brand
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand)));
binInfo.getBankName().ifPresent(bankName
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName)));
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber)));
binInfo.getBankURL().ifPresent(url
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url)));
binInfo.getCountry().ifPresent(country
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country)));
binInfo.getBankCity().ifPresent(city
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city)));
}
/*
* If the hit is from unused or unallocated space, record the Solr
* document id to support showing just the chunk that contained the
* hit.
*/
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile) content;
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
}
}
/*
* Create an account artifact.
*/
try {
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT);
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error adding artifact for account to blackboard", ex); //NON-NLS
return null;
}
} }
if (StringUtils.isNotBlank(listName)) { if (StringUtils.isNotBlank(listName)) {
@ -459,6 +395,114 @@ final class TermsComponentQuery implements KeywordSearchQuery {
} }
} }
private void createCCNAccount(Content content, KeywordHit hit, String snippet, String listName) {
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
LOGGER.log(Level.SEVERE, "Keyword hit is not a credit card number"); //NON-NLS
return;
}
/*
* Create a credit card account with attributes parsed from from the
* snippet for the hit and looked up based on the parsed bank
* identifcation number.
*/
Collection<BlackboardAttribute> attributes = new ArrayList<>();
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
Matcher matcher = CREDIT_CARD_TRACK1_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack1Data(parsedTrackAttributeMap, matcher);
}
matcher = CREDIT_CARD_TRACK2_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack2Data(parsedTrackAttributeMap, matcher);
}
final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) {
if (hit.isArtifactHit()) {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", searchTerm, hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS
} else {
long contentId = 0;
try {
contentId = hit.getContentID();
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, String.format("Failed to content id from keyword hit: term = %s, snippet = '%s'", searchTerm, hit.getSnippet()), ex); //NON-NLS
}
if (contentId > 0) {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", searchTerm, hit.getSnippet(), contentId)); //NON-NLS
} else {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s'", searchTerm, hit.getSnippet())); //NON-NLS
}
}
return;
}
attributes.addAll(parsedTrackAttributeMap.values());
/*
* Look up the bank name, scheme, etc. attributes for the bank
* indentification number (BIN).
*/
final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8));
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
if (binInfo != null) {
binInfo.getScheme().ifPresent(scheme
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme)));
binInfo.getCardType().ifPresent(cardType
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType)));
binInfo.getBrand().ifPresent(brand
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand)));
binInfo.getBankName().ifPresent(bankName
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName)));
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber)));
binInfo.getBankURL().ifPresent(url
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url)));
binInfo.getCountry().ifPresent(country
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country)));
binInfo.getBankCity().ifPresent(city
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city)));
}
/*
* If the hit is from unused or unallocated space, record the Solr
* document id to support showing just the chunk that contained the hit.
*/
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile) content;
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
}
}
if (StringUtils.isNotBlank(listName)) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
}
if (snippet != null) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW, MODULE_NAME, snippet));
}
hit.getArtifactID().ifPresent(
artifactID -> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactID))
);
// TermsComponentQuery is now being used exclusively for substring searches.
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.SUBSTRING.ordinal()));
/*
* Create an account.
*/
try {
AccountFileInstance ccAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.CREDIT_CARD, ccnAttribute.getValueString(), MODULE_NAME, content);
ccAccountInstance.addAttributes(attributes);
//newArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(ccAccountInstance.getArtifactId());
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error creating CCN account instance", ex); //NON-NLS
}
}
/** /**
* Parses the track 2 data from the snippet for a credit card account number * Parses the track 2 data from the snippet for a credit card account number
* hit and turns them into artifact attributes. * hit and turns them into artifact attributes.

View File

@ -1,5 +1,5 @@
#Updated by build script #Updated by build script
#Wed, 08 Nov 2017 17:45:11 -0500 #Wed, 06 Dec 2017 09:53:33 -0500
LBL_splash_window_title=Starting Autopsy LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=314 SPLASH_HEIGHT=314
SPLASH_WIDTH=538 SPLASH_WIDTH=538

View File

@ -1,4 +1,4 @@
#Updated by build script #Updated by build script
#Wed, 08 Nov 2017 17:45:11 -0500 #Wed, 06 Dec 2017 09:53:33 -0500
CTL_MainWindow_Title=Autopsy 4.5.0 CTL_MainWindow_Title=Autopsy 4.5.0
CTL_MainWindow_Title_No_Project=Autopsy 4.5.0 CTL_MainWindow_Title_No_Project=Autopsy 4.5.0

View File

@ -21,8 +21,13 @@ package org.sleuthkit.autopsy.thunderbirdparser;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
@ -40,12 +45,16 @@ import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.AccountFileInstance;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.Relationship;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskDataException;
import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.TskException;
/** /**
@ -354,6 +363,24 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
return files; return files;
} }
/**
* Finds and returns a set of unique email addresses found in the input string
*
* @param input - input string, like the To/CC line from an email header
*
* @param Set<String>: set of email addresses found in the input string
*/
private Set<String> findEmailAddresess(String input) {
Pattern p = Pattern.compile("\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b",
Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(input);
Set<String> emailAddresses = new HashSet<String>();
while (m.find()) {
emailAddresses.add( m.group());
}
return emailAddresses;
}
/** /**
* Add a blackboard artifact for the given email message. * Add a blackboard artifact for the given email message.
* *
@ -377,55 +404,71 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
long id = email.getId(); long id = email.getId();
String localPath = email.getLocalPath(); String localPath = email.getLocalPath();
if (headers.isEmpty() == false) { List<String> senderAddressList = new ArrayList<>();
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HEADERS, EmailParserModuleFactory.getModuleName(), headers)); String senderAddress;
senderAddressList.addAll(findEmailAddresess(from));
AccountFileInstance senderAccountInstance = null;
if (senderAddressList.size() == 1) {
senderAddress = senderAddressList.get(0);
try {
senderAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, senderAddress, EmailParserModuleFactory.getModuleName(), abstractFile);
}
catch(TskCoreException ex) {
logger.log(Level.WARNING, "Failed to create account for email address " + senderAddress, ex); //NON-NLS
}
} }
if (from.isEmpty() == false) { else {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_FROM, EmailParserModuleFactory.getModuleName(), from)); logger.log(Level.WARNING, "Failed to find sender address, from = "+ from); //NON-NLS
}
if (to.isEmpty() == false) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_TO, EmailParserModuleFactory.getModuleName(), to));
}
if (subject.isEmpty() == false) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SUBJECT, EmailParserModuleFactory.getModuleName(), subject));
}
if (dateL > 0) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_RCVD, EmailParserModuleFactory.getModuleName(), dateL));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_SENT, EmailParserModuleFactory.getModuleName(), dateL));
}
if (body.isEmpty() == false) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN, EmailParserModuleFactory.getModuleName(), body));
} }
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_MSG_ID, EmailParserModuleFactory.getModuleName(), ((id < 0L) ? NbBundle List<String> recipientAddresses = new ArrayList<>();
.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(id)))); recipientAddresses.addAll(findEmailAddresess(to));
recipientAddresses.addAll(findEmailAddresess(cc));
recipientAddresses.addAll(findEmailAddresess(bcc));
if (localPath.isEmpty() == false) { List<AccountFileInstance> recipientAccountInstances = new ArrayList<>();
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, EmailParserModuleFactory.getModuleName(), localPath)); recipientAddresses.forEach((addr) -> {
} else { try {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, EmailParserModuleFactory.getModuleName(), "/foo/bar")); //NON-NLS AccountFileInstance recipientAccountInstance =
} Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, addr,
EmailParserModuleFactory.getModuleName(), abstractFile);
recipientAccountInstances.add(recipientAccountInstance);
}
catch(TskCoreException ex) {
logger.log(Level.WARNING, "Failed to create account for email address " + addr, ex); //NON-NLS
}
});
addEmailAttribute(headers, ATTRIBUTE_TYPE.TSK_HEADERS, bbattributes);
addEmailAttribute(from, ATTRIBUTE_TYPE.TSK_EMAIL_FROM, bbattributes);
addEmailAttribute(to, ATTRIBUTE_TYPE.TSK_EMAIL_TO, bbattributes);
addEmailAttribute(subject, ATTRIBUTE_TYPE.TSK_SUBJECT, bbattributes);
if (cc.isEmpty() == false) { addEmailAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_RCVD, bbattributes);
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CC, EmailParserModuleFactory.getModuleName(), cc)); addEmailAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_SENT, bbattributes);
}
if (bcc.isEmpty() == false) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_BCC, EmailParserModuleFactory.getModuleName(), bcc));
}
if (bodyHTML.isEmpty() == false) { addEmailAttribute(body, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN, bbattributes);
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, EmailParserModuleFactory.getModuleName(), bodyHTML));
} addEmailAttribute(((id < 0L) ? NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(id)),
if (rtf.isEmpty() == false) { ATTRIBUTE_TYPE.TSK_MSG_ID, bbattributes);
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, EmailParserModuleFactory.getModuleName(), rtf));
} addEmailAttribute(((localPath.isEmpty() == false) ? localPath : "/foo/bar"),
ATTRIBUTE_TYPE.TSK_PATH, bbattributes);
addEmailAttribute(cc, ATTRIBUTE_TYPE.TSK_EMAIL_CC, bbattributes);
addEmailAttribute(bodyHTML, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, bbattributes);
addEmailAttribute(rtf, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, bbattributes);
try { try {
bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG); bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
bbart.addAttributes(bbattributes); bbart.addAttributes(bbattributes);
// Add account relationships
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance, recipientAccountInstances, bbart,Relationship.Type.MESSAGE, dateL);
try { try {
// index the artifact for keyword search // index the artifact for keyword search
blackboard.indexArtifact(bbart); blackboard.indexArtifact(bbart);
@ -433,13 +476,24 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bbart.getArtifactID(), ex); //NON-NLS logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bbart.getArtifactID(), ex); //NON-NLS
MessageNotifyUtil.Notify.error(Bundle.ThunderbirdMboxFileIngestModule_addArtifact_indexError_message(), bbart.getDisplayName()); MessageNotifyUtil.Notify.error(Bundle.ThunderbirdMboxFileIngestModule_addArtifact_indexError_message(), bbart.getDisplayName());
} }
} catch (TskCoreException ex) { } catch (TskCoreException | TskDataException ex) {
logger.log(Level.WARNING, null, ex); logger.log(Level.WARNING, null, ex);
} }
return bbart; return bbart;
} }
private void addEmailAttribute(String stringVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
if (stringVal.isEmpty() == false) {
bbattributes.add(new BlackboardAttribute(attrType, EmailParserModuleFactory.getModuleName(), stringVal));
}
}
private void addEmailAttribute(long longVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
if (longVal > 0) {
bbattributes.add(new BlackboardAttribute(attrType, EmailParserModuleFactory.getModuleName(), longVal));
}
}
void postErrorMessage(String subj, String details) { void postErrorMessage(String subj, String details) {
IngestMessage ingestMessage = IngestMessage.createErrorMessage(EmailParserModuleFactory.getModuleVersion(), subj, details); IngestMessage ingestMessage = IngestMessage.createErrorMessage(EmailParserModuleFactory.getModuleVersion(), subj, details);
services.postMessage(ingestMessage); services.postMessage(ingestMessage);
@ -451,5 +505,6 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
@Override @Override
public void shutDown() { public void shutDown() {
// nothing to shut down
} }
} }