Merge pull request #3274 from sleuthkit/accounts_relationships
907: merge account_relationships to develop
@ -22,5 +22,6 @@
|
|||||||
|
|
||||||
<dependency conf="core->default" org="org.apache.commons" name="commons-dbcp2" rev="2.1.1"/>
|
<dependency conf="core->default" org="org.apache.commons" name="commons-dbcp2" rev="2.1.1"/>
|
||||||
<dependency conf="core->default" org="org.apache.commons" name="commons-pool2" rev="2.4.2"/>
|
<dependency conf="core->default" org="org.apache.commons" name="commons-pool2" rev="2.4.2"/>
|
||||||
|
<dependency conf="core->default" org="org.jsoup" name="jsoup" rev="1.10.3"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</ivy-module>
|
</ivy-module>
|
||||||
|
@ -5,6 +5,7 @@ file.reference.commons-dbcp2-2.1.1.jar=release\\modules\\ext\\commons-dbcp2-2.1.
|
|||||||
file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.2.jar
|
file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.2.jar
|
||||||
file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
|
file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
|
||||||
file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar
|
file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar
|
||||||
|
file.reference.jsoup-1.10.3.jar=release/modules/ext/jsoup-1.10.3.jar
|
||||||
file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar
|
file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar
|
||||||
file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar
|
file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar
|
||||||
file.reference.metadata-extractor-2.9.1.jar=release/modules/ext/metadata-extractor-2.9.1.jar
|
file.reference.metadata-extractor-2.9.1.jar=release/modules/ext/metadata-extractor-2.9.1.jar
|
||||||
|
@ -320,6 +320,10 @@
|
|||||||
<package>org.sleuthkit.autopsy.report</package>
|
<package>org.sleuthkit.autopsy.report</package>
|
||||||
<package>org.sleuthkit.datamodel</package>
|
<package>org.sleuthkit.datamodel</package>
|
||||||
</public-packages>
|
</public-packages>
|
||||||
|
<class-path-extension>
|
||||||
|
<runtime-relative-path>ext/xmpcore-5.1.2.jar</runtime-relative-path>
|
||||||
|
<binary-origin>release/modules/ext/xmpcore-5.1.2.jar</binary-origin>
|
||||||
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/zookeeper-3.4.6.jar</runtime-relative-path>
|
<runtime-relative-path>ext/zookeeper-3.4.6.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/zookeeper-3.4.6.jar</binary-origin>
|
<binary-origin>release/modules/ext/zookeeper-3.4.6.jar</binary-origin>
|
||||||
@ -335,6 +339,10 @@
|
|||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/Tsk_DataModel_PostgreSQL.jar</runtime-relative-path>
|
<runtime-relative-path>ext/Tsk_DataModel_PostgreSQL.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/Tsk_DataModel_PostgreSQL.jar</binary-origin>
|
<binary-origin>release/modules/ext/Tsk_DataModel_PostgreSQL.jar</binary-origin>
|
||||||
|
</class-path-extension>
|
||||||
|
<class-path-extension>
|
||||||
|
<runtime-relative-path>ext/StixLib.jar</runtime-relative-path>
|
||||||
|
<binary-origin>release/modules/ext/StixLib.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
|
<runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
|
||||||
@ -344,6 +352,10 @@
|
|||||||
<runtime-relative-path>ext/curator-framework-2.8.0.jar</runtime-relative-path>
|
<runtime-relative-path>ext/curator-framework-2.8.0.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/curator-framework-2.8.0.jar</binary-origin>
|
<binary-origin>release/modules/ext/curator-framework-2.8.0.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
|
<class-path-extension>
|
||||||
|
<runtime-relative-path>ext/curator-client-2.8.0.jar</runtime-relative-path>
|
||||||
|
<binary-origin>release/modules/ext/curator-client-2.8.0.jar</binary-origin>
|
||||||
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/commons-dbcp2-2.1.1.jar</runtime-relative-path>
|
<runtime-relative-path>ext/commons-dbcp2-2.1.1.jar</runtime-relative-path>
|
||||||
<binary-origin>release\modules\ext\commons-dbcp2-2.1.1.jar</binary-origin>
|
<binary-origin>release\modules\ext\commons-dbcp2-2.1.1.jar</binary-origin>
|
||||||
@ -356,6 +368,14 @@
|
|||||||
<runtime-relative-path>ext/jython-standalone-2.7.0.jar</runtime-relative-path>
|
<runtime-relative-path>ext/jython-standalone-2.7.0.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/jython-standalone-2.7.0.jar</binary-origin>
|
<binary-origin>release/modules/ext/jython-standalone-2.7.0.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
|
<class-path-extension>
|
||||||
|
<runtime-relative-path>ext/activemq-all-5.11.1.jar</runtime-relative-path>
|
||||||
|
<binary-origin>release/modules/ext/activemq-all-5.11.1.jar</binary-origin>
|
||||||
|
</class-path-extension>
|
||||||
|
<class-path-extension>
|
||||||
|
<runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
|
||||||
|
<binary-origin>release/modules/ext/opencv-248.jar</binary-origin>
|
||||||
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/sevenzipjbinding.jar</runtime-relative-path>
|
<runtime-relative-path>ext/sevenzipjbinding.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/sevenzipjbinding.jar</binary-origin>
|
<binary-origin>release/modules/ext/sevenzipjbinding.jar</binary-origin>
|
||||||
@ -377,12 +397,12 @@
|
|||||||
<binary-origin>release/modules/ext/xmpcore-5.1.2.jar</binary-origin>
|
<binary-origin>release/modules/ext/xmpcore-5.1.2.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/StixLib.jar</runtime-relative-path>
|
<runtime-relative-path>ext/sevenzipjbinding-AllPlatforms.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/StixLib.jar</binary-origin>
|
<binary-origin>release/modules/ext/sevenzipjbinding-AllPlatforms.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/curator-client-2.8.0.jar</runtime-relative-path>
|
<runtime-relative-path>ext/commons-pool2-2.4.2.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/curator-client-2.8.0.jar</binary-origin>
|
<binary-origin>release\modules\ext\commons-pool2-2.4.2.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/sqlite-jdbc-3.8.11.jar</runtime-relative-path>
|
<runtime-relative-path>ext/sqlite-jdbc-3.8.11.jar</runtime-relative-path>
|
||||||
@ -392,18 +412,14 @@
|
|||||||
<runtime-relative-path>ext/activemq-all-5.11.1.jar</runtime-relative-path>
|
<runtime-relative-path>ext/activemq-all-5.11.1.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/activemq-all-5.11.1.jar</binary-origin>
|
<binary-origin>release/modules/ext/activemq-all-5.11.1.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
|
<class-path-extension>
|
||||||
|
<runtime-relative-path>ext/jsoup-1.10.3.jar</runtime-relative-path>
|
||||||
|
<binary-origin>release/modules/ext/jsoup-1.10.3.jar</binary-origin>
|
||||||
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/Rejistry-1.0-SNAPSHOT.jar</runtime-relative-path>
|
<runtime-relative-path>ext/Rejistry-1.0-SNAPSHOT.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/Rejistry-1.0-SNAPSHOT.jar</binary-origin>
|
<binary-origin>release/modules/ext/Rejistry-1.0-SNAPSHOT.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
|
||||||
<runtime-relative-path>ext/sevenzipjbinding-AllPlatforms.jar</runtime-relative-path>
|
|
||||||
<binary-origin>release/modules/ext/sevenzipjbinding-AllPlatforms.jar</binary-origin>
|
|
||||||
</class-path-extension>
|
|
||||||
<class-path-extension>
|
|
||||||
<runtime-relative-path>ext/commons-pool2-2.4.2.jar</runtime-relative-path>
|
|
||||||
<binary-origin>release\modules\ext\commons-pool2-2.4.2.jar</binary-origin>
|
|
||||||
</class-path-extension>
|
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/metadata-extractor-2.9.1.jar</runtime-relative-path>
|
<runtime-relative-path>ext/metadata-extractor-2.9.1.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/metadata-extractor-2.9.1.jar</binary-origin>
|
<binary-origin>release/modules/ext/metadata-extractor-2.9.1.jar</binary-origin>
|
||||||
@ -420,6 +436,10 @@
|
|||||||
<runtime-relative-path>ext/c3p0-0.9.5.jar</runtime-relative-path>
|
<runtime-relative-path>ext/c3p0-0.9.5.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/c3p0-0.9.5.jar</binary-origin>
|
<binary-origin>release/modules/ext/c3p0-0.9.5.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
|
<class-path-extension>
|
||||||
|
<runtime-relative-path>ext/c3p0-0.9.5.jar</runtime-relative-path>
|
||||||
|
<binary-origin>release/modules/ext/c3p0-0.9.5.jar</binary-origin>
|
||||||
|
</class-path-extension>
|
||||||
</data>
|
</data>
|
||||||
</configuration>
|
</configuration>
|
||||||
</project>
|
</project>
|
||||||
|
@ -76,6 +76,7 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
|||||||
import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.events.ReportAddedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.ReportAddedEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.Services;
|
import org.sleuthkit.autopsy.casemodule.services.Services;
|
||||||
|
import org.sleuthkit.autopsy.communications.OpenCommVisualizationToolAction;
|
||||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
||||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CategoryNode;
|
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CategoryNode;
|
||||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException;
|
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException;
|
||||||
@ -1050,6 +1051,7 @@ public class Case {
|
|||||||
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true);
|
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true);
|
||||||
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true);
|
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true);
|
||||||
CallableSystemAction.get(OpenTimelineAction.class).setEnabled(true);
|
CallableSystemAction.get(OpenTimelineAction.class).setEnabled(true);
|
||||||
|
CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(true);
|
||||||
CallableSystemAction.get(OpenOutputFolderAction.class).setEnabled(false);
|
CallableSystemAction.get(OpenOutputFolderAction.class).setEnabled(false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1092,24 +1094,13 @@ public class Case {
|
|||||||
/*
|
/*
|
||||||
* Disable the case-specific menu items.
|
* Disable the case-specific menu items.
|
||||||
*/
|
*/
|
||||||
CallableSystemAction
|
CallableSystemAction.get(AddImageAction.class).setEnabled(false);
|
||||||
.get(AddImageAction.class
|
CallableSystemAction.get(CaseCloseAction.class).setEnabled(false);
|
||||||
).setEnabled(false);
|
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(false);
|
||||||
CallableSystemAction
|
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(false);
|
||||||
.get(CaseCloseAction.class
|
CallableSystemAction.get(OpenTimelineAction.class).setEnabled(false);
|
||||||
).setEnabled(false);
|
CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(false);
|
||||||
CallableSystemAction
|
CallableSystemAction.get(OpenOutputFolderAction.class).setEnabled(false);
|
||||||
.get(CasePropertiesAction.class
|
|
||||||
).setEnabled(false);
|
|
||||||
CallableSystemAction
|
|
||||||
.get(CaseDeleteAction.class
|
|
||||||
).setEnabled(false);
|
|
||||||
CallableSystemAction
|
|
||||||
.get(OpenTimelineAction.class
|
|
||||||
).setEnabled(false);
|
|
||||||
CallableSystemAction
|
|
||||||
.get(OpenOutputFolderAction.class
|
|
||||||
).setEnabled(false);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear the notifications in the notfier component in the lower
|
* Clear the notifications in the notfier component in the lower
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
@ -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
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
@ -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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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>
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
364
Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form
Normal 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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
556
Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java
Normal 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
|
||||||
|
}
|
@ -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>
|
@ -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
|
||||||
|
|
||||||
|
}
|
@ -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.
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -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 "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
72
Core/src/org/sleuthkit/autopsy/communications/Utils.java
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png
Executable file
After Width: | Height: | Size: 864 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/calllog.png
Executable file
After Width: | Height: | Size: 691 B |
After Width: | Height: | Size: 499 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/credit-card.png
Executable file
After Width: | Height: | Size: 536 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/email.png
Executable file
After Width: | Height: | Size: 710 B |
After Width: | Height: | Size: 821 B |
After Width: | Height: | Size: 887 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 541 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/folder-icon-16.png
Executable file
After Width: | Height: | Size: 483 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/funnel.png
Executable file
After Width: | Height: | Size: 591 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/image.png
Executable file
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 804 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/messaging.png
Executable file
After Width: | Height: | Size: 829 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/phone.png
Normal file
After Width: | Height: | Size: 488 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/table.png
Normal file
After Width: | Height: | Size: 566 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/tick.png
Executable file
After Width: | Height: | Size: 582 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/twitter.png
Normal file
After Width: | Height: | Size: 656 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/web-file.png
Executable file
After Width: | Height: | Size: 928 B |
@ -17,3 +17,19 @@ Metadata.toolTip=Displays metadata about the file.
|
|||||||
Metadata.nodeText.nonFilePassedIn=Non-file passed in
|
Metadata.nodeText.nonFilePassedIn=Non-file passed in
|
||||||
Metadata.nodeText.text=From The Sleuth Kit istat Tool\:
|
Metadata.nodeText.text=From The Sleuth Kit istat Tool\:
|
||||||
Metadata.nodeText.exceptionNotice.text=Error getting file metadata\:
|
Metadata.nodeText.exceptionNotice.text=Error getting file metadata\:
|
||||||
|
MessageContentViewer.rtfbodyScrollPane.TabConstraints.tabTitle=RTF
|
||||||
|
MessageContentViewer.headersScrollPane.TabConstraints.tabTitle=Headers
|
||||||
|
MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle=Text
|
||||||
|
MessageContentViewer.htmlPane.TabConstraints.tabTitle=HTML
|
||||||
|
MessageContentViewer.fromText.text=from address goes here
|
||||||
|
MessageContentViewer.fromLabel.text=From:
|
||||||
|
MessageContentViewer.datetimeText.text=date goes here
|
||||||
|
MessageContentViewer.toText.text=to list goes here
|
||||||
|
MessageContentViewer.toLabel.text=To:
|
||||||
|
MessageContentViewer.ccText.text=cc list goes here
|
||||||
|
MessageContentViewer.subjectLabel.text=Subject:
|
||||||
|
MessageContentViewer.subjectText.text=subject goes here
|
||||||
|
MessageContentViewer.directionText.text=direction
|
||||||
|
MessageContentViewer.ccLabel.text=CC:
|
||||||
|
MessageContentViewer.attachmentsPanel.TabConstraints.tabTitle=Attachments
|
||||||
|
MessageContentViewer.viewInNewWindowButton.text=View in New Window
|
||||||
|
@ -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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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>
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.contentviewers;
|
|||||||
import javax.swing.JTextPane;
|
import javax.swing.JTextPane;
|
||||||
import javax.swing.text.html.HTMLEditorKit;
|
import javax.swing.text.html.HTMLEditorKit;
|
||||||
import javax.swing.text.html.StyleSheet;
|
import javax.swing.text.html.StyleSheet;
|
||||||
|
import javax.swing.text.rtf.RTFEditorKit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -47,4 +48,11 @@ public class Utilities {
|
|||||||
styleSheet.addRule("th {font-family:Arial, 'ヒラギノ角ゴ Pro W3','Hiragino Kaku Gothic Pro','メイリオ',Meiryo,'MS Pゴシック','MS PGothic',sans-serif;font-size:14pt;overflow:hidden;padding-right:5px;padding-left:5px;font-weight:bold;}"); //NON-NLS
|
styleSheet.addRule("th {font-family:Arial, 'ヒラギノ角ゴ Pro W3','Hiragino Kaku Gothic Pro','メイリオ',Meiryo,'MS 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,'MS Pゴシック','MS PGothic',sans-serif;font-size:14pt;}"); //NON-NLS
|
styleSheet.addRule("p {font-family:Arial, 'ヒラギノ角ゴ Pro W3','Hiragino Kaku Gothic Pro','メイリオ',Meiryo,'MS 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
11
Core/src/org/sleuthkit/autopsy/core/cvtWsmode.xml
Normal 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>
|
||||||
|
|
@ -443,6 +443,7 @@
|
|||||||
<folder name="floatingLeftBottom"/>
|
<folder name="floatingLeftBottom"/>
|
||||||
<file name="floatingLeftBottom.wsmode" url="floatingLeftBottomWsmode.xml"/>
|
<file name="floatingLeftBottom.wsmode" url="floatingLeftBottomWsmode.xml"/>
|
||||||
<file name="timeline.wsmode" url="timelineWsmode.xml"/>
|
<file name="timeline.wsmode" url="timelineWsmode.xml"/>
|
||||||
|
<file name="cvt.wsmode" url="cvtWsmode.xml"/>
|
||||||
</folder>
|
</folder>
|
||||||
</folder>
|
</folder>
|
||||||
|
|
||||||
|
@ -20,12 +20,10 @@ package org.sleuthkit.autopsy.corecomponentinterfaces;
|
|||||||
|
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.windows.TopComponent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The interface for the "bottom right component" window.
|
* The interface for the "bottom right component" window.
|
||||||
*
|
*
|
||||||
* @author jantonius
|
|
||||||
*/
|
*/
|
||||||
public interface DataContent extends PropertyChangeListener {
|
public interface DataContent extends PropertyChangeListener {
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013 Basis Technology Corp.
|
* Copyright 2011-17 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -85,10 +85,13 @@ public interface DataResultViewer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a custom content viewer to respond to selection events from this
|
* Set a custom content viewer to respond to selection events from this
|
||||||
* result viewer. If not set, the default content viewer is user
|
* result viewer. If not set, the default content viewer is used
|
||||||
*
|
*
|
||||||
* @param contentViewer content viewer to respond to selection events from
|
* @param contentViewer content viewer to respond to selection events from
|
||||||
* this viewer
|
* this viewer
|
||||||
|
*
|
||||||
|
* @deprecated All implementations of this in the standard DataResultViewers are now no-ops.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setContentViewer(DataContent contentViewer);
|
public void setContentViewer(DataContent contentViewer);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013 Basis Technology Corp.
|
* Copyright 2011-17 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -25,7 +25,6 @@ import javax.swing.JPanel;
|
|||||||
import org.openide.explorer.ExplorerManager;
|
import org.openide.explorer.ExplorerManager;
|
||||||
import org.openide.explorer.ExplorerManager.Provider;
|
import org.openide.explorer.ExplorerManager.Provider;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.util.Lookup;
|
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
@ -40,11 +39,6 @@ abstract class AbstractDataResultViewer extends JPanel implements DataResultView
|
|||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(AbstractDataResultViewer.class.getName());
|
private static final Logger logger = Logger.getLogger(AbstractDataResultViewer.class.getName());
|
||||||
protected transient ExplorerManager em;
|
protected transient ExplorerManager em;
|
||||||
/**
|
|
||||||
* Content viewer to respond to selection events Either the main one, or
|
|
||||||
* custom one if set
|
|
||||||
*/
|
|
||||||
protected DataContent contentViewer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor is intended to allow an AbstractDataResultViewer to use
|
* This constructor is intended to allow an AbstractDataResultViewer to use
|
||||||
@ -53,10 +47,11 @@ abstract class AbstractDataResultViewer extends JPanel implements DataResultView
|
|||||||
* TopComponent has focus. The ExplorerManager must be present when the
|
* TopComponent has focus. The ExplorerManager must be present when the
|
||||||
* object is constructed so that its child components can discover it using
|
* object is constructed so that its child components can discover it using
|
||||||
* the ExplorerManager.find() method.
|
* the ExplorerManager.find() method.
|
||||||
|
*
|
||||||
|
* @param explorerManager
|
||||||
*/
|
*/
|
||||||
public AbstractDataResultViewer(ExplorerManager explorerManager) {
|
AbstractDataResultViewer(ExplorerManager explorerManager) {
|
||||||
this.em = explorerManager;
|
this.em = explorerManager;
|
||||||
initialize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,14 +60,7 @@ abstract class AbstractDataResultViewer extends JPanel implements DataResultView
|
|||||||
* context lookup.
|
* context lookup.
|
||||||
*/
|
*/
|
||||||
public AbstractDataResultViewer() {
|
public AbstractDataResultViewer() {
|
||||||
em = new ExplorerManager();
|
this(new ExplorerManager());
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initialize() {
|
|
||||||
//DataContent is designed to return only the default viewer from lookup
|
|
||||||
//use the default one unless set otherwise
|
|
||||||
contentViewer = Lookup.getDefault().lookup(DataContent.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -115,8 +103,8 @@ abstract class AbstractDataResultViewer extends JPanel implements DataResultView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
@Override
|
@Override
|
||||||
public void setContentViewer(DataContent contentViewer) {
|
public void setContentViewer(DataContent contentViewer) {
|
||||||
this.contentViewer = contentViewer;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import java.awt.Cursor;
|
|||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.JTabbedPane;
|
import javax.swing.JTabbedPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
@ -64,7 +65,7 @@ import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo;
|
|||||||
* normally docked into the lower right hand side of the main window, underneath
|
* normally docked into the lower right hand side of the main window, underneath
|
||||||
* the results view. A custom content view may be specified instead.
|
* the results view. A custom content view may be specified instead.
|
||||||
*/
|
*/
|
||||||
public class DataResultPanel extends javax.swing.JPanel implements DataResult, ChangeListener {
|
public class DataResultPanel extends javax.swing.JPanel implements DataResult, ChangeListener, ExplorerManager.Provider {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final int NO_TAB_SELECTED = -1;
|
private static final int NO_TAB_SELECTED = -1;
|
||||||
@ -79,8 +80,8 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
|||||||
private DataContent contentView;
|
private DataContent contentView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs and opens a Swing JPanel with a JTabbedPane child component.
|
* Constructs and opens a DataResultPanel with the given initial data, and
|
||||||
* The tabbed pane contains result viewers.
|
* the default DataContent.
|
||||||
*
|
*
|
||||||
* @param title The title for the panel.
|
* @param title The title for the panel.
|
||||||
* @param pathText Descriptive text about the source of the nodes
|
* @param pathText Descriptive text about the source of the nodes
|
||||||
@ -98,8 +99,8 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs and opens a Swing JPanel with a JTabbedPane child component.
|
* Constructs and opens a DataResultPanel with the given initial data, and a
|
||||||
* The tabbed pane contains result viewers.
|
* custom DataContent.
|
||||||
*
|
*
|
||||||
* @param title The title for the panel.
|
* @param title The title for the panel.
|
||||||
* @param pathText Descriptive text about the source of the nodes
|
* @param pathText Descriptive text about the source of the nodes
|
||||||
@ -119,9 +120,9 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a Swing JPanel with a JTabbedPane child component. The tabbed
|
* Constructs a DataResultPanel with the given initial data, and a custom
|
||||||
* pane contains result viewers. The panel is NOT opened; the client of this
|
* DataContent. The panel is NOT opened; the client of this method must call
|
||||||
* method must call open on the panel that is returned.
|
* open on the panel that is returned.
|
||||||
*
|
*
|
||||||
* @param title The title for the panel.
|
* @param title The title for the panel.
|
||||||
* @param pathText Descriptive text about the source of the nodes
|
* @param pathText Descriptive text about the source of the nodes
|
||||||
@ -159,42 +160,32 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a Swing JPanel with a JTabbedPane child component that
|
* Constructs a DataResultPanel with the default DataContent
|
||||||
* contains result viewers (implementations of the DataResultViewer
|
|
||||||
* interface).
|
|
||||||
*/
|
|
||||||
private DataResultPanel() {
|
|
||||||
this.isMain = true;
|
|
||||||
initComponents();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a Swing JPanel with a JTabbedPane child component that
|
|
||||||
* contains result viewers (implementations of the DataResultViewer
|
|
||||||
* interface).
|
|
||||||
*
|
*
|
||||||
* @param title The title for the panel.
|
* @param title The title for the panel.
|
||||||
* @param isMain True if the DataResultPanel being constructed is the "main"
|
* @param isMain True if the DataResultPanel being constructed is the "main"
|
||||||
* DataResultPanel.
|
* DataResultPanel.
|
||||||
*/
|
*/
|
||||||
DataResultPanel(String title, boolean isMain) {
|
DataResultPanel(String title, boolean isMain) {
|
||||||
this();
|
this(isMain, Lookup.getDefault().lookup(DataContent.class));
|
||||||
|
setTitle(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataResultPanel(boolean isMain, DataContent contentView) {
|
||||||
this.isMain = isMain;
|
this.isMain = isMain;
|
||||||
this.contentView = Lookup.getDefault().lookup(DataContent.class);
|
this.contentView = contentView;
|
||||||
|
initComponents();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a Swing JPanel with a JTabbedPane child component that
|
* Constructs a DataResultPanel with the a custom DataContent.
|
||||||
* contains result viewers (implementations of the DataResultViewer
|
|
||||||
* interface).
|
|
||||||
*
|
*
|
||||||
* @param title The title for the panel.
|
* @param title The title for the panel.
|
||||||
* @param customContentView A content view to use in place of the default
|
* @param customContentView A content view to use in place of the default
|
||||||
* content view.
|
* content view.
|
||||||
*/
|
*/
|
||||||
DataResultPanel(String title, DataContent customContentView) {
|
DataResultPanel(String title, DataContent customContentView) {
|
||||||
this(title, false);
|
this(false, customContentView);
|
||||||
this.contentView = customContentView;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -245,10 +236,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
|||||||
*
|
*
|
||||||
* @param resultViewer The result viewer.
|
* @param resultViewer The result viewer.
|
||||||
*/
|
*/
|
||||||
private void addResultViewer(DataResultViewer resultViewer) {
|
public void addResultViewer(DataResultViewer resultViewer) {
|
||||||
if (null != contentView) {
|
|
||||||
resultViewer.setContentViewer(contentView);
|
|
||||||
}
|
|
||||||
resultViewers.add(resultViewer);
|
resultViewers.add(resultViewer);
|
||||||
dataResultTabbedPanel.addTab(resultViewer.getTitle(), resultViewer.getComponent());
|
dataResultTabbedPanel.addTab(resultViewer.getTitle(), resultViewer.getComponent());
|
||||||
}
|
}
|
||||||
@ -260,11 +248,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<DataResultViewer> getViewers() {
|
public List<DataResultViewer> getViewers() {
|
||||||
List<DataResultViewer> viewers = new ArrayList<>();
|
return Collections.unmodifiableList(resultViewers);
|
||||||
resultViewers.forEach((viewer) -> {
|
|
||||||
viewers.add(viewer);
|
|
||||||
});
|
|
||||||
return viewers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -397,9 +381,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
|||||||
* @param selectedNodes The nodes to be selected.
|
* @param selectedNodes The nodes to be selected.
|
||||||
*/
|
*/
|
||||||
public void setSelectedNodes(Node[] selectedNodes) {
|
public void setSelectedNodes(Node[] selectedNodes) {
|
||||||
this.resultViewers.forEach((viewer) -> {
|
this.resultViewers.forEach((viewer) -> viewer.setSelectedNodes(selectedNodes));
|
||||||
viewer.setSelectedNodes(selectedNodes);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -517,14 +499,10 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
|||||||
explorerManager = null;
|
explorerManager = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resultViewers.forEach((viewer) -> {
|
this.resultViewers.forEach((viewer) -> viewer.setNode(null));
|
||||||
viewer.setNode(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!this.isMain) {
|
if (!this.isMain) {
|
||||||
this.resultViewers.forEach((viewer) -> {
|
this.resultViewers.forEach(DataResultViewer::clearComponent);
|
||||||
viewer.clearComponent();
|
|
||||||
});
|
|
||||||
this.directoryTablePath.removeAll();
|
this.directoryTablePath.removeAll();
|
||||||
this.directoryTablePath = null;
|
this.directoryTablePath = null;
|
||||||
this.numberMatchLabel.removeAll();
|
this.numberMatchLabel.removeAll();
|
||||||
@ -537,6 +515,11 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExplorerManager getExplorerManager() {
|
||||||
|
return explorerManager;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responds to node selection change events from the explorer manager.
|
* Responds to node selection change events from the explorer manager.
|
||||||
*/
|
*/
|
||||||
@ -563,9 +546,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
|||||||
* Pass the selected nodes to all of the result viewers
|
* Pass the selected nodes to all of the result viewers
|
||||||
* sharing this explorer manager.
|
* sharing this explorer manager.
|
||||||
*/
|
*/
|
||||||
resultViewers.forEach((viewer) -> {
|
resultViewers.forEach((viewer) -> viewer.setSelectedNodes(selectedNodes));
|
||||||
viewer.setSelectedNodes(selectedNodes);
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Passing null signals that either multiple nodes are
|
* Passing null signals that either multiple nodes are
|
||||||
|
@ -80,6 +80,9 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
@NbBundle.Messages("DataResultViewerTable.firstColLbl=Name")
|
@NbBundle.Messages("DataResultViewerTable.firstColLbl=Name")
|
||||||
static private final String FIRST_COLUMN_LABEL = Bundle.DataResultViewerTable_firstColLbl();
|
static private final String FIRST_COLUMN_LABEL = Bundle.DataResultViewerTable_firstColLbl();
|
||||||
private static final Color TAGGED_COLOR = new Color(255, 255, 195);
|
private static final Color TAGGED_COLOR = new Color(255, 255, 195);
|
||||||
|
|
||||||
|
private final String title;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The properties map:
|
* The properties map:
|
||||||
*
|
*
|
||||||
@ -108,17 +111,42 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
/**
|
/**
|
||||||
* Listener for table model event and mouse clicks.
|
* Listener for table model event and mouse clicks.
|
||||||
*/
|
*/
|
||||||
private TableListener tableListener;
|
private final TableListener tableListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a DataResultViewerTable object that is compatible with node
|
* Creates a DataResultViewerTable object that is compatible with node
|
||||||
* multiple selection actions.
|
* multiple selection actions, and the default title.
|
||||||
*
|
*
|
||||||
* @param explorerManager allow for explorer manager sharing
|
* @param explorerManager allow for explorer manager sharing
|
||||||
*/
|
*/
|
||||||
public DataResultViewerTable(ExplorerManager explorerManager) {
|
public DataResultViewerTable(ExplorerManager explorerManager) {
|
||||||
|
this(explorerManager, Bundle.DataResultViewerTable_title());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a DataResultViewerTable object that is compatible with node
|
||||||
|
* multiple selection actions, and a custom title.
|
||||||
|
*
|
||||||
|
* @param explorerManager allow for explorer manager sharing
|
||||||
|
* @param title The custom title.
|
||||||
|
*/
|
||||||
|
public DataResultViewerTable(ExplorerManager explorerManager, String title) {
|
||||||
super(explorerManager);
|
super(explorerManager);
|
||||||
initialize();
|
this.title = title;
|
||||||
|
|
||||||
|
initComponents();
|
||||||
|
|
||||||
|
outlineView.setAllowedDragActions(DnDConstants.ACTION_NONE);
|
||||||
|
outline = outlineView.getOutline();
|
||||||
|
outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||||
|
outline.setRootVisible(false); // don't show the root node
|
||||||
|
outline.setDragEnabled(false);
|
||||||
|
outline.setDefaultRenderer(Object.class, new ColorTagCustomRenderer());
|
||||||
|
// add a listener so that when columns are moved, the new order is stored
|
||||||
|
tableListener = new TableListener();
|
||||||
|
outline.getColumnModel().addColumnModelListener(tableListener);
|
||||||
|
// the listener also moves columns back if user tries to move the first column out of place
|
||||||
|
outline.getTableHeader().addMouseListener(tableListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,26 +154,9 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
* multiple selection actions.
|
* multiple selection actions.
|
||||||
*/
|
*/
|
||||||
public DataResultViewerTable() {
|
public DataResultViewerTable() {
|
||||||
initialize();
|
this(new ExplorerManager(),Bundle.DataResultViewerTable_title());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialize() {
|
|
||||||
initComponents();
|
|
||||||
|
|
||||||
outlineView.setAllowedDragActions(DnDConstants.ACTION_NONE);
|
|
||||||
|
|
||||||
outline = outlineView.getOutline();
|
|
||||||
outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
|
||||||
outline.setRootVisible(false); // don't show the root node
|
|
||||||
outline.setDragEnabled(false);
|
|
||||||
outline.setDefaultRenderer(Object.class, new ColorTagCustomRenderer());
|
|
||||||
|
|
||||||
// add a listener so that when columns are moved, the new order is stored
|
|
||||||
tableListener = new TableListener();
|
|
||||||
outline.getColumnModel().addColumnModelListener(tableListener);
|
|
||||||
// the listener also moves columns back if user tries to move the first column out of place
|
|
||||||
outline.getTableHeader().addMouseListener(tableListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand node
|
* Expand node
|
||||||
@ -579,7 +590,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
@Override
|
@Override
|
||||||
@NbBundle.Messages("DataResultViewerTable.title=Table")
|
@NbBundle.Messages("DataResultViewerTable.title=Table")
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return Bundle.DataResultViewerTable_title();
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -764,7 +775,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
|
|
||||||
Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
|
Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
|
||||||
// only override the color if a node is not selected
|
// only override the color if a node is not selected
|
||||||
if (!isSelected) {
|
if (currentRoot != null && !isSelected) {
|
||||||
Node node = currentRoot.getChildren().getNodeAt(table.convertRowIndexToModel(row));
|
Node node = currentRoot.getChildren().getNodeAt(table.convertRowIndexToModel(row));
|
||||||
boolean tagFound = false;
|
boolean tagFound = false;
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
|
@ -61,6 +61,7 @@ public abstract class AbstractFsContentNode<T extends AbstractFile> extends Abst
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@NbBundle.Messages("AbstractFsContentNode.noDesc.text=no description")
|
||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
Sheet s = super.createSheet();
|
Sheet s = super.createSheet();
|
||||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||||
@ -72,7 +73,7 @@ public abstract class AbstractFsContentNode<T extends AbstractFile> extends Abst
|
|||||||
Map<String, Object> map = new LinkedHashMap<>();
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
fillPropertyMap(map, getContent());
|
fillPropertyMap(map, getContent());
|
||||||
|
|
||||||
final String NO_DESCR = NbBundle.getMessage(this.getClass(), "AbstractFsContentNode.noDesc.text");
|
final String NO_DESCR = Bundle.AbstractFsContentNode_noDesc_text();
|
||||||
for (AbstractFilePropertyType propType : AbstractFilePropertyType.values()) {
|
for (AbstractFilePropertyType propType : AbstractFilePropertyType.values()) {
|
||||||
final String propString = propType.toString();
|
final String propString = propType.toString();
|
||||||
ss.put(new NodeProperty<>(propString, propString, NO_DESCR, map.get(propString)));
|
ss.put(new NodeProperty<>(propString, propString, NO_DESCR, map.get(propString)));
|
||||||
|
@ -2,7 +2,6 @@ OpenIDE-Module-Name=DataModel
|
|||||||
AbstractContentChildren.CreateTSKNodeVisitor.exception.noNodeMsg=No Node defined for the given SleuthkitItem
|
AbstractContentChildren.CreateTSKNodeVisitor.exception.noNodeMsg=No Node defined for the given SleuthkitItem
|
||||||
AbstractContentChildren.createAutopsyNodeVisitor.exception.noNodeMsg=No Node defined for the given DisplayableItem
|
AbstractContentChildren.createAutopsyNodeVisitor.exception.noNodeMsg=No Node defined for the given DisplayableItem
|
||||||
AbstractContentNode.exception.cannotChangeSysName.msg=Cannot change the system name.
|
AbstractContentNode.exception.cannotChangeSysName.msg=Cannot change the system name.
|
||||||
AbstractFsContentNode.noDesc.text=no description
|
|
||||||
ArtifactStringContent.getStr.srcFilePath.text=Source File Path
|
ArtifactStringContent.getStr.srcFilePath.text=Source File Path
|
||||||
ArtifactStringContent.getStr.err=Error getting content
|
ArtifactStringContent.getStr.err=Error getting content
|
||||||
ArtifactTypeNode.createSheet.artType.name=Artifact Type
|
ArtifactTypeNode.createSheet.artType.name=Artifact Type
|
||||||
|
@ -71,6 +71,7 @@ import org.sleuthkit.autopsy.ingest.IngestManager;
|
|||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Account;
|
import org.sleuthkit.datamodel.Account;
|
||||||
|
import org.sleuthkit.datamodel.AccountFileInstance;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
@ -294,13 +295,13 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
@Override
|
@Override
|
||||||
protected Node[] createNodes(String key) {
|
protected Node[] createNodes(String key) {
|
||||||
try {
|
try {
|
||||||
Account.Type accountType = Account.Type.valueOf(key);
|
String accountType = key;
|
||||||
switch (accountType) {
|
if (accountType.equals(Account.Type.CREDIT_CARD.getTypeName())) {
|
||||||
case CREDIT_CARD:
|
return new Node[]{new CreditCardNumberAccountTypeNode()};
|
||||||
return new Node[]{new CreditCardNumberAccountTypeNode()};
|
} else {
|
||||||
default:
|
return new Node[]{new DefaultAccountTypeNode(key)};
|
||||||
return new Node[]{new DefaultAccountTypeNode(key)};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IllegalArgumentException ex) {
|
} catch (IllegalArgumentException ex) {
|
||||||
LOGGER.log(Level.WARNING, "Unknown account type: {0}", key);
|
LOGGER.log(Level.WARNING, "Unknown account type: {0}", key);
|
||||||
//Flesh out what happens with other account types here.
|
//Flesh out what happens with other account types here.
|
||||||
@ -547,7 +548,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
+ " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS
|
+ " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS
|
||||||
+ " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS
|
+ " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS
|
||||||
+ " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
+ " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
||||||
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.name() + "'" //NON-NLS
|
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS
|
||||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||||
+ getRejectedArtifactFilterClause()
|
+ getRejectedArtifactFilterClause()
|
||||||
+ " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS
|
+ " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS
|
||||||
@ -607,7 +608,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
+ " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS
|
+ " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS
|
||||||
+ " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS
|
+ " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS
|
||||||
+ " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
+ " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
|
||||||
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.name() + "'" //NON-NLS
|
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS
|
||||||
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
|
||||||
+ getRejectedArtifactFilterClause()
|
+ getRejectedArtifactFilterClause()
|
||||||
+ " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo";
|
+ " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo";
|
||||||
@ -1427,7 +1428,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
final Collection<? extends BlackboardArtifact> artifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
|
final Collection<? extends BlackboardArtifact> artifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
|
||||||
artifacts.forEach(artifact -> {
|
artifacts.forEach(artifact -> {
|
||||||
try {
|
try {
|
||||||
skCase.setReviewStatus(artifact, newStatus);
|
skCase.setReviewStatus(artifact, newStatus);
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Error changing artifact review status.", ex); //NON-NLS
|
LOGGER.log(Level.SEVERE, "Error changing artifact review status.", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
|
@ -990,7 +990,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accountType.equals(Account.Type.CREDIT_CARD.name())) {
|
if (accountType.equals(Account.Type.CREDIT_CARD.getTypeName())) {
|
||||||
Node accountNode = accountRootChilds.findChild(Account.Type.CREDIT_CARD.getDisplayName());
|
Node accountNode = accountRootChilds.findChild(Account.Type.CREDIT_CARD.getDisplayName());
|
||||||
if (accountNode == null) {
|
if (accountNode == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -170,21 +170,27 @@ class TableReportGenerator {
|
|||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
for (String accountType : groupedArtifacts.keySet()) {
|
for (String accountTypeStr : groupedArtifacts.keySet()) {
|
||||||
/* If the report is a ReportHTML, the data type name
|
/* If the report is a ReportHTML, the data type name
|
||||||
* eventualy makes it to useDataTypeIcon which expects but
|
* eventualy makes it to useDataTypeIcon which expects but
|
||||||
* does not require a artifact name, so we make a synthetic
|
* does not require a artifact name, so we make a synthetic
|
||||||
* compund name by appending a ":" and the account type.
|
* compund name by appending a ":" and the account type.
|
||||||
*/
|
*/
|
||||||
String accountDisplayname = accountType;
|
String accountDisplayname = accountTypeStr;
|
||||||
for (Account.Type acct : Account.Type.values()) {
|
if (accountTypeStr != null) {
|
||||||
if (acct.equals(Account.Type.valueOf(accountType))) {
|
try {
|
||||||
accountDisplayname = acct.getDisplayName();
|
Account.Type acctType = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().getAccountType(accountTypeStr);
|
||||||
break;
|
if (acctType != null) {
|
||||||
|
accountDisplayname = acctType.getDisplayName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Unable to get display name for account type " + accountTypeStr, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final String compundDataTypeName = BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + accountDisplayname;
|
final String compundDataTypeName = BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + accountDisplayname;
|
||||||
writeTableForDataType(new ArrayList<>(groupedArtifacts.get(accountType)), type, compundDataTypeName, comment);
|
writeTableForDataType(new ArrayList<>(groupedArtifacts.get(accountTypeStr)), type, compundDataTypeName, comment);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//all other artifact types are sent to writeTableForDataType directly
|
//all other artifact types are sent to writeTableForDataType directly
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
<!-- for file search -->
|
<!-- for file search -->
|
||||||
<dependency conf="autopsy_core->*" org="org.jbundle.thin.base.screen" name="jcalendarbutton" rev="1.4.6"/>
|
<dependency conf="autopsy_core->*" org="org.jbundle.thin.base.screen" name="jcalendarbutton" rev="1.4.6"/>
|
||||||
|
<dependency conf="autopsy_core->*" org="com.github.lgooddatepicker" name="LGoodDatePicker" rev="10.3.1"/>
|
||||||
|
|
||||||
<!-- commmon -->
|
<!-- commmon -->
|
||||||
<dependency org="com.google.guava" name="guava" rev="19.0"/>
|
<dependency org="com.google.guava" name="guava" rev="19.0"/>
|
||||||
|
@ -53,6 +53,7 @@ file.reference.joda-time-2.4-javadoc.jar=release/modules/ext/joda-time-2.4-javad
|
|||||||
file.reference.joda-time-2.4-sources.jar=release/modules/ext/joda-time-2.4-sources.jar
|
file.reference.joda-time-2.4-sources.jar=release/modules/ext/joda-time-2.4-sources.jar
|
||||||
file.reference.joda-time-2.4.jar=release/modules/ext/joda-time-2.4.jar
|
file.reference.joda-time-2.4.jar=release/modules/ext/joda-time-2.4.jar
|
||||||
file.reference.jsr305-1.3.9.jar=release/modules/ext/jsr305-1.3.9.jar
|
file.reference.jsr305-1.3.9.jar=release/modules/ext/jsr305-1.3.9.jar
|
||||||
|
file.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1.jar
|
||||||
file.reference.log4j-1.2.17.jar=release/modules/ext/log4j-1.2.17.jar
|
file.reference.log4j-1.2.17.jar=release/modules/ext/log4j-1.2.17.jar
|
||||||
file.reference.logkit-1.0.1.jar=release/modules/ext/logkit-1.0.1.jar
|
file.reference.logkit-1.0.1.jar=release/modules/ext/logkit-1.0.1.jar
|
||||||
file.reference.mail-1.4.3.jar=release/modules/ext/mail-1.4.3.jar
|
file.reference.mail-1.4.3.jar=release/modules/ext/mail-1.4.3.jar
|
||||||
@ -82,6 +83,7 @@ javadoc.reference.guava-19.0.jar=release/modules/ext/guava-19.0-javadoc.jar
|
|||||||
javadoc.reference.jfxtras-common-8.0-r4.jar=release/modules/ext/jfxtras-common-8.0-r4-javadoc.jar
|
javadoc.reference.jfxtras-common-8.0-r4.jar=release/modules/ext/jfxtras-common-8.0-r4-javadoc.jar
|
||||||
javadoc.reference.jfxtras-controls-8.0-r4.jar=release/modules/ext/jfxtras-controls-8.0-r4-javadoc.jar
|
javadoc.reference.jfxtras-controls-8.0-r4.jar=release/modules/ext/jfxtras-controls-8.0-r4-javadoc.jar
|
||||||
javadoc.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4-javadoc.jar
|
javadoc.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4-javadoc.jar
|
||||||
|
javadoc.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1-javadoc.jar
|
||||||
nbm.needs.restart=true
|
nbm.needs.restart=true
|
||||||
source.reference.commons-csv-1.4.jar=release/modules/ext/commons-csv-1.4-sources.jar
|
source.reference.commons-csv-1.4.jar=release/modules/ext/commons-csv-1.4-sources.jar
|
||||||
source.reference.commons-io-2.5.jar=release/modules/ext/commons-io-2.5-sources.jar
|
source.reference.commons-io-2.5.jar=release/modules/ext/commons-io-2.5-sources.jar
|
||||||
@ -91,3 +93,4 @@ source.reference.guava-19.0.jar=release/modules/ext/guava-19.0-sources.jar
|
|||||||
source.reference.jfxtras-common-8.0-r4.jar=release/modules/ext/jfxtras-common-8.0-r4-sources.jar
|
source.reference.jfxtras-common-8.0-r4.jar=release/modules/ext/jfxtras-common-8.0-r4-sources.jar
|
||||||
source.reference.jfxtras-controls-8.0-r4.jar=release/modules/ext/jfxtras-controls-8.0-r4-sources.jar
|
source.reference.jfxtras-controls-8.0-r4.jar=release/modules/ext/jfxtras-controls-8.0-r4-sources.jar
|
||||||
source.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4-sources.jar
|
source.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4-sources.jar
|
||||||
|
source.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1-sources.jar
|
||||||
|
@ -37,6 +37,9 @@
|
|||||||
<package>com.apple.eawt</package>
|
<package>com.apple.eawt</package>
|
||||||
<package>com.apple.eawt.event</package>
|
<package>com.apple.eawt.event</package>
|
||||||
<package>com.apple.eio</package>
|
<package>com.apple.eio</package>
|
||||||
|
<package>com.github.lgooddatepicker.components</package>
|
||||||
|
<package>com.github.lgooddatepicker.optionalusertools</package>
|
||||||
|
<package>com.github.lgooddatepicker.zinternaltools</package>
|
||||||
<package>com.github.mustachejava</package>
|
<package>com.github.mustachejava</package>
|
||||||
<package>com.github.mustachejava.codes</package>
|
<package>com.github.mustachejava.codes</package>
|
||||||
<package>com.github.mustachejava.functions</package>
|
<package>com.github.mustachejava.functions</package>
|
||||||
@ -679,6 +682,10 @@
|
|||||||
<runtime-relative-path>ext/compiler-0.9.1.jar</runtime-relative-path>
|
<runtime-relative-path>ext/compiler-0.9.1.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/compiler-0.9.1.jar</binary-origin>
|
<binary-origin>release/modules/ext/compiler-0.9.1.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
|
<class-path-extension>
|
||||||
|
<runtime-relative-path>ext/LGoodDatePicker-10.3.1.jar</runtime-relative-path>
|
||||||
|
<binary-origin>release/modules/ext/LGoodDatePicker-10.3.1.jar</binary-origin>
|
||||||
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/imageio-iff-3.2.jar</runtime-relative-path>
|
<runtime-relative-path>ext/imageio-iff-3.2.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/imageio-iff-3.2.jar</binary-origin>
|
<binary-origin>release/modules/ext/imageio-iff-3.2.jar</binary-origin>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
Autopsy Forensic Browser
|
Autopsy Forensic Browser
|
||||||
|
|
||||||
Copyright 2016 Basis Technology Corp.
|
Copyright 2016-17 Basis Technology Corp.
|
||||||
Contact: carrier <at> sleuthkit <dot> org
|
Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -44,10 +44,14 @@ from org.sleuthkit.datamodel import BlackboardAttribute
|
|||||||
from org.sleuthkit.datamodel.BlackboardAttribute import ATTRIBUTE_TYPE
|
from org.sleuthkit.datamodel.BlackboardAttribute import ATTRIBUTE_TYPE
|
||||||
from org.sleuthkit.datamodel import Content
|
from org.sleuthkit.datamodel import Content
|
||||||
from org.sleuthkit.datamodel import TskCoreException
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
|
from org.sleuthkit.datamodel import Account
|
||||||
|
from org.sleuthkit.datamodel import Relationship
|
||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
import general
|
import general
|
||||||
|
|
||||||
|
deviceAccountInstance = None
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Locates a variety of different call log databases, parses them, and populates the blackboard.
|
Locates a variety of different call log databases, parses them, and populates the blackboard.
|
||||||
"""
|
"""
|
||||||
@ -82,6 +86,15 @@ class CallLogAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
|
|
||||||
def analyze(self, dataSource, fileManager, context):
|
def analyze(self, dataSource, fileManager, context):
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
# Create a 'Device' account using the data source device id
|
||||||
|
datasourceObjId = dataSource.getDataSource().getId()
|
||||||
|
ds = Case.getCurrentCase().getSleuthkitCase().getDataSource(datasourceObjId)
|
||||||
|
deviceID = ds.getDeviceId()
|
||||||
|
|
||||||
|
global deviceAccountInstance
|
||||||
|
deviceAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.DEVICE, deviceID, general.MODULE_NAME, dataSource)
|
||||||
|
|
||||||
absFiles = fileManager.findFiles(dataSource, "logs.db")
|
absFiles = fileManager.findFiles(dataSource, "logs.db")
|
||||||
absFiles.addAll(fileManager.findFiles(dataSource, "contacts.db"))
|
absFiles.addAll(fileManager.findFiles(dataSource, "contacts.db"))
|
||||||
absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db"))
|
absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db"))
|
||||||
@ -133,6 +146,13 @@ class CallLogAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))
|
attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))
|
||||||
|
|
||||||
artifact.addAttributes(attributes)
|
artifact.addAttributes(attributes)
|
||||||
|
|
||||||
|
# Create an account
|
||||||
|
calllogAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.PHONE, number, general.MODULE_NAME, abstractFile);
|
||||||
|
|
||||||
|
# create relationship between accounts
|
||||||
|
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(deviceAccountInstance, [calllogAccountInstance], artifact, Relationship.Type.CALL_LOG, date);
|
||||||
|
|
||||||
bbartifacts.append(artifact)
|
bbartifacts.append(artifact)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
Autopsy Forensic Browser
|
Autopsy Forensic Browser
|
||||||
|
|
||||||
Copyright 2016 Basis Technology Corp.
|
Copyright 2016-17 Basis Technology Corp.
|
||||||
Contact: carrier <at> sleuthkit <dot> org
|
Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -42,10 +42,14 @@ from org.sleuthkit.datamodel import BlackboardArtifact
|
|||||||
from org.sleuthkit.datamodel import BlackboardAttribute
|
from org.sleuthkit.datamodel import BlackboardAttribute
|
||||||
from org.sleuthkit.datamodel import Content
|
from org.sleuthkit.datamodel import Content
|
||||||
from org.sleuthkit.datamodel import TskCoreException
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
|
from org.sleuthkit.datamodel import Account
|
||||||
|
from org.sleuthkit.datamodel import Relationship
|
||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
import general
|
import general
|
||||||
|
|
||||||
|
deviceAccountInstance = None
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Locates a variety of different contacts databases, parses them, and populates the blackboard.
|
Locates a variety of different contacts databases, parses them, and populates the blackboard.
|
||||||
"""
|
"""
|
||||||
@ -56,6 +60,15 @@ class ContactAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
|
|
||||||
def analyze(self, dataSource, fileManager, context):
|
def analyze(self, dataSource, fileManager, context):
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
# Create a 'Device' account using the data source device id
|
||||||
|
datasourceObjId = dataSource.getDataSource().getId()
|
||||||
|
ds = Case.getCurrentCase().getSleuthkitCase().getDataSource(datasourceObjId)
|
||||||
|
deviceID = ds.getDeviceId()
|
||||||
|
|
||||||
|
global deviceAccountInstance
|
||||||
|
deviceAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance (Account.Type.DEVICE, deviceID, general.MODULE_NAME, dataSource)
|
||||||
|
|
||||||
absFiles = fileManager.findFiles(dataSource, "contacts.db")
|
absFiles = fileManager.findFiles(dataSource, "contacts.db")
|
||||||
absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db"))
|
absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db"))
|
||||||
if absFiles.isEmpty():
|
if absFiles.isEmpty():
|
||||||
@ -131,12 +144,21 @@ class ContactAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))
|
||||||
if mimetype == "vnd.android.cursor.item/phone_v2":
|
if mimetype == "vnd.android.cursor.item/phone_v2":
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, general.MODULE_NAME, data1))
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, general.MODULE_NAME, data1))
|
||||||
|
acctType = Account.Type.PHONE
|
||||||
else:
|
else:
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, general.MODULE_NAME, data1))
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, general.MODULE_NAME, data1))
|
||||||
|
acctType = Account.Type.EMAIL
|
||||||
|
|
||||||
|
artifact.addAttributes(attributes)
|
||||||
|
|
||||||
|
# Create an account instance
|
||||||
|
contactAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance (acctType, data1, general.MODULE_NAME, abstractFile);
|
||||||
|
|
||||||
|
# create relationship between accounts
|
||||||
|
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(deviceAccountInstance, [contactAccountInstance], artifact,Relationship.Type.CONTACT, 0);
|
||||||
|
|
||||||
oldName = name
|
oldName = name
|
||||||
|
|
||||||
artifact.addAttributes(attributes)
|
|
||||||
bbartifacts.append(artifact)
|
bbartifacts.append(artifact)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -42,10 +42,13 @@ from org.sleuthkit.datamodel import BlackboardArtifact
|
|||||||
from org.sleuthkit.datamodel import BlackboardAttribute
|
from org.sleuthkit.datamodel import BlackboardAttribute
|
||||||
from org.sleuthkit.datamodel import Content
|
from org.sleuthkit.datamodel import Content
|
||||||
from org.sleuthkit.datamodel import TskCoreException
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
|
from org.sleuthkit.datamodel import Account
|
||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
import general
|
import general
|
||||||
|
|
||||||
|
deviceAccountInstance = None
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Locates database for the Tango app and adds info to blackboard.
|
Locates database for the Tango app and adds info to blackboard.
|
||||||
"""
|
"""
|
||||||
@ -56,6 +59,14 @@ class TangoMessageAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
|
|
||||||
def analyze(self, dataSource, fileManager, context):
|
def analyze(self, dataSource, fileManager, context):
|
||||||
try:
|
try:
|
||||||
|
# Create a 'Device' account using the data source device id
|
||||||
|
datasourceObjId = dataSource.getDataSource().getId()
|
||||||
|
ds = Case.getCurrentCase().getSleuthkitCase().getDataSource(datasourceObjId)
|
||||||
|
deviceID = ds.getDeviceId()
|
||||||
|
|
||||||
|
global deviceAccountInstance
|
||||||
|
deviceAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.DEVICE, deviceID, general.MODULE_NAME, dataSource)
|
||||||
|
|
||||||
absFiles = fileManager.findFiles(dataSource, "tc.db")
|
absFiles = fileManager.findFiles(dataSource, "tc.db")
|
||||||
for abstractFile in absFiles:
|
for abstractFile in absFiles:
|
||||||
try:
|
try:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
Autopsy Forensic Browser
|
Autopsy Forensic Browser
|
||||||
|
|
||||||
Copyright 2016 Basis Technology Corp.
|
Copyright 2016-17 Basis Technology Corp.
|
||||||
Contact: carrier <at> sleuthkit <dot> org
|
Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -43,10 +43,14 @@ from org.sleuthkit.datamodel import BlackboardArtifact
|
|||||||
from org.sleuthkit.datamodel import BlackboardAttribute
|
from org.sleuthkit.datamodel import BlackboardAttribute
|
||||||
from org.sleuthkit.datamodel import Content
|
from org.sleuthkit.datamodel import Content
|
||||||
from org.sleuthkit.datamodel import TskCoreException
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
|
from org.sleuthkit.datamodel import Account
|
||||||
|
from org.sleuthkit.datamodel import Relationship
|
||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
import general
|
import general
|
||||||
|
|
||||||
|
deviceAccountInstance = None
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Finds database with SMS/MMS messages and adds them to blackboard.
|
Finds database with SMS/MMS messages and adds them to blackboard.
|
||||||
"""
|
"""
|
||||||
@ -57,6 +61,15 @@ class TextMessageAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
|
|
||||||
def analyze(self, dataSource, fileManager, context):
|
def analyze(self, dataSource, fileManager, context):
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
# Create a 'Device' account using the data source device id
|
||||||
|
datasourceObjId = dataSource.getDataSource().getId()
|
||||||
|
ds = Case.getCurrentCase().getSleuthkitCase().getDataSource(datasourceObjId)
|
||||||
|
deviceID = ds.getDeviceId()
|
||||||
|
|
||||||
|
global deviceAccountInstance
|
||||||
|
deviceAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.DEVICE, deviceID, general.MODULE_NAME, dataSource)
|
||||||
|
|
||||||
absFiles = fileManager.findFiles(dataSource, "mmssms.db")
|
absFiles = fileManager.findFiles(dataSource, "mmssms.db")
|
||||||
for abstractFile in absFiles:
|
for abstractFile in absFiles:
|
||||||
try:
|
try:
|
||||||
@ -108,6 +121,13 @@ class TextMessageAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "SMS Message"))
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "SMS Message"))
|
||||||
|
|
||||||
artifact.addAttributes(attributes)
|
artifact.addAttributes(attributes)
|
||||||
|
|
||||||
|
# Create an account
|
||||||
|
msgAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.PHONE, address, general.MODULE_NAME, abstractFile);
|
||||||
|
|
||||||
|
# create relationship between accounts
|
||||||
|
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(deviceAccountInstance, [msgAccountInstance], artifact,Relationship.Type.MESSAGE, date);
|
||||||
|
|
||||||
bbartifacts.append(artifact)
|
bbartifacts.append(artifact)
|
||||||
try:
|
try:
|
||||||
# index the artifact for keyword search
|
# index the artifact for keyword search
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
Autopsy Forensic Browser
|
Autopsy Forensic Browser
|
||||||
|
|
||||||
Copyright 2016 Basis Technology Corp.
|
Copyright 2016-17 Basis Technology Corp.
|
||||||
Contact: carrier <at> sleuthkit <dot> org
|
Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -39,10 +39,15 @@ from org.sleuthkit.datamodel import BlackboardArtifact
|
|||||||
from org.sleuthkit.datamodel import BlackboardAttribute
|
from org.sleuthkit.datamodel import BlackboardAttribute
|
||||||
from org.sleuthkit.datamodel import Content
|
from org.sleuthkit.datamodel import Content
|
||||||
from org.sleuthkit.datamodel import TskCoreException
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
|
from org.sleuthkit.datamodel import Account
|
||||||
|
from org.sleuthkit.datamodel import Relationship
|
||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
import general
|
import general
|
||||||
|
|
||||||
|
wwfAccountType = None
|
||||||
|
deviceAccountInstance = None
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Analyzes messages from Words With Friends
|
Analyzes messages from Words With Friends
|
||||||
"""
|
"""
|
||||||
@ -53,6 +58,18 @@ class WWFMessageAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
|
|
||||||
def analyze(self, dataSource, fileManager, context):
|
def analyze(self, dataSource, fileManager, context):
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
global wwfAccountType
|
||||||
|
wwfAccountType = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addAccountType("WWF", "Words with Friends")
|
||||||
|
|
||||||
|
# Create a 'Device' account using the data source device id
|
||||||
|
datasourceObjId = dataSource.getDataSource().getId()
|
||||||
|
ds = Case.getCurrentCase().getSleuthkitCase().getDataSource(datasourceObjId)
|
||||||
|
deviceID = ds.getDeviceId()
|
||||||
|
|
||||||
|
global deviceAccountInstance
|
||||||
|
deviceAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.DEVICE, deviceID, general.MODULE_NAME, dataSource)
|
||||||
|
|
||||||
absFiles = fileManager.findFiles(dataSource, "WordsFramework")
|
absFiles = fileManager.findFiles(dataSource, "WordsFramework")
|
||||||
for abstractFile in absFiles:
|
for abstractFile in absFiles:
|
||||||
try:
|
try:
|
||||||
@ -98,6 +115,13 @@ class WWFMessageAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Words With Friends Message"))
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Words With Friends Message"))
|
||||||
|
|
||||||
artifact.addAttributes(attributes)
|
artifact.addAttributes(attributes)
|
||||||
|
|
||||||
|
# Create an account
|
||||||
|
wwfAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(wwfAccountType, user_id, general.MODULE_NAME, abstractFile);
|
||||||
|
|
||||||
|
# create relationship between accounts
|
||||||
|
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(deviceAccountInstance, [wwfAccountInstance], artifact,Relationship.Type.MESSAGE, created_at);
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# index the artifact for keyword search
|
# index the artifact for keyword search
|
||||||
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||||
|
@ -173,7 +173,14 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
panel.updateControls(currentSource);
|
panel.updateControls(currentSource);
|
||||||
setPanel(content.getName(), sources);
|
|
||||||
|
String contentName = "";
|
||||||
|
if (content != null) {
|
||||||
|
contentName = content.getName();
|
||||||
|
}
|
||||||
|
setPanel(contentName, sources);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static private IndexedText getRawArtifactText(Lookup nodeLookup) throws TskCoreException {
|
static private IndexedText getRawArtifactText(Lookup nodeLookup) throws TskCoreException {
|
||||||
|
@ -222,9 +222,6 @@ class QueryResults {
|
|||||||
* Post an artifact for the hit to the blackboard.
|
* Post an artifact for the hit to the blackboard.
|
||||||
*/
|
*/
|
||||||
BlackboardArtifact artifact = query.postKeywordHitToBlackboard(content, keyword, hit, snippet, query.getKeywordList().getName());
|
BlackboardArtifact artifact = query.postKeywordHitToBlackboard(content, keyword, hit, snippet, query.getKeywordList().getName());
|
||||||
if (null == artifact) {
|
|
||||||
logger.log(Level.SEVERE, "Error posting keyword hit artifact for keyword {0} in {1} to the blackboard", new Object[]{keyword.toString(), content}); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send an ingest inbox message for the hit.
|
* Send an ingest inbox message for the hit.
|
||||||
|
@ -36,7 +36,9 @@ import org.apache.solr.client.solrj.response.QueryResponse;
|
|||||||
import org.apache.solr.common.SolrDocument;
|
import org.apache.solr.common.SolrDocument;
|
||||||
import org.apache.solr.common.SolrDocumentList;
|
import org.apache.solr.common.SolrDocumentList;
|
||||||
import org.apache.solr.common.params.CursorMarkParams;
|
import org.apache.solr.common.params.CursorMarkParams;
|
||||||
|
import org.openide.util.Exceptions;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import org.sleuthkit.autopsy.datamodel.CreditCards;
|
import org.sleuthkit.autopsy.datamodel.CreditCards;
|
||||||
@ -46,6 +48,7 @@ import static org.sleuthkit.autopsy.keywordsearch.TermsComponentQuery.CREDIT_CAR
|
|||||||
import static org.sleuthkit.autopsy.keywordsearch.TermsComponentQuery.KEYWORD_SEARCH_DOCUMENT_ID;
|
import static org.sleuthkit.autopsy.keywordsearch.TermsComponentQuery.KEYWORD_SEARCH_DOCUMENT_ID;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Account;
|
import org.sleuthkit.datamodel.Account;
|
||||||
|
import org.sleuthkit.datamodel.AccountFileInstance;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
@ -444,97 +447,30 @@ final class RegexQuery implements KeywordSearchQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create either a "plain vanilla" keyword hit artifact with keyword and
|
* Credit Card number hits are handled differently
|
||||||
* regex attributes, or a credit card account artifact with attributes
|
*/
|
||||||
* parsed from from the snippet for the hit and looked up based on the
|
if (originalKeyword.getArtifactAttributeType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
|
||||||
* parsed bank identifcation number.
|
createCCNAccount(content, foundKeyword, hit, snippet, listName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a "plain vanilla" keyword hit artifact with keyword and
|
||||||
|
* regex attributes
|
||||||
*/
|
*/
|
||||||
BlackboardArtifact newArtifact;
|
BlackboardArtifact newArtifact;
|
||||||
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
||||||
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
|
|
||||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm()));
|
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm()));
|
||||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, getQueryString()));
|
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, getQueryString()));
|
||||||
try {
|
|
||||||
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
try {
|
||||||
} catch (TskCoreException ex) {
|
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
||||||
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
|
} catch (TskCoreException ex) {
|
||||||
return null;
|
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
|
||||||
}
|
return null;
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Parse the credit card account attributes from the snippet for the
|
|
||||||
* hit.
|
|
||||||
*/
|
|
||||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE, MODULE_NAME, Account.Type.CREDIT_CARD.name()));
|
|
||||||
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
|
|
||||||
Matcher matcher = TermsComponentQuery.CREDIT_CARD_TRACK1_PATTERN.matcher(hit.getSnippet());
|
|
||||||
if (matcher.find()) {
|
|
||||||
parseTrack1Data(parsedTrackAttributeMap, matcher);
|
|
||||||
}
|
|
||||||
matcher = CREDIT_CARD_TRACK2_PATTERN.matcher(hit.getSnippet());
|
|
||||||
if (matcher.find()) {
|
|
||||||
parseTrack2Data(parsedTrackAttributeMap, matcher);
|
|
||||||
}
|
|
||||||
final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
|
|
||||||
if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) {
|
|
||||||
if (hit.isArtifactHit()) {
|
|
||||||
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS
|
|
||||||
} else {
|
|
||||||
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getSolrObjectId())); //NON-NLS
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
attributes.addAll(parsedTrackAttributeMap.values());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Look up the bank name, scheme, etc. attributes for the bank
|
|
||||||
* indentification number (BIN).
|
|
||||||
*/
|
|
||||||
final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8));
|
|
||||||
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
|
|
||||||
if (binInfo != null) {
|
|
||||||
binInfo.getScheme().ifPresent(scheme
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme)));
|
|
||||||
binInfo.getCardType().ifPresent(cardType
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType)));
|
|
||||||
binInfo.getBrand().ifPresent(brand
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand)));
|
|
||||||
binInfo.getBankName().ifPresent(bankName
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName)));
|
|
||||||
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber)));
|
|
||||||
binInfo.getBankURL().ifPresent(url
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url)));
|
|
||||||
binInfo.getCountry().ifPresent(country
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country)));
|
|
||||||
binInfo.getBankCity().ifPresent(city
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the hit is from unused or unallocated space, record the Solr
|
|
||||||
* document id to support showing just the chunk that contained the
|
|
||||||
* hit.
|
|
||||||
*/
|
|
||||||
if (content instanceof AbstractFile) {
|
|
||||||
AbstractFile file = (AbstractFile) content;
|
|
||||||
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|
|
||||||
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
|
|
||||||
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create an account artifact.
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT);
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Error adding artifact for account to blackboard", ex); //NON-NLS
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(listName)) {
|
if (StringUtils.isNotBlank(listName)) {
|
||||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
|
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
|
||||||
}
|
}
|
||||||
@ -557,6 +493,113 @@ final class RegexQuery implements KeywordSearchQuery {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createCCNAccount(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
|
||||||
|
|
||||||
|
final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName();
|
||||||
|
|
||||||
|
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Keyword hit is not a credit card number"); //NON-NLS
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Create a credit card account with attributes
|
||||||
|
* parsed from the snippet for the hit and looked up based on the
|
||||||
|
* parsed bank identifcation number.
|
||||||
|
*/
|
||||||
|
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
||||||
|
|
||||||
|
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
|
||||||
|
Matcher matcher = TermsComponentQuery.CREDIT_CARD_TRACK1_PATTERN.matcher(hit.getSnippet());
|
||||||
|
if (matcher.find()) {
|
||||||
|
parseTrack1Data(parsedTrackAttributeMap, matcher);
|
||||||
|
}
|
||||||
|
matcher = CREDIT_CARD_TRACK2_PATTERN.matcher(hit.getSnippet());
|
||||||
|
if (matcher.find()) {
|
||||||
|
parseTrack2Data(parsedTrackAttributeMap, matcher);
|
||||||
|
}
|
||||||
|
final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
|
||||||
|
if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) {
|
||||||
|
|
||||||
|
if (hit.isArtifactHit()) {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getContentID())); //NON-NLS
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s' ", foundKeyword.getSearchTerm(), hit.getSnippet())); //NON-NLS
|
||||||
|
LOGGER.log(Level.SEVERE, "There was a error getting contentID for keyword hit.", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
attributes.addAll(parsedTrackAttributeMap.values());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look up the bank name, scheme, etc. attributes for the bank
|
||||||
|
* indentification number (BIN).
|
||||||
|
*/
|
||||||
|
final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8));
|
||||||
|
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
|
||||||
|
if (binInfo != null) {
|
||||||
|
binInfo.getScheme().ifPresent(scheme
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme)));
|
||||||
|
binInfo.getCardType().ifPresent(cardType
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType)));
|
||||||
|
binInfo.getBrand().ifPresent(brand
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand)));
|
||||||
|
binInfo.getBankName().ifPresent(bankName
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName)));
|
||||||
|
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber)));
|
||||||
|
binInfo.getBankURL().ifPresent(url
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url)));
|
||||||
|
binInfo.getCountry().ifPresent(country
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country)));
|
||||||
|
binInfo.getBankCity().ifPresent(city
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the hit is from unused or unallocated space, record the Solr
|
||||||
|
* document id to support showing just the chunk that contained the
|
||||||
|
* hit.
|
||||||
|
*/
|
||||||
|
if (content instanceof AbstractFile) {
|
||||||
|
AbstractFile file = (AbstractFile) content;
|
||||||
|
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|
||||||
|
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
|
||||||
|
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(listName)) {
|
||||||
|
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
|
||||||
|
}
|
||||||
|
if (snippet != null) {
|
||||||
|
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW, MODULE_NAME, snippet));
|
||||||
|
}
|
||||||
|
|
||||||
|
hit.getArtifactID().ifPresent(artifactID
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactID))
|
||||||
|
);
|
||||||
|
|
||||||
|
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.REGEX.ordinal()));
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create an account instance.
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
AccountFileInstance ccAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.CREDIT_CARD, ccnAttribute.getValueString() , MODULE_NAME, content);
|
||||||
|
|
||||||
|
ccAccountInstance.addAttributes(attributes);
|
||||||
|
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error creating CCN account instance", ex); //NON-NLS
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Parses the track 2 data from the snippet for a credit card account number
|
* Parses the track 2 data from the snippet for a credit card account number
|
||||||
* hit and turns them into artifact attributes.
|
* hit and turns them into artifact attributes.
|
||||||
|
@ -32,11 +32,14 @@ import java.util.regex.Pattern;
|
|||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.solr.client.solrj.SolrQuery;
|
import org.apache.solr.client.solrj.SolrQuery;
|
||||||
import org.apache.solr.client.solrj.response.TermsResponse.Term;
|
import org.apache.solr.client.solrj.response.TermsResponse.Term;
|
||||||
|
import org.openide.util.Exceptions;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.Version;
|
import org.sleuthkit.autopsy.coreutils.Version;
|
||||||
import org.sleuthkit.autopsy.datamodel.CreditCards;
|
import org.sleuthkit.autopsy.datamodel.CreditCards;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Account;
|
import org.sleuthkit.datamodel.Account;
|
||||||
|
import org.sleuthkit.datamodel.AccountFileInstance;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
@ -342,98 +345,31 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public BlackboardArtifact postKeywordHitToBlackboard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
|
public BlackboardArtifact postKeywordHitToBlackboard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create either a "plain vanilla" keyword hit artifact with keyword and
|
* CCN hits are handled specially
|
||||||
* regex attributes, or a credit card account artifact with attributes
|
*/
|
||||||
* parsed from from the snippet for the hit and looked up based on the
|
if (originalKeyword.getArtifactAttributeType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
|
||||||
* parsed bank identifcation number.
|
createCCNAccount(content, hit, snippet, listName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a "plain vanilla" keyword hit artifact with keyword and regex
|
||||||
|
* attributes,
|
||||||
*/
|
*/
|
||||||
BlackboardArtifact newArtifact;
|
BlackboardArtifact newArtifact;
|
||||||
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
||||||
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
|
|
||||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm()));
|
|
||||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, originalKeyword.getSearchTerm()));
|
|
||||||
|
|
||||||
try {
|
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm()));
|
||||||
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, originalKeyword.getSearchTerm()));
|
||||||
|
|
||||||
} catch (TskCoreException ex) {
|
try {
|
||||||
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
|
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Parse the credit card account attributes from the snippet for the
|
|
||||||
* hit.
|
|
||||||
*/
|
|
||||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE, MODULE_NAME, Account.Type.CREDIT_CARD.name()));
|
|
||||||
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
|
|
||||||
Matcher matcher = CREDIT_CARD_TRACK1_PATTERN.matcher(hit.getSnippet());
|
|
||||||
if (matcher.find()) {
|
|
||||||
parseTrack1Data(parsedTrackAttributeMap, matcher);
|
|
||||||
}
|
|
||||||
matcher = CREDIT_CARD_TRACK2_PATTERN.matcher(hit.getSnippet());
|
|
||||||
if (matcher.find()) {
|
|
||||||
parseTrack2Data(parsedTrackAttributeMap, matcher);
|
|
||||||
}
|
|
||||||
final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
|
|
||||||
if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) {
|
|
||||||
if (hit.isArtifactHit()) {
|
|
||||||
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", searchTerm, hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS
|
|
||||||
} else {
|
|
||||||
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", searchTerm, hit.getSnippet(), hit.getSolrObjectId())); //NON-NLS
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
attributes.addAll(parsedTrackAttributeMap.values());
|
|
||||||
|
|
||||||
/*
|
} catch (TskCoreException ex) {
|
||||||
* Look up the bank name, scheme, etc. attributes for the bank
|
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
|
||||||
* indentification number (BIN).
|
return null;
|
||||||
*/
|
|
||||||
final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8));
|
|
||||||
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
|
|
||||||
if (binInfo != null) {
|
|
||||||
binInfo.getScheme().ifPresent(scheme
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme)));
|
|
||||||
binInfo.getCardType().ifPresent(cardType
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType)));
|
|
||||||
binInfo.getBrand().ifPresent(brand
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand)));
|
|
||||||
binInfo.getBankName().ifPresent(bankName
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName)));
|
|
||||||
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber)));
|
|
||||||
binInfo.getBankURL().ifPresent(url
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url)));
|
|
||||||
binInfo.getCountry().ifPresent(country
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country)));
|
|
||||||
binInfo.getBankCity().ifPresent(city
|
|
||||||
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the hit is from unused or unallocated space, record the Solr
|
|
||||||
* document id to support showing just the chunk that contained the
|
|
||||||
* hit.
|
|
||||||
*/
|
|
||||||
if (content instanceof AbstractFile) {
|
|
||||||
AbstractFile file = (AbstractFile) content;
|
|
||||||
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|
|
||||||
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
|
|
||||||
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create an account artifact.
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT);
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Error adding artifact for account to blackboard", ex); //NON-NLS
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(listName)) {
|
if (StringUtils.isNotBlank(listName)) {
|
||||||
@ -459,6 +395,114 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createCCNAccount(Content content, KeywordHit hit, String snippet, String listName) {
|
||||||
|
|
||||||
|
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Keyword hit is not a credit card number"); //NON-NLS
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a credit card account with attributes parsed from from the
|
||||||
|
* snippet for the hit and looked up based on the parsed bank
|
||||||
|
* identifcation number.
|
||||||
|
*/
|
||||||
|
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
||||||
|
|
||||||
|
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
|
||||||
|
Matcher matcher = CREDIT_CARD_TRACK1_PATTERN.matcher(hit.getSnippet());
|
||||||
|
if (matcher.find()) {
|
||||||
|
parseTrack1Data(parsedTrackAttributeMap, matcher);
|
||||||
|
}
|
||||||
|
matcher = CREDIT_CARD_TRACK2_PATTERN.matcher(hit.getSnippet());
|
||||||
|
if (matcher.find()) {
|
||||||
|
parseTrack2Data(parsedTrackAttributeMap, matcher);
|
||||||
|
}
|
||||||
|
final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
|
||||||
|
if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) {
|
||||||
|
if (hit.isArtifactHit()) {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", searchTerm, hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS
|
||||||
|
} else {
|
||||||
|
long contentId = 0;
|
||||||
|
try {
|
||||||
|
contentId = hit.getContentID();
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Failed to content id from keyword hit: term = %s, snippet = '%s'", searchTerm, hit.getSnippet()), ex); //NON-NLS
|
||||||
|
}
|
||||||
|
if (contentId > 0) {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", searchTerm, hit.getSnippet(), contentId)); //NON-NLS
|
||||||
|
} else {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s'", searchTerm, hit.getSnippet())); //NON-NLS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
attributes.addAll(parsedTrackAttributeMap.values());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look up the bank name, scheme, etc. attributes for the bank
|
||||||
|
* indentification number (BIN).
|
||||||
|
*/
|
||||||
|
final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8));
|
||||||
|
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
|
||||||
|
if (binInfo != null) {
|
||||||
|
binInfo.getScheme().ifPresent(scheme
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme)));
|
||||||
|
binInfo.getCardType().ifPresent(cardType
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType)));
|
||||||
|
binInfo.getBrand().ifPresent(brand
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand)));
|
||||||
|
binInfo.getBankName().ifPresent(bankName
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName)));
|
||||||
|
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber)));
|
||||||
|
binInfo.getBankURL().ifPresent(url
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url)));
|
||||||
|
binInfo.getCountry().ifPresent(country
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country)));
|
||||||
|
binInfo.getBankCity().ifPresent(city
|
||||||
|
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the hit is from unused or unallocated space, record the Solr
|
||||||
|
* document id to support showing just the chunk that contained the hit.
|
||||||
|
*/
|
||||||
|
if (content instanceof AbstractFile) {
|
||||||
|
AbstractFile file = (AbstractFile) content;
|
||||||
|
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|
||||||
|
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
|
||||||
|
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(listName)) {
|
||||||
|
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
|
||||||
|
}
|
||||||
|
if (snippet != null) {
|
||||||
|
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW, MODULE_NAME, snippet));
|
||||||
|
}
|
||||||
|
|
||||||
|
hit.getArtifactID().ifPresent(
|
||||||
|
artifactID -> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactID))
|
||||||
|
);
|
||||||
|
|
||||||
|
// TermsComponentQuery is now being used exclusively for substring searches.
|
||||||
|
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.SUBSTRING.ordinal()));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create an account.
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
AccountFileInstance ccAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.CREDIT_CARD, ccnAttribute.getValueString(), MODULE_NAME, content);
|
||||||
|
ccAccountInstance.addAttributes(attributes);
|
||||||
|
//newArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(ccAccountInstance.getArtifactId());
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error creating CCN account instance", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the track 2 data from the snippet for a credit card account number
|
* Parses the track 2 data from the snippet for a credit card account number
|
||||||
* hit and turns them into artifact attributes.
|
* hit and turns them into artifact attributes.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#Updated by build script
|
#Updated by build script
|
||||||
#Wed, 08 Nov 2017 17:45:11 -0500
|
#Wed, 06 Dec 2017 09:53:33 -0500
|
||||||
LBL_splash_window_title=Starting Autopsy
|
LBL_splash_window_title=Starting Autopsy
|
||||||
SPLASH_HEIGHT=314
|
SPLASH_HEIGHT=314
|
||||||
SPLASH_WIDTH=538
|
SPLASH_WIDTH=538
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#Updated by build script
|
#Updated by build script
|
||||||
#Wed, 08 Nov 2017 17:45:11 -0500
|
#Wed, 06 Dec 2017 09:53:33 -0500
|
||||||
CTL_MainWindow_Title=Autopsy 4.5.0
|
CTL_MainWindow_Title=Autopsy 4.5.0
|
||||||
CTL_MainWindow_Title_No_Project=Autopsy 4.5.0
|
CTL_MainWindow_Title_No_Project=Autopsy 4.5.0
|
||||||
|
@ -21,8 +21,13 @@ package org.sleuthkit.autopsy.thunderbirdparser;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
@ -40,12 +45,16 @@ import org.sleuthkit.autopsy.ingest.IngestServices;
|
|||||||
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.Account;
|
||||||
|
import org.sleuthkit.datamodel.AccountFileInstance;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||||
import org.sleuthkit.datamodel.DerivedFile;
|
import org.sleuthkit.datamodel.DerivedFile;
|
||||||
|
import org.sleuthkit.datamodel.Relationship;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
import org.sleuthkit.datamodel.TskDataException;
|
||||||
import org.sleuthkit.datamodel.TskException;
|
import org.sleuthkit.datamodel.TskException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -354,6 +363,24 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds and returns a set of unique email addresses found in the input string
|
||||||
|
*
|
||||||
|
* @param input - input string, like the To/CC line from an email header
|
||||||
|
*
|
||||||
|
* @param Set<String>: set of email addresses found in the input string
|
||||||
|
*/
|
||||||
|
private Set<String> findEmailAddresess(String input) {
|
||||||
|
Pattern p = Pattern.compile("\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b",
|
||||||
|
Pattern.CASE_INSENSITIVE);
|
||||||
|
Matcher m = p.matcher(input);
|
||||||
|
Set<String> emailAddresses = new HashSet<String>();
|
||||||
|
while (m.find()) {
|
||||||
|
emailAddresses.add( m.group());
|
||||||
|
}
|
||||||
|
return emailAddresses;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a blackboard artifact for the given email message.
|
* Add a blackboard artifact for the given email message.
|
||||||
*
|
*
|
||||||
@ -377,55 +404,71 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
long id = email.getId();
|
long id = email.getId();
|
||||||
String localPath = email.getLocalPath();
|
String localPath = email.getLocalPath();
|
||||||
|
|
||||||
if (headers.isEmpty() == false) {
|
List<String> senderAddressList = new ArrayList<>();
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HEADERS, EmailParserModuleFactory.getModuleName(), headers));
|
String senderAddress;
|
||||||
|
senderAddressList.addAll(findEmailAddresess(from));
|
||||||
|
|
||||||
|
AccountFileInstance senderAccountInstance = null;
|
||||||
|
if (senderAddressList.size() == 1) {
|
||||||
|
senderAddress = senderAddressList.get(0);
|
||||||
|
try {
|
||||||
|
senderAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, senderAddress, EmailParserModuleFactory.getModuleName(), abstractFile);
|
||||||
|
}
|
||||||
|
catch(TskCoreException ex) {
|
||||||
|
logger.log(Level.WARNING, "Failed to create account for email address " + senderAddress, ex); //NON-NLS
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (from.isEmpty() == false) {
|
else {
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_FROM, EmailParserModuleFactory.getModuleName(), from));
|
logger.log(Level.WARNING, "Failed to find sender address, from = "+ from); //NON-NLS
|
||||||
}
|
|
||||||
if (to.isEmpty() == false) {
|
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_TO, EmailParserModuleFactory.getModuleName(), to));
|
|
||||||
}
|
|
||||||
if (subject.isEmpty() == false) {
|
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SUBJECT, EmailParserModuleFactory.getModuleName(), subject));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dateL > 0) {
|
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_RCVD, EmailParserModuleFactory.getModuleName(), dateL));
|
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_SENT, EmailParserModuleFactory.getModuleName(), dateL));
|
|
||||||
}
|
|
||||||
if (body.isEmpty() == false) {
|
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN, EmailParserModuleFactory.getModuleName(), body));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_MSG_ID, EmailParserModuleFactory.getModuleName(), ((id < 0L) ? NbBundle
|
List<String> recipientAddresses = new ArrayList<>();
|
||||||
.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(id))));
|
recipientAddresses.addAll(findEmailAddresess(to));
|
||||||
|
recipientAddresses.addAll(findEmailAddresess(cc));
|
||||||
|
recipientAddresses.addAll(findEmailAddresess(bcc));
|
||||||
|
|
||||||
if (localPath.isEmpty() == false) {
|
List<AccountFileInstance> recipientAccountInstances = new ArrayList<>();
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, EmailParserModuleFactory.getModuleName(), localPath));
|
recipientAddresses.forEach((addr) -> {
|
||||||
} else {
|
try {
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, EmailParserModuleFactory.getModuleName(), "/foo/bar")); //NON-NLS
|
AccountFileInstance recipientAccountInstance =
|
||||||
}
|
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, addr,
|
||||||
|
EmailParserModuleFactory.getModuleName(), abstractFile);
|
||||||
|
recipientAccountInstances.add(recipientAccountInstance);
|
||||||
|
}
|
||||||
|
catch(TskCoreException ex) {
|
||||||
|
logger.log(Level.WARNING, "Failed to create account for email address " + addr, ex); //NON-NLS
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
addEmailAttribute(headers, ATTRIBUTE_TYPE.TSK_HEADERS, bbattributes);
|
||||||
|
addEmailAttribute(from, ATTRIBUTE_TYPE.TSK_EMAIL_FROM, bbattributes);
|
||||||
|
addEmailAttribute(to, ATTRIBUTE_TYPE.TSK_EMAIL_TO, bbattributes);
|
||||||
|
addEmailAttribute(subject, ATTRIBUTE_TYPE.TSK_SUBJECT, bbattributes);
|
||||||
|
|
||||||
if (cc.isEmpty() == false) {
|
addEmailAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_RCVD, bbattributes);
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CC, EmailParserModuleFactory.getModuleName(), cc));
|
addEmailAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_SENT, bbattributes);
|
||||||
}
|
|
||||||
if (bcc.isEmpty() == false) {
|
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_BCC, EmailParserModuleFactory.getModuleName(), bcc));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bodyHTML.isEmpty() == false) {
|
addEmailAttribute(body, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN, bbattributes);
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, EmailParserModuleFactory.getModuleName(), bodyHTML));
|
|
||||||
}
|
addEmailAttribute(((id < 0L) ? NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(id)),
|
||||||
if (rtf.isEmpty() == false) {
|
ATTRIBUTE_TYPE.TSK_MSG_ID, bbattributes);
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, EmailParserModuleFactory.getModuleName(), rtf));
|
|
||||||
}
|
addEmailAttribute(((localPath.isEmpty() == false) ? localPath : "/foo/bar"),
|
||||||
|
ATTRIBUTE_TYPE.TSK_PATH, bbattributes);
|
||||||
|
|
||||||
|
addEmailAttribute(cc, ATTRIBUTE_TYPE.TSK_EMAIL_CC, bbattributes);
|
||||||
|
addEmailAttribute(bodyHTML, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, bbattributes);
|
||||||
|
addEmailAttribute(rtf, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, bbattributes);
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
|
bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
|
||||||
bbart.addAttributes(bbattributes);
|
bbart.addAttributes(bbattributes);
|
||||||
|
|
||||||
|
// Add account relationships
|
||||||
|
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance, recipientAccountInstances, bbart,Relationship.Type.MESSAGE, dateL);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// index the artifact for keyword search
|
// index the artifact for keyword search
|
||||||
blackboard.indexArtifact(bbart);
|
blackboard.indexArtifact(bbart);
|
||||||
@ -433,13 +476,24 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bbart.getArtifactID(), ex); //NON-NLS
|
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bbart.getArtifactID(), ex); //NON-NLS
|
||||||
MessageNotifyUtil.Notify.error(Bundle.ThunderbirdMboxFileIngestModule_addArtifact_indexError_message(), bbart.getDisplayName());
|
MessageNotifyUtil.Notify.error(Bundle.ThunderbirdMboxFileIngestModule_addArtifact_indexError_message(), bbart.getDisplayName());
|
||||||
}
|
}
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException | TskDataException ex) {
|
||||||
logger.log(Level.WARNING, null, ex);
|
logger.log(Level.WARNING, null, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bbart;
|
return bbart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addEmailAttribute(String stringVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
|
||||||
|
if (stringVal.isEmpty() == false) {
|
||||||
|
bbattributes.add(new BlackboardAttribute(attrType, EmailParserModuleFactory.getModuleName(), stringVal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void addEmailAttribute(long longVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
|
||||||
|
if (longVal > 0) {
|
||||||
|
bbattributes.add(new BlackboardAttribute(attrType, EmailParserModuleFactory.getModuleName(), longVal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void postErrorMessage(String subj, String details) {
|
void postErrorMessage(String subj, String details) {
|
||||||
IngestMessage ingestMessage = IngestMessage.createErrorMessage(EmailParserModuleFactory.getModuleVersion(), subj, details);
|
IngestMessage ingestMessage = IngestMessage.createErrorMessage(EmailParserModuleFactory.getModuleVersion(), subj, details);
|
||||||
services.postMessage(ingestMessage);
|
services.postMessage(ingestMessage);
|
||||||
@ -451,5 +505,6 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void shutDown() {
|
public void shutDown() {
|
||||||
|
// nothing to shut down
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|