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-pool2" rev="2.4.2"/>
<dependency conf="core->default" org="org.jsoup" name="jsoup" rev="1.10.3"/>
</dependencies>
</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.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.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.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

View File

@ -320,6 +320,10 @@
<package>org.sleuthkit.autopsy.report</package>
<package>org.sleuthkit.datamodel</package>
</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>
<runtime-relative-path>ext/zookeeper-3.4.6.jar</runtime-relative-path>
<binary-origin>release/modules/ext/zookeeper-3.4.6.jar</binary-origin>
@ -336,6 +340,10 @@
<runtime-relative-path>ext/Tsk_DataModel_PostgreSQL.jar</runtime-relative-path>
<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>
<runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
<binary-origin>release/modules/ext/opencv-248.jar</binary-origin>
@ -344,6 +352,10 @@
<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>
</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>
<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>
@ -356,6 +368,14 @@
<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>
</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>
<runtime-relative-path>ext/sevenzipjbinding.jar</runtime-relative-path>
<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>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/StixLib.jar</runtime-relative-path>
<binary-origin>release/modules/ext/StixLib.jar</binary-origin>
<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/curator-client-2.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/curator-client-2.8.0.jar</binary-origin>
<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>
<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>
<binary-origin>release/modules/ext/activemq-all-5.11.1.jar</binary-origin>
</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>
<runtime-relative-path>ext/Rejistry-1.0-SNAPSHOT.jar</runtime-relative-path>
<binary-origin>release/modules/ext/Rejistry-1.0-SNAPSHOT.jar</binary-origin>
</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>
<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>
@ -420,6 +436,10 @@
<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>
<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>
</configuration>
</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.ReportAddedEvent;
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.CategoryNode;
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException;
@ -1050,6 +1051,7 @@ public class Case {
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true);
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true);
CallableSystemAction.get(OpenTimelineAction.class).setEnabled(true);
CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(true);
CallableSystemAction.get(OpenOutputFolderAction.class).setEnabled(false);
/*
@ -1092,24 +1094,13 @@ public class Case {
/*
* Disable the case-specific menu items.
*/
CallableSystemAction
.get(AddImageAction.class
).setEnabled(false);
CallableSystemAction
.get(CaseCloseAction.class
).setEnabled(false);
CallableSystemAction
.get(CasePropertiesAction.class
).setEnabled(false);
CallableSystemAction
.get(CaseDeleteAction.class
).setEnabled(false);
CallableSystemAction
.get(OpenTimelineAction.class
).setEnabled(false);
CallableSystemAction
.get(OpenOutputFolderAction.class
).setEnabled(false);
CallableSystemAction.get(AddImageAction.class).setEnabled(false);
CallableSystemAction.get(CaseCloseAction.class).setEnabled(false);
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(false);
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(false);
CallableSystemAction.get(OpenTimelineAction.class).setEnabled(false);
CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(false);
CallableSystemAction.get(OpenOutputFolderAction.class).setEnabled(false);
/*
* 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.text=From The Sleuth Kit istat Tool\:
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.text.html.HTMLEditorKit;
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("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"/>
<file name="floatingLeftBottom.wsmode" url="floatingLeftBottomWsmode.xml"/>
<file name="timeline.wsmode" url="timelineWsmode.xml"/>
<file name="cvt.wsmode" url="cvtWsmode.xml"/>
</folder>
</folder>

View File

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

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2011-17 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* 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
* 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
* this viewer
*
* @deprecated All implementations of this in the standard DataResultViewers are now no-ops.
*/
@Deprecated
public void setContentViewer(DataContent contentViewer);
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2011-17 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* 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.Provider;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
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());
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
@ -53,10 +47,11 @@ abstract class AbstractDataResultViewer extends JPanel implements DataResultView
* TopComponent has focus. The ExplorerManager must be present when the
* object is constructed so that its child components can discover it using
* the ExplorerManager.find() method.
*
* @param explorerManager
*/
public AbstractDataResultViewer(ExplorerManager explorerManager) {
AbstractDataResultViewer(ExplorerManager explorerManager) {
this.em = explorerManager;
initialize();
}
/**
@ -65,14 +60,7 @@ abstract class AbstractDataResultViewer extends JPanel implements DataResultView
* context lookup.
*/
public AbstractDataResultViewer() {
em = 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);
this(new ExplorerManager());
}
@Override
@ -115,8 +103,8 @@ abstract class AbstractDataResultViewer extends JPanel implements DataResultView
}
}
@Deprecated
@Override
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.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JTabbedPane;
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
* 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 int NO_TAB_SELECTED = -1;
@ -79,8 +80,8 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
private DataContent contentView;
/**
* Constructs and opens a Swing JPanel with a JTabbedPane child component.
* The tabbed pane contains result viewers.
* Constructs and opens a DataResultPanel with the given initial data, and
* the default DataContent.
*
* @param title The title for the panel.
* @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.
* The tabbed pane contains result viewers.
* Constructs and opens a DataResultPanel with the given initial data, and a
* custom DataContent.
*
* @param title The title for the panel.
* @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
* pane contains result viewers. The panel is NOT opened; the client of this
* method must call open on the panel that is returned.
* Constructs a DataResultPanel with the given initial data, and a custom
* DataContent. The panel is NOT opened; the client of this method must call
* open on the panel that is returned.
*
* @param title The title for the panel.
* @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
* 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).
* Constructs a DataResultPanel with the default DataContent
*
* @param title The title for the panel.
* @param isMain True if the DataResultPanel being constructed is the "main"
* DataResultPanel.
*/
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.contentView = Lookup.getDefault().lookup(DataContent.class);
this.contentView = contentView;
initComponents();
}
/**
* Constructs a Swing JPanel with a JTabbedPane child component that
* contains result viewers (implementations of the DataResultViewer
* interface).
* Constructs a DataResultPanel with the a custom DataContent.
*
* @param title The title for the panel.
* @param customContentView A content view to use in place of the default
* content view.
*/
DataResultPanel(String title, DataContent customContentView) {
this(title, false);
this.contentView = customContentView;
this(false, customContentView);
}
/**
@ -245,10 +236,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
*
* @param resultViewer The result viewer.
*/
private void addResultViewer(DataResultViewer resultViewer) {
if (null != contentView) {
resultViewer.setContentViewer(contentView);
}
public void addResultViewer(DataResultViewer resultViewer) {
resultViewers.add(resultViewer);
dataResultTabbedPanel.addTab(resultViewer.getTitle(), resultViewer.getComponent());
}
@ -260,11 +248,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
*/
@Override
public List<DataResultViewer> getViewers() {
List<DataResultViewer> viewers = new ArrayList<>();
resultViewers.forEach((viewer) -> {
viewers.add(viewer);
});
return viewers;
return Collections.unmodifiableList(resultViewers);
}
/**
@ -397,9 +381,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
* @param selectedNodes The nodes to be selected.
*/
public void setSelectedNodes(Node[] selectedNodes) {
this.resultViewers.forEach((viewer) -> {
viewer.setSelectedNodes(selectedNodes);
});
this.resultViewers.forEach((viewer) -> viewer.setSelectedNodes(selectedNodes));
}
/**
@ -517,14 +499,10 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
explorerManager = null;
}
this.resultViewers.forEach((viewer) -> {
viewer.setNode(null);
});
this.resultViewers.forEach((viewer) -> viewer.setNode(null));
if (!this.isMain) {
this.resultViewers.forEach((viewer) -> {
viewer.clearComponent();
});
this.resultViewers.forEach(DataResultViewer::clearComponent);
this.directoryTablePath.removeAll();
this.directoryTablePath = null;
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.
*/
@ -563,9 +546,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
* Pass the selected nodes to all of the result viewers
* sharing this explorer manager.
*/
resultViewers.forEach((viewer) -> {
viewer.setSelectedNodes(selectedNodes);
});
resultViewers.forEach((viewer) -> viewer.setSelectedNodes(selectedNodes));
/*
* Passing null signals that either multiple nodes are

View File

@ -80,6 +80,9 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
@NbBundle.Messages("DataResultViewerTable.firstColLbl=Name")
static private final String FIRST_COLUMN_LABEL = Bundle.DataResultViewerTable_firstColLbl();
private static final Color TAGGED_COLOR = new Color(255, 255, 195);
private final String title;
/**
* The properties map:
*
@ -108,17 +111,42 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
/**
* Listener for table model event and mouse clicks.
*/
private TableListener tableListener;
private final TableListener tableListener;
/**
* 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
*/
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);
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.
*/
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
@ -579,7 +590,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
@Override
@NbBundle.Messages("DataResultViewerTable.title=Table")
public String getTitle() {
return Bundle.DataResultViewerTable_title();
return title;
}
@Override
@ -764,7 +775,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
// only override the color if a node is not selected
if (!isSelected) {
if (currentRoot != null && !isSelected) {
Node node = currentRoot.getChildren().getNodeAt(table.convertRowIndexToModel(row));
boolean tagFound = false;
if (node != null) {

View File

@ -61,6 +61,7 @@ public abstract class AbstractFsContentNode<T extends AbstractFile> extends Abst
}
@Override
@NbBundle.Messages("AbstractFsContentNode.noDesc.text=no description")
protected Sheet createSheet() {
Sheet s = super.createSheet();
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<>();
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()) {
final String propString = propType.toString();
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.createAutopsyNodeVisitor.exception.noNodeMsg=No Node defined for the given DisplayableItem
AbstractContentNode.exception.cannotChangeSysName.msg=Cannot change the system name.
AbstractFsContentNode.noDesc.text=no description
ArtifactStringContent.getStr.srcFilePath.text=Source File Path
ArtifactStringContent.getStr.err=Error getting content
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.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.AccountFileInstance;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -294,13 +295,13 @@ final public class Accounts implements AutopsyVisitableItem {
@Override
protected Node[] createNodes(String key) {
try {
Account.Type accountType = Account.Type.valueOf(key);
switch (accountType) {
case CREDIT_CARD:
String accountType = key;
if (accountType.equals(Account.Type.CREDIT_CARD.getTypeName())) {
return new Node[]{new CreditCardNumberAccountTypeNode()};
default:
} else {
return new Node[]{new DefaultAccountTypeNode(key)};
}
} catch (IllegalArgumentException ex) {
LOGGER.log(Level.WARNING, "Unknown account type: {0}", key);
//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
+ " 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.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
+ getRejectedArtifactFilterClause()
+ " 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
+ " 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.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
+ getRejectedArtifactFilterClause()
+ " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo";

View File

@ -990,7 +990,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
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());
if (accountNode == null) {
return;

View File

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

View File

@ -14,6 +14,7 @@
<!-- for file search -->
<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 -->
<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.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.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.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
@ -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-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.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1-javadoc.jar
nbm.needs.restart=true
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
@ -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-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.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.event</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.codes</package>
<package>com.github.mustachejava.functions</package>
@ -679,6 +682,10 @@
<runtime-relative-path>ext/compiler-0.9.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/compiler-0.9.1.jar</binary-origin>
</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>
<runtime-relative-path>ext/imageio-iff-3.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/imageio-iff-3.2.jar</binary-origin>

View File

@ -1,7 +1,7 @@
"""
Autopsy Forensic Browser
Copyright 2016 Basis Technology Corp.
Copyright 2016-17 Basis Technology Corp.
Contact: carrier <at> sleuthkit <dot> org
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 import Content
from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel import Account
from org.sleuthkit.datamodel import Relationship
import traceback
import general
deviceAccountInstance = None
"""
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):
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.addAll(fileManager.findFiles(dataSource, "contacts.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))
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)
try:

View File

@ -1,7 +1,7 @@
"""
Autopsy Forensic Browser
Copyright 2016 Basis Technology Corp.
Copyright 2016-17 Basis Technology Corp.
Contact: carrier <at> sleuthkit <dot> org
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 Content
from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel import Account
from org.sleuthkit.datamodel import Relationship
import traceback
import general
deviceAccountInstance = None
"""
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):
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.addAll(fileManager.findFiles(dataSource, "contacts2.db"))
if absFiles.isEmpty():
@ -131,12 +144,21 @@ class ContactAnalyzer(general.AndroidComponentAnalyzer):
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))
if mimetype == "vnd.android.cursor.item/phone_v2":
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, general.MODULE_NAME, data1))
acctType = Account.Type.PHONE
else:
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
artifact.addAttributes(attributes)
bbartifacts.append(artifact)
try:

View File

@ -42,10 +42,13 @@ from org.sleuthkit.datamodel import BlackboardArtifact
from org.sleuthkit.datamodel import BlackboardAttribute
from org.sleuthkit.datamodel import Content
from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel import Account
import traceback
import general
deviceAccountInstance = None
"""
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):
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")
for abstractFile in absFiles:
try:

View File

@ -1,7 +1,7 @@
"""
Autopsy Forensic Browser
Copyright 2016 Basis Technology Corp.
Copyright 2016-17 Basis Technology Corp.
Contact: carrier <at> sleuthkit <dot> org
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 Content
from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel import Account
from org.sleuthkit.datamodel import Relationship
import traceback
import general
deviceAccountInstance = None
"""
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):
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")
for abstractFile in absFiles:
try:
@ -108,6 +121,13 @@ class TextMessageAnalyzer(general.AndroidComponentAnalyzer):
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "SMS Message"))
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)
try:
# index the artifact for keyword search

View File

@ -1,7 +1,7 @@
"""
Autopsy Forensic Browser
Copyright 2016 Basis Technology Corp.
Copyright 2016-17 Basis Technology Corp.
Contact: carrier <at> sleuthkit <dot> org
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 Content
from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel import Account
from org.sleuthkit.datamodel import Relationship
import traceback
import general
wwfAccountType = None
deviceAccountInstance = None
"""
Analyzes messages from Words With Friends
"""
@ -53,6 +58,18 @@ class WWFMessageAnalyzer(general.AndroidComponentAnalyzer):
def analyze(self, dataSource, fileManager, context):
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")
for abstractFile in absFiles:
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"))
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:
# index the artifact for keyword search
blackboard = Case.getCurrentCase().getServices().getBlackboard()

View File

@ -173,7 +173,14 @@ public class ExtractedContentViewer implements DataContentViewer {
}
}
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 {

View File

@ -222,9 +222,6 @@ class QueryResults {
* Post an artifact for the hit to the blackboard.
*/
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.

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.SolrDocumentList;
import org.apache.solr.common.params.CursorMarkParams;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
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 org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.AccountFileInstance;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -444,28 +447,67 @@ final class RegexQuery implements KeywordSearchQuery {
}
/*
* Create either a "plain vanilla" keyword hit artifact with keyword and
* regex attributes, or a credit card account artifact with attributes
* parsed from from the snippet for the hit and looked up based on the
* parsed bank identifcation number.
* Credit Card number hits are handled differently
*/
if (originalKeyword.getArtifactAttributeType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
createCCNAccount(content, foundKeyword, hit, snippet, listName);
return null;
}
/*
* Create a "plain vanilla" keyword hit artifact with keyword and
* regex attributes
*/
BlackboardArtifact newArtifact;
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, getQueryString()));
try {
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
return null;
}
} else {
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()));
try {
newArtifact.addAttributes(attributes);
return newArtifact;
} catch (TskCoreException e) {
LOGGER.log(Level.SEVERE, "Error adding bb attributes for terms search artifact", e); //NON-NLS
return null;
}
}
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;
}
/*
* Parse the credit card account attributes from the snippet for the
* hit.
* Create a credit card account with attributes
* parsed from the snippet for the hit and looked up based on the
* parsed bank identifcation number.
*/
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE, MODULE_NAME, Account.Type.CREDIT_CARD.name()));
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()) {
@ -477,12 +519,18 @@ final class RegexQuery implements KeywordSearchQuery {
}
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
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 null;
}
return;
}
attributes.addAll(parsedTrackAttributeMap.values());
@ -524,17 +572,6 @@ final class RegexQuery implements KeywordSearchQuery {
}
}
/*
* 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)) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
}
@ -548,15 +585,21 @@ final class RegexQuery implements KeywordSearchQuery {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.REGEX.ordinal()));
/*
* Create an account instance.
*/
try {
newArtifact.addAttributes(attributes);
return newArtifact;
} catch (TskCoreException e) {
LOGGER.log(Level.SEVERE, "Error adding bb attributes for terms search artifact", e); //NON-NLS
return null;
}
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
* 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.solr.client.solrj.SolrQuery;
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.Version;
import org.sleuthkit.autopsy.datamodel.CreditCards;
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.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -342,15 +345,22 @@ final class TermsComponentQuery implements KeywordSearchQuery {
*/
@Override
public BlackboardArtifact postKeywordHitToBlackboard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
/*
* Create either a "plain vanilla" keyword hit artifact with keyword and
* regex attributes, or a credit card account artifact with attributes
* parsed from from the snippet for the hit and looked up based on the
* parsed bank identifcation number.
* CCN hits are handled specially
*/
if (originalKeyword.getArtifactAttributeType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
createCCNAccount(content, hit, snippet, listName);
return null;
}
/*
* Create a "plain vanilla" keyword hit artifact with keyword and regex
* attributes,
*/
BlackboardArtifact newArtifact;
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()));
@ -361,12 +371,44 @@ final class TermsComponentQuery implements KeywordSearchQuery {
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
return null;
}
} else {
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()));
try {
newArtifact.addAttributes(attributes);
return newArtifact;
} catch (TskCoreException e) {
LOGGER.log(Level.SEVERE, "Error adding bb attributes for terms search artifact", e); //NON-NLS
return null;
}
}
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;
}
/*
* Parse the credit card account attributes from the snippet for the
* hit.
* 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.
*/
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE, MODULE_NAME, Account.Type.CREDIT_CARD.name()));
Collection<BlackboardAttribute> attributes = new ArrayList<>();
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
Matcher matcher = CREDIT_CARD_TRACK1_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
@ -381,9 +423,19 @@ final class TermsComponentQuery implements KeywordSearchQuery {
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
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
}
return null;
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());
@ -414,8 +466,7 @@ final class TermsComponentQuery implements KeywordSearchQuery {
/*
* If the hit is from unused or unallocated space, record the Solr
* document id to support showing just the chunk that contained the
* hit.
* document id to support showing just the chunk that contained the hit.
*/
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile) content;
@ -425,17 +476,6 @@ final class TermsComponentQuery implements KeywordSearchQuery {
}
}
/*
* 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)) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
}
@ -450,13 +490,17 @@ final class TermsComponentQuery implements KeywordSearchQuery {
// 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 {
newArtifact.addAttributes(attributes);
return newArtifact;
} catch (TskCoreException e) {
LOGGER.log(Level.SEVERE, "Error adding bb attributes for terms search artifact", e); //NON-NLS
return null;
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
}
}
/**

View File

@ -1,5 +1,5 @@
#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
SPLASH_HEIGHT=314
SPLASH_WIDTH=538

View File

@ -1,4 +1,4 @@
#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_No_Project=Autopsy 4.5.0

View File

@ -21,8 +21,13 @@ package org.sleuthkit.autopsy.thunderbirdparser;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
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.Messages;
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.ModuleDataEvent;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.AccountFileInstance;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.Relationship;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskDataException;
import org.sleuthkit.datamodel.TskException;
/**
@ -354,6 +363,24 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
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.
*
@ -377,55 +404,71 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
long id = email.getId();
String localPath = email.getLocalPath();
if (headers.isEmpty() == false) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HEADERS, EmailParserModuleFactory.getModuleName(), headers));
List<String> senderAddressList = new ArrayList<>();
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);
}
if (from.isEmpty() == false) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_FROM, EmailParserModuleFactory.getModuleName(), from));
catch(TskCoreException ex) {
logger.log(Level.WARNING, "Failed to create account for email address " + senderAddress, ex); //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));
else {
logger.log(Level.WARNING, "Failed to find sender address, from = "+ from); //NON-NLS
}
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));
}
List<String> recipientAddresses = new ArrayList<>();
recipientAddresses.addAll(findEmailAddresess(to));
recipientAddresses.addAll(findEmailAddresess(cc));
recipientAddresses.addAll(findEmailAddresess(bcc));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_MSG_ID, EmailParserModuleFactory.getModuleName(), ((id < 0L) ? NbBundle
.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(id))));
List<AccountFileInstance> recipientAccountInstances = new ArrayList<>();
recipientAddresses.forEach((addr) -> {
try {
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
}
});
if (localPath.isEmpty() == false) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, EmailParserModuleFactory.getModuleName(), localPath));
} else {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, EmailParserModuleFactory.getModuleName(), "/foo/bar")); //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) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CC, EmailParserModuleFactory.getModuleName(), cc));
}
if (bcc.isEmpty() == false) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_BCC, EmailParserModuleFactory.getModuleName(), bcc));
}
addEmailAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_RCVD, bbattributes);
addEmailAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_SENT, bbattributes);
addEmailAttribute(body, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN, bbattributes);
addEmailAttribute(((id < 0L) ? NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(id)),
ATTRIBUTE_TYPE.TSK_MSG_ID, bbattributes);
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);
if (bodyHTML.isEmpty() == false) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, EmailParserModuleFactory.getModuleName(), bodyHTML));
}
if (rtf.isEmpty() == false) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, EmailParserModuleFactory.getModuleName(), rtf));
}
try {
bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
bbart.addAttributes(bbattributes);
// Add account relationships
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance, recipientAccountInstances, bbart,Relationship.Type.MESSAGE, dateL);
try {
// index the artifact for keyword search
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
MessageNotifyUtil.Notify.error(Bundle.ThunderbirdMboxFileIngestModule_addArtifact_indexError_message(), bbart.getDisplayName());
}
} catch (TskCoreException ex) {
} catch (TskCoreException | TskDataException ex) {
logger.log(Level.WARNING, null, ex);
}
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) {
IngestMessage ingestMessage = IngestMessage.createErrorMessage(EmailParserModuleFactory.getModuleVersion(), subj, details);
services.postMessage(ingestMessage);
@ -451,5 +505,6 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
@Override
public void shutDown() {
// nothing to shut down
}
}