Merge branch 'develop' of github.com:sleuthkit/autopsy into 5014_known_slack_filtering

This commit is contained in:
esaunders 2019-05-15 14:43:18 -04:00
commit 698b464bc4
82 changed files with 5260 additions and 1087 deletions

View File

@ -110,11 +110,11 @@
<target name="getTestDataFiles">
<mkdir dir="${basedir}/test/qa-functional/data"/>
<get src="https://drive.google.com/uc?id=1FkinvA7EFqP4nOSOyTAOli5KefM67ufA" dest="${test-input}/EmbeddedIM_img1_v2.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1JACMDyH4y54ypGzFWl82ZzMQf3qbrioP" dest="${test-input}/BitlockerDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=17sGybvmBGsWWJYo1IWKmO04oG9hKpPi3" dest="${test-input}/SqlCipherDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1zPlIn1xmOeC1VYKmV3fJHl5qE6E_M7K-" dest="${test-input}/BitlockerDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1brQqmX8MJnBPUFEbsdUvZ1X81PmQNVCY" dest="${test-input}/SqlCipherDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=0BxdBkzm5VKGNT0dGY0dqcHVsU3M" dest="${test-input}/IngestFilters_img1_v1.img" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1bghoSm7z7nhmGIxlllyY1MMlbLntxm7n" dest="${test-input}/IngestFilters_local1_v1.zip" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1BrSiUQ1fzxFS9vIaK4mYKX6qIVp9kRWT" dest="${test-input}/PasswordDetection_img1_v1.img" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1Ovyv_xVty8xMYgsc3C45pvphfhbdKg1x" dest="${test-input}/PasswordDetection_img1_v1.img" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1HD8s4rculgHV1qZT5g80Kg7j4m1qccrN" dest="${test-input}/VeracryptDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1mr9waEDG5H8GBBn_yXwMUQ6senwC1goL" dest="${test-input}/CommonFiles_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1-vmbmAAb2HBLbf58GpAA97ozGUFiYHbN" dest="${test-input}/CommonFiles_img2_v1.vhd" skipexisting="true"/>

View File

@ -181,7 +181,7 @@ final class AddImageWizardSelectDspVisual extends JPanel {
/**
* Create a list of the DataSourceProcessors which should exist as options
* on this panel. The default Autopsy DataSourceProcessors will appear at
* the beggining of the list in the same order.
* the beginning of the list in the same order.
*
* @return dspList a list of DataSourceProcessors which can be chose in this
* panel
@ -200,6 +200,7 @@ final class AddImageWizardSelectDspVisual extends JPanel {
dspList.add(LocalDiskDSProcessor.getType());
dspList.add(LocalFilesDSProcessor.getType());
dspList.add(RawDSProcessor.getType());
dspList.add(LogicalImagerDSProcessor.getType());
// now add any addtional DSPs that haven't already been added
for (String dspType : datasourceProcessorsMap.keySet()) {
if (!dspList.contains(dspType)) {

View File

@ -238,6 +238,13 @@ OpenMultiUserCasePanel.cancelButton.text=Cancel
OpenMultiUserCasePanel.openSingleUserCaseButton.text=Open Single-User Case...
OpenMultiUserCasePanel.openSelectedCaseButton.text=Open Selected Case
OpenMultiUserCasePanel.searchLabel.text=Select any case and start typing to search by case name
LogicalImagerPanel.jLabel1.text=Insert external drive
LogicalImagerPanel.scanButton.text=Scan
LogicalImagerPanel.jLabel6.text=Or, pick a Logical Imager folder
LogicalImagerPanel.browseButton.text=Browse
LogicalImagerPanel.topLabel.text=Import Autopsy Imager Results
LogicalImagerPanel.selectDriveLabel.text=Select Drive
LogicalImagerPanel.messageLabel.text=Error/Status message
UnpackagePortableCaseDialog.desc2Label.text=Portable Case Report Module.
UnpackagePortableCaseDialog.desc1Label.text=Unpackage a portable case so it can be opened in Autopsy. Portable cases are created through the
UnpackagePortableCaseDialog.exitButton.text=Exit
@ -252,4 +259,4 @@ UnpackagePortableCaseProgressDialog.cancelButton.text=Cancel
UnpackagePortableCaseProgressDialog.okButton.text=OK
UnpackagePortableCaseProgressDialog.resultLabel.text=resultLabel
UnpackagePortableCaseDialog.extractLabel.text=Folder to extract to:
UnpackagePortableCaseDialog.caseLabel.text=Portable Case:
UnpackagePortableCaseDialog.caseLabel.text=Portable Case:

View File

@ -168,6 +168,18 @@ LogicalEvidenceFilePanel.pathValidation.getOpenCase.Error=Warning: Exception whi
LogicalEvidenceFilePanel.validatePanel.nonL01Error.text=Only files with the .l01 file extension are supported here.
LogicalFilesDspPanel.subTypeComboBox.l01FileOption.text=Logical evidence file (L01)
LogicalFilesDspPanel.subTypeComboBox.localFilesOption.text=Local files and folders
LogicalImagerDSProcessor.dataSourceType=Autopsy Imager
LogicalImagerPanel.imageTable.columnModel.title0=Hostname
LogicalImagerPanel.imageTable.columnModel.title1=Extracted Date
LogicalImagerPanel.messageLabel.clickScanOrBrowse=Click SCAN or BROWSE button to find images
LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain {1}
LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS
LogicalImagerPanel.messageLabel.driveHasNoImages=Drive has no images
LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found
LogicalImagerPanel.messageLabel.noImageSelected=No image selected
LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for sparse_image.vhd ...
LogicalImagerPanel.messageLabel.selectedImage=Selected folder
LogicalImagerPanel.selectAcquisitionFromDriveLabel.text=Select acquisition from Drive
Menu/Case/OpenRecentCase=Open Recent Case
CTL_CaseDeleteAction=Delete Case
OpenIDE-Module-Name=Case
@ -440,6 +452,13 @@ OpenMultiUserCasePanel.cancelButton.text=Cancel
OpenMultiUserCasePanel.openSingleUserCaseButton.text=Open Single-User Case...
OpenMultiUserCasePanel.openSelectedCaseButton.text=Open Selected Case
OpenMultiUserCasePanel.searchLabel.text=Select any case and start typing to search by case name
LogicalImagerPanel.jLabel1.text=Insert external drive
LogicalImagerPanel.scanButton.text=Scan
LogicalImagerPanel.jLabel6.text=Or, pick a Logical Imager folder
LogicalImagerPanel.browseButton.text=Browse
LogicalImagerPanel.topLabel.text=Import Autopsy Imager Results
LogicalImagerPanel.selectDriveLabel.text=Select Drive
LogicalImagerPanel.messageLabel.text=Error/Status message
UnpackagePortableCaseDialog.desc2Label.text=Portable Case Report Module.
UnpackagePortableCaseDialog.desc1Label.text=Unpackage a portable case so it can be opened in Autopsy. Portable cases are created through the
UnpackagePortableCaseDialog.exitButton.text=Exit

View File

@ -116,7 +116,7 @@
<Component id="hashValuesNoteLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="51" max="32767" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>

View File

@ -0,0 +1,165 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule;
import java.nio.file.Path;
import javax.swing.JPanel;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.openide.util.lookup.ServiceProviders;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
/**
* A Logical Imager data source processor that implements the DataSourceProcessor service
* provider interface to allow integration with the add data source wizard. It
* also provides a run method overload to allow it to be used independently of
* the wizard.
*/
@ServiceProviders(value={
@ServiceProvider(service=DataSourceProcessor.class)}
)
public class LogicalImagerDSProcessor implements DataSourceProcessor {
private final LogicalImagerPanel configPanel;
/*
* Constructs a Logical Imager data source processor that implements the
* DataSourceProcessor service provider interface to allow integration with
* the add data source wizard. It also provides a run method overload to
* allow it to be used independently of the wizard.
*/
public LogicalImagerDSProcessor() {
configPanel = LogicalImagerPanel.createInstance(LogicalImagerDSProcessor.class.getName());
}
/**
* Gets a string that describes the type of data sources this processor is
* able to add to the case database. The string is suitable for display in a
* type selection UI component (e.g., a combo box).
*
* @return A data source type display string for this data source processor.
*/
@Messages({"LogicalImagerDSProcessor.dataSourceType=Autopsy Imager"})
public static String getType() {
return Bundle.LogicalImagerDSProcessor_dataSourceType();
}
/**
* Gets a string that describes the type of data sources this processor is
* able to add to the case database. The string is suitable for display in a
* type selection UI component (e.g., a combo box).
*
* @return A data source type display string for this data source processor.
*/
@Override
public String getDataSourceType() {
return Bundle.LogicalImagerDSProcessor_dataSourceType();
}
/**
* Gets the panel that allows a user to select a data source and do any
* configuration required by the data source. The panel is less than 544
* pixels wide and less than 173 pixels high.
*
* @return A selection and configuration panel for this data source
* processor.
*/
@Override
public JPanel getPanel() {
configPanel.reset();
return configPanel;
}
/**
* Indicates whether the settings in the selection and configuration panel
* are valid and complete.
*
* @return True if the settings are valid and complete and the processor is
* ready to have its run method called, false otherwise.
*/
@Override
public boolean isPanelValid() {
return configPanel.validatePanel();
}
/**
* Adds a data source to the case database using a background task in a
* separate thread and the settings provided by the selection and
* configuration panel. Returns as soon as the background task is started.
* The background task uses a callback object to signal task completion and
* return results.
*
* This method should not be called unless isPanelValid returns true.
*
* @param progressMonitor Progress monitor that will be used by the
* background task to report progress.
* @param callback Callback that will be used by the background task
* to return results.
*/
@Override
public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
configPanel.storeSettings();
Path dirPath = configPanel.getImageDirPath();
System.out.println("Choosen directory " + dirPath.toString());
// TODO: process the data source in 5011
}
/**
* Adds a "Logical Imager" data source to the case database using a background task in
* a separate thread and the given settings instead of those provided by the
* selection and configuration panel. Returns as soon as the background task
* is started and uses the callback object to signal task completion and
* return results.
*
* @param deviceId An ASCII-printable identifier for the device
* associated with the data source that is
* intended to be unique across multiple cases
* (e.g., a UUID).
* @param imageFilePath Path to the image file.
* @param timeZone The time zone to use when processing dates
* and times for the image, obtained from
* java.util.TimeZone.getID.
* @param chunkSize The maximum size of each chunk of the raw
* data source as it is divided up into virtual
* unallocated space files.
* @param progressMonitor Progress monitor for reporting progress
* during processing.
* @param callback Callback to call when processing is done.
*/
private void run(String deviceId, String imagePath, int sectorSize, String timeZone, boolean ignoreFatOrphanFiles, String md5, String sha1, String sha256, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
AddImageTask addImageTask = new AddImageTask(deviceId, imagePath, sectorSize, timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, null, progressMonitor, callback);
new Thread(addImageTask).start();
}
@Override
public void cancel() {
}
/**
* Resets the selection and configuration panel for this data source
* processor.
*/
@Override
public void reset() {
configPanel.reset();
}
}

View File

@ -0,0 +1,233 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 65]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[403, 65]"/>
</Property>
</Properties>
<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" attributes="0">
<EmptySpace min="-2" pref="238" max="-2" attributes="0"/>
<Component id="topLabel" min="-2" pref="163" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="28" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="messageLabel" alignment="1" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="jSeparator1" alignment="0" max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="selectDriveLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="289" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<Component id="scanButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="126" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="36" max="-2" attributes="0"/>
<Component id="browseButton" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="driveListScrollPane" min="-2" pref="211" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="28" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="selectAcquisitionFromDriveLabel" min="-2" pref="305" max="-2" attributes="0"/>
<Component id="imageScrollPane" min="-2" pref="346" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="346" max="-2" attributes="0"/>
<Component id="jLabel6" min="-2" pref="154" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="144" max="-2" attributes="0"/>
<Component id="jLabel1" min="-2" pref="116" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace pref="48" max="32767" 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="topLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel6" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="scanButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jSeparator1" min="-2" pref="4" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="selectDriveLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="selectAcquisitionFromDriveLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="imageScrollPane" pref="0" max="32767" attributes="0"/>
<Component id="driveListScrollPane" pref="194" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
<Component id="messageLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="154" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="topLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.topLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="scanButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.scanButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="scanButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="messageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.messageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="selectDriveLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.selectDriveLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JScrollPane" name="driveListScrollPane">
<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.JList" name="driveList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
<StringArray count="0"/>
</Property>
<Property name="selectionMode" type="int" value="0"/>
</Properties>
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="driveListMouseClicked"/>
<EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="driveListKeyReleased"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="selectAcquisitionFromDriveLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.selectAcquisitionFromDriveLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel6">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.jLabel6.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="browseButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LogicalImagerPanel.browseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="imageScrollPane">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[346, 402]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="imageTable">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.editors2.TableModelEditor">
<Table columnCount="0" rowCount="0"/>
</Property>
<Property name="autoResizeMode" type="int" value="0"/>
<Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor">
<TableColumnModel selectionModel="1"/>
</Property>
<Property name="showHorizontalLines" type="boolean" value="false"/>
<Property name="showVerticalLines" type="boolean" value="false"/>
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
<TableHeader reorderingAllowed="false" resizingAllowed="true"/>
</Property>
<Property name="updateSelectionOnSort" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="imageTableMouseClicked"/>
<EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="imageTableKeyReleased"/>
</Events>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JSeparator" name="jSeparator1">
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,583 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileStore;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileSystemView;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
/**
* Panel for adding an logical image file from drive letters. Allows the user
* to select a file.
*/
@Messages({
"LogicalImagerPanel.messageLabel.selectedImage=Selected folder",
"LogicalImagerPanel.messageLabel.noImageSelected=No image selected",
"LogicalImagerPanel.messageLabel.driveHasNoImages=Drive has no images",
"LogicalImagerPanel.selectAcquisitionFromDriveLabel.text=Select acquisition from Drive",
})
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public class LogicalImagerPanel extends JPanel implements DocumentListener {
private static final long serialVersionUID = 1L;
private static final String SPARSE_IMAGE_VHD = "sparse_image.vhd"; //NON-NLS
private static final String SELECTED_IMAGE = Bundle.LogicalImagerPanel_messageLabel_selectedImage();
private static final String NO_IMAGE_SELECTED = Bundle.LogicalImagerPanel_messageLabel_noImageSelected();
private static final String DRIVE_HAS_NO_IMAGES = Bundle.LogicalImagerPanel_messageLabel_driveHasNoImages();
private static final String[] EMPTY_LIST_DATA = {};
private final JFileChooser fileChooser = new JFileChooser();
private final Pattern regex = Pattern.compile("Logical_Imager_(.+)_(\\d{4})(\\d{2})(\\d{2})_(\\d{2})_(\\d{2})_(\\d{2})");
private final String contextName;
private Path choosenImageDirPath;
private TableModel imageTableModel;
/**
* Creates new form LogicalImagerPanel
*
* @param context A string context name used to read/store last
* used settings.
*/
private LogicalImagerPanel(String context) {
this.contextName = context;
initComponents();
clearImageTable();
}
/**
* Creates and returns an instance of a LogicalImagerPanel.
*
* @param context A string context name used to read/store last
* used settings.
*
* @return instance of the LogicalImagerPanel
*/
@Messages({
"LogicalImagerPanel.messageLabel.clickScanOrBrowse=Click SCAN or BROWSE button to find images"
})
public static synchronized LogicalImagerPanel createInstance(String context) {
LogicalImagerPanel instance = new LogicalImagerPanel(context);
// post-constructor initialization of listener support without leaking references of uninitialized objects
instance.messageLabel.setText(Bundle.LogicalImagerPanel_messageLabel_clickScanOrBrowse());
instance.imageTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
return instance;
}
/**
* 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() {
topLabel = new javax.swing.JLabel();
jLabel1 = new javax.swing.JLabel();
scanButton = new javax.swing.JButton();
messageLabel = new javax.swing.JLabel();
selectDriveLabel = new javax.swing.JLabel();
driveListScrollPane = new javax.swing.JScrollPane();
driveList = new javax.swing.JList<>();
selectAcquisitionFromDriveLabel = new javax.swing.JLabel();
jLabel6 = new javax.swing.JLabel();
browseButton = new javax.swing.JButton();
imageScrollPane = new javax.swing.JScrollPane();
imageTable = new javax.swing.JTable();
jSeparator1 = new javax.swing.JSeparator();
setMinimumSize(new java.awt.Dimension(0, 65));
setPreferredSize(new java.awt.Dimension(403, 65));
org.openide.awt.Mnemonics.setLocalizedText(topLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.topLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.jLabel1.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(scanButton, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.scanButton.text")); // NOI18N
scanButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
scanButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(messageLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.messageLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(selectDriveLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.selectDriveLabel.text")); // NOI18N
driveList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
driveList.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
driveListMouseClicked(evt);
}
});
driveList.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent evt) {
driveListKeyReleased(evt);
}
});
driveListScrollPane.setViewportView(driveList);
org.openide.awt.Mnemonics.setLocalizedText(selectAcquisitionFromDriveLabel, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.selectAcquisitionFromDriveLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.jLabel6.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(LogicalImagerPanel.class, "LogicalImagerPanel.browseButton.text")); // NOI18N
browseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
browseButtonActionPerformed(evt);
}
});
imageScrollPane.setPreferredSize(new java.awt.Dimension(346, 402));
imageTable.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
},
new String [] {
}
));
imageTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
imageTable.setShowHorizontalLines(false);
imageTable.setShowVerticalLines(false);
imageTable.getTableHeader().setReorderingAllowed(false);
imageTable.setUpdateSelectionOnSort(false);
imageTable.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
imageTableMouseClicked(evt);
}
});
imageTable.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent evt) {
imageTableKeyReleased(evt);
}
});
imageScrollPane.setViewportView(imageTable);
imageTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
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(238, 238, 238)
.addComponent(topLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 163, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addGap(28, 28, 28)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(messageLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(selectDriveLabel)
.addGap(289, 289, 289))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(scanButton)
.addGap(126, 126, 126)))
.addGap(36, 36, 36)
.addComponent(browseButton))
.addGroup(layout.createSequentialGroup()
.addComponent(driveListScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 211, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(28, 28, 28)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(selectAcquisitionFromDriveLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 305, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(imageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 346, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGroup(layout.createSequentialGroup()
.addGap(346, 346, 346)
.addComponent(jLabel6, javax.swing.GroupLayout.PREFERRED_SIZE, 154, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addGap(144, 144, 144)
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 116, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addContainerGap(48, Short.MAX_VALUE))))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(topLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
.addComponent(jLabel6))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(scanButton)
.addComponent(browseButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 4, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(selectDriveLabel)
.addComponent(selectAcquisitionFromDriveLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(imageScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addComponent(driveListScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 194, Short.MAX_VALUE))
.addGap(26, 26, 26)
.addComponent(messageLabel)
.addGap(154, 154, 154))
);
}// </editor-fold>//GEN-END:initComponents
public static String humanReadableByteCount(long bytes, boolean si) {
int unit = si ? 1000 : 1024;
if (bytes < unit) {
return bytes + " B"; //NON-NLS
}
int exp = (int) (Math.log(bytes) / Math.log(unit));
String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i"); //NON-NLS
return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); //NON-NLS
}
@Messages({
"LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for sparse_image.vhd ...",
"LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found"
})
private void scanButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scanButtonActionPerformed
// Scan external drives for sparse_image.vhd
clearImageTable();
setNormalMessage(Bundle.LogicalImagerPanel_messageLabel_scanningExternalDrives());
List<String> listData = new ArrayList<>();
File[] roots = File.listRoots();
int firstRemovableDrive = -1;
int i = 0;
for (File root : roots) {
String description = FileSystemView.getFileSystemView().getSystemTypeDescription(root);
long spaceInBytes = root.getTotalSpace();
String sizeWithUnit = humanReadableByteCount(spaceInBytes, false);
listData.add(root + " (" + description + ") (" + sizeWithUnit + ")");
if (firstRemovableDrive == -1) {
try {
FileStore fileStore = Files.getFileStore(root.toPath());
if ((boolean) fileStore.getAttribute("volume:isRemovable")) { //NON-NLS
firstRemovableDrive = i;
}
} catch (IOException ex) {
; // skip
}
}
i++;
}
driveList.setListData(listData.toArray(new String[0]));
if (!listData.isEmpty()) {
// auto-select the first external drive, if any
driveList.setSelectedIndex(firstRemovableDrive == -1 ? 0 : firstRemovableDrive);
driveListMouseClicked(null);
driveList.requestFocusInWindow();
} else {
setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_noExternalDriveFound());
}
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
}//GEN-LAST:event_scanButtonActionPerformed
@Messages({
"LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain {1}",
"LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS"
})
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
imageTable.clearSelection();
choosenImageDirPath = null;
setErrorMessage(NO_IMAGE_SELECTED);
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int retval = fileChooser.showOpenDialog(this);
if (retval == JFileChooser.APPROVE_OPTION) {
String path = fileChooser.getSelectedFile().getPath();
Matcher m = regex.matcher(path);
if (m.find()) {
Path vhdPath = Paths.get(path, SPARSE_IMAGE_VHD);
if (!vhdPath.toFile().exists()) {
setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_directoryDoesNotContainSparseImage(path,SPARSE_IMAGE_VHD));
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
return;
}
choosenImageDirPath = Paths.get(path);
setNormalMessage(SELECTED_IMAGE + " " + path);
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
} else {
setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_directoryFormatInvalid(path));
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
}
} else {
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
}
}//GEN-LAST:event_browseButtonActionPerformed
private void imageTableSelect() {
int index = imageTable.getSelectedRow();
if (index != -1) {
choosenImageDirPath = Paths.get((String) imageTableModel.getValueAt(index, 2));
setNormalMessage(SELECTED_IMAGE + " " + choosenImageDirPath.toString());
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
} else {
choosenImageDirPath = null;
setErrorMessage(NO_IMAGE_SELECTED);
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
}
}
private void imageTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_imageTableMouseClicked
imageTableSelect();
}//GEN-LAST:event_imageTableMouseClicked
private void driveListSelect() {
String selectedStr = driveList.getSelectedValue();
if (selectedStr == null) {
return;
}
String driveLetter = selectedStr.substring(0, 3);
File directory = new File(driveLetter);
File[] fList = directory.listFiles();
if (fList != null) {
imageTableModel = new ImageTableModel();
int row = 0;
// Find all directories with name like Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS
// and has a sparse_image.vhd file in it
for (File file : fList) {
if (file.isDirectory()
&& Paths.get(driveLetter, file.getName(), SPARSE_IMAGE_VHD).toFile().exists()) {
String dir = file.getName();
Matcher m = regex.matcher(dir);
if (m.find()) {
String imageDirPath = driveLetter + dir;
String hostname = m.group(1);
String year = m.group(2);
String month = m.group(3);
String day = m.group(4);
String hour = m.group(5);
String minute = m.group(6);
String second = m.group(7);
String extractDate = year + "/" + month + "/" + day
+ " " + hour + ":" + minute + ":" + second;
imageTableModel.setValueAt(hostname, row, 0);
imageTableModel.setValueAt(extractDate, row, 1);
imageTableModel.setValueAt(imageDirPath, row, 2);
row++;
}
}
}
selectAcquisitionFromDriveLabel.setText(Bundle.LogicalImagerPanel_selectAcquisitionFromDriveLabel_text()
+ " " + driveLetter);
imageTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
imageTable.setModel(imageTableModel);
fixImageTableColumnWidth();
// If there are any images, select the first one
if (imageTable.getRowCount() > 0) {
imageTable.setRowSelectionInterval(0, 0);
imageTableSelect();
} else {
choosenImageDirPath = null;
setErrorMessage(DRIVE_HAS_NO_IMAGES);
}
}
}
private void fixImageTableColumnWidth() {
int width = imageScrollPane.getPreferredSize().width - 2;
imageTable.getColumnModel().getColumn(0).setPreferredWidth((int) (.60 * width));
imageTable.getColumnModel().getColumn(1).setPreferredWidth((int) (.40 * width));
}
private void setErrorMessage(String msg) {
messageLabel.setForeground(Color.red);
messageLabel.setText(msg);
}
private void setNormalMessage(String msg) {
messageLabel.setForeground(Color.black);
messageLabel.setText(msg);
}
private void clearImageTable() {
imageTableModel = new ImageTableModel();
imageTable.setModel(imageTableModel);
fixImageTableColumnWidth();
}
private void driveListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_driveListMouseClicked
driveListSelect();
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
}//GEN-LAST:event_driveListMouseClicked
private void driveListKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_driveListKeyReleased
driveListSelect();
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
}//GEN-LAST:event_driveListKeyReleased
private void imageTableKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_imageTableKeyReleased
imageTableSelect();
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
}//GEN-LAST:event_imageTableKeyReleased
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton browseButton;
private javax.swing.JList<String> driveList;
private javax.swing.JScrollPane driveListScrollPane;
private javax.swing.JScrollPane imageScrollPane;
private javax.swing.JTable imageTable;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel6;
private javax.swing.JSeparator jSeparator1;
private javax.swing.JLabel messageLabel;
private javax.swing.JButton scanButton;
private javax.swing.JLabel selectAcquisitionFromDriveLabel;
private javax.swing.JLabel selectDriveLabel;
private javax.swing.JLabel topLabel;
// End of variables declaration//GEN-END:variables
public void reset() {
//reset the UI elements to default
choosenImageDirPath = null;
driveList.setListData(EMPTY_LIST_DATA);
clearImageTable();
setNormalMessage(Bundle.LogicalImagerPanel_messageLabel_clickScanOrBrowse());
}
/**
* Should we enable the next button of the wizard?
*
* @return true if a proper image has been selected, false otherwise
*/
public boolean validatePanel() {
return choosenImageDirPath != null && choosenImageDirPath.toFile().exists();
}
Path getImageDirPath() {
return choosenImageDirPath;
}
@Override
public void insertUpdate(DocumentEvent e) {
}
@Override
public void removeUpdate(DocumentEvent e) {
}
@Override
public void changedUpdate(DocumentEvent e) {
}
void storeSettings() {
}
private class ImageTableModel extends AbstractTableModel {
private final List<String> hostnames = new ArrayList<>();
private final List<String> extractDates = new ArrayList<>();
private final List<String> imageDirPaths = new ArrayList<>();
@Override
public int getRowCount() {
return hostnames.size();
}
@Override
public int getColumnCount() {
return 2;
}
@Messages({
"LogicalImagerPanel.imageTable.columnModel.title0=Hostname",
"LogicalImagerPanel.imageTable.columnModel.title1=Extracted Date"
})
@Override
public String getColumnName(int column) {
String colName = null;
switch (column) {
case 0:
colName = Bundle.LogicalImagerPanel_imageTable_columnModel_title0();
break;
case 1:
colName = Bundle.LogicalImagerPanel_imageTable_columnModel_title1();
break;
default:
break;
}
return colName;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object ret = null;
switch (columnIndex) {
case 0:
ret = hostnames.get(rowIndex);
break;
case 1:
ret = extractDates.get(rowIndex);
break;
case 2:
ret = imageDirPaths.get(rowIndex);
break;
default:
throw new UnsupportedOperationException("Invalid table column index: " + columnIndex); //NON-NLS
}
return ret;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
hostnames.add((String) aValue);
break;
case 1:
extractDates.add((String) aValue);
break;
case 2:
imageDirPaths.add((String) aValue);
break;
default:
throw new UnsupportedOperationException("Invalid table column index: " + columnIndex); //NON-NLS
}
// Only show the hostname and extractDates column
if (columnIndex < 2) {
super.setValueAt(aValue, rowIndex, columnIndex);
}
}
}
}

View File

@ -1,88 +0,0 @@
/*
* 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.python.google.common.collect.Iterables;
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.Content;
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.
*
*/
final 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));
String displayName = (accountDeviceInstances.size() == 1)
? Iterables.getOnlyElement(accountDeviceInstances).getAccount().getTypeSpecificID()
: accountDeviceInstances.size() + " accounts";
setDisplayName(displayName);
}
/**
* Children object for the relationships that the accounts are part of.
*/
private static class AccountRelationshipChildren extends ChildFactory<Content> {
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<Content> 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(Content t) {
if (t instanceof BlackboardArtifact) {
return new RelationshipNode((BlackboardArtifact) t);
} else {
throw new UnsupportedOperationException("Cannot create a RelationshipNode for non BlackboardArtifact content.");
}
}
}
}

View File

@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.communications;
import com.google.common.eventbus.Subscribe;
import java.awt.Component;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import javax.swing.JPanel;
import javax.swing.ListSelectionModel;
@ -31,11 +33,16 @@ import org.openide.explorer.ExplorerManager;
import org.openide.explorer.ExplorerUtils;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.lookup.ProxyLookup;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.communications.relationships.RelationshipBrowser;
import org.sleuthkit.autopsy.communications.relationships.SelectionInfo;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AccountDeviceInstance;
import org.sleuthkit.datamodel.CommunicationsFilter;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.TskCoreException;
@ -56,8 +63,9 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro
private final Outline outline;
private final ExplorerManager messageBrowserEM = new ExplorerManager();
private final ExplorerManager accountsTableEM = new ExplorerManager();
final RelationshipBrowser relationshipBrowser;
/*
* This lookup proxies the selection lookup of both he accounts table and
@ -78,21 +86,30 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro
((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
relationshipBrowser = new RelationshipBrowser();
jSplitPane1.setRightComponent(relationshipBrowser);
accountsTableEM.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);
} else if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
final Node[] selectedNodes = accountsTableEM.getSelectedNodes();
final Set<AccountDeviceInstance> accountDeviceInstances = new HashSet<>();
CommunicationsFilter filter = null;
for (final Node node : selectedNodes) {
accountDeviceInstances.add(((AccountDeviceInstanceNode) node).getAccountDeviceInstance());
filter = ((AccountDeviceInstanceNode)node).getFilter();
}
relationshipBrowser.setSelectionInfo(new SelectionInfo(accountDeviceInstances, filter));
}
});
final MessageBrowser messageBrowser = new MessageBrowser(accountsTableEM, messageBrowserEM);
jSplitPane1.setRightComponent(messageBrowser);
proxyLookup = new ProxyLookup(
messageBrowser.getLookup(),
ExplorerUtils.createLookup(accountsTableEM, getActionMap()));
proxyLookup = new ProxyLookup(relationshipBrowser.getLookup(),
ExplorerUtils.createLookup(accountsTableEM, getActionMap()));
}
private void setColumnWidths() {

View File

@ -32,21 +32,16 @@ VisualizationPanel.zoomInButton.toolTipText=Zoom in
VisualizationPanel.zoomInButton.text=
VisualizationPanel.zoomOutButton.toolTipText=Zoom out
VisualizationPanel.zoomOutButton.text=
<<<<<<< HEAD
VisualizationPanel.fastOrganicLayoutButton.text=Redraw
VisualizationPanel.clearVizButton.text_1=Clear
VisualizationPanel.fastOrganicLayoutButton.text=
VisualizationPanel.backButton.text_1=
VisualizationPanel.forwardButton.text=
=======
VisualizationPanel.circleLayoutButton.text=Circle
VisualizationPanel.organicLayoutButton.text=Organic
VisualizationPanel.fastOrganicLayoutButton.text=
VisualizationPanel.hierarchyLayoutButton.text=Hierarchical
VisualizationPanel.clearVizButton.text_1=
VisualizationPanel.snapshotButton.text_1=Snapshot Report
>>>>>>> develop
VisualizationPanel.clearVizButton.actionCommand=
VisualizationPanel.backButton.toolTipText=Click to go back
VisualizationPanel.forwardButton.toolTipText=Click to go forward
VisualizationPanel.fastOrganicLayoutButton.toolTipText=Click to redraw the chart
VisualizationPanel.clearVizButton.toolTipText=Click to clear the chart
VisualizationPanel.forwardButton.text=

View File

@ -22,7 +22,6 @@ FiltersPanel.refreshButton.text=Refresh
FiltersPanel.deviceRequiredLabel.text=Select at least one.
FiltersPanel.accountTypeRequiredLabel.text=Select at least one.
FiltersPanel.needsRefreshLabel.text=Displayed data is out of date. Press Refresh.
MessageBrowser.DataResultViewerTable.title=Messages
OpenCVTAction.displayName=Communications
PinAccountsAction.pluralText=Add Selected Accounts to Visualization
PinAccountsAction.singularText=Add Selected Account to Visualization
@ -76,24 +75,19 @@ VisualizationPanel.zoomInButton.toolTipText=Zoom in
VisualizationPanel.zoomInButton.text=
VisualizationPanel.zoomOutButton.toolTipText=Zoom out
VisualizationPanel.zoomOutButton.text=
<<<<<<< HEAD
VisualizationPanel.fastOrganicLayoutButton.text=Redraw
VisualizationPanel.clearVizButton.text_1=Clear
VisualizationPanel.fastOrganicLayoutButton.text=
VisualizationPanel.backButton.text_1=
VisualizationPanel.forwardButton.text=
=======
VisualizationPanel.circleLayoutButton.text=Circle
VisualizationPanel.organicLayoutButton.text=Organic
VisualizationPanel.fastOrganicLayoutButton.text=
VisualizationPanel.hierarchyLayoutButton.text=Hierarchical
VisualizationPanel.clearVizButton.text_1=
VisualizationPanel.snapshotButton.text_1=Snapshot Report
>>>>>>> develop
VisualizationPanel.clearVizButton.actionCommand=
VisualizationPanel.backButton.toolTipText=Click to go back
VisualizationPanel.forwardButton.toolTipText=Click to go forward
VisualizationPanel.fastOrganicLayoutButton.toolTipText=Click to redraw the chart
VisualizationPanel.clearVizButton.toolTipText=Click to clear the chart
VisualizationPanel.forwardButton.text=
VisualizationPanel_action_dialogs_title=Communications
VisualizationPanel_action_name_text=Snapshot Report
VisualizationPanel_module_name=Communications

View File

@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.communications;
import com.google.common.eventbus.Subscribe;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.util.List;
@ -61,8 +62,11 @@ public final class CVTTopComponent extends TopComponent {
associateLookup(proxyLookup);
// Make sure the Global Actions Context is proxying the selection of the active tab.
browseVisualizeTabPane.addChangeListener(changeEvent -> {
Lookup.Provider selectedComponent = (Lookup.Provider) browseVisualizeTabPane.getSelectedComponent();
proxyLookup.setNewLookups(selectedComponent.getLookup());
Component selectedComponent = browseVisualizeTabPane.getSelectedComponent();
if(selectedComponent instanceof Lookup.Provider) {
Lookup lookup = ((Lookup.Provider)selectedComponent).getLookup();
proxyLookup.setNewLookups(lookup);
}
filtersPane.setDeviceAccountTypeEnabled(browseVisualizeTabPane.getSelectedIndex() != 0);
});

View File

@ -52,6 +52,7 @@ import org.sleuthkit.datamodel.CommunicationsFilter.DateRangeFilter;
import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter;
import org.sleuthkit.datamodel.DataSource;
import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG;
import static org.sleuthkit.datamodel.Relationship.Type.CONTACT;
import static org.sleuthkit.datamodel.Relationship.Type.MESSAGE;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
@ -598,7 +599,7 @@ final public class FiltersPanel extends JPanel {
commsFilter.addAndFilter(getAccountTypeFilter());
commsFilter.addAndFilter(getDateRangeFilter());
commsFilter.addAndFilter(new CommunicationsFilter.RelationshipTypeFilter(
ImmutableSet.of(CALL_LOG, MESSAGE)));
ImmutableSet.of(CALL_LOG, MESSAGE, CONTACT)));
return commsFilter;
}

View File

@ -1,231 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017-2018 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.awt.Component;
import java.awt.KeyboardFocusManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JPanel;
import static javax.swing.SwingUtilities.isDescendingFrom;
import org.openide.explorer.ExplorerManager;
import static org.openide.explorer.ExplorerUtils.createLookup;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
/**
* The right hand side of the CVT. Has a DataResultPanel to show a listing of
* messages and other account details, and a ContentViewer to show individual
* messages.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class MessageBrowser extends JPanel implements ExplorerManager.Provider, Lookup.Provider {
private static final long serialVersionUID = 1L;
private final ExplorerManager tableEM;
private final ExplorerManager gacExplorerManager;
private final DataResultPanel messagesResultPanel;
/* lookup that will be exposed through the (Global Actions Context) */
private final ModifiableProxyLookup proxyLookup = new ModifiableProxyLookup();
private final PropertyChangeListener focusPropertyListener = new PropertyChangeListener() {
/**
* Listener that keeps the proxyLookup in sync with the focused area of
* the UI.
*
* Since the embedded MessageContentViewer (attachments panel) is not in
* its own TopComponenet, its selection does not get proxied into the
* Global Actions Context (GAC), and many of the available actions don't
* work on it. Further, we can't put the selection from both the
* Messages table and the Attachments table in the GAC because they
* could both include AbstractFiles, muddling the selection seen by the
* actions. Instead, depending on where the focus is in the window, we
* want to put different Content in the Global Actions Context to be
* picked up by, e.g., the tagging actions. The best way I could figure
* to do this was to listen to all focus events and swap out what is in
* the lookup appropriately. An alternative to this would be to
* investigate using the ContextAwareAction interface.
*
* @see org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a
* similar situation and a similar solution.
*
* @param focusEvent The focus change event.
*/
@Override
public void propertyChange(final PropertyChangeEvent focusEvent) {
if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
final Component newFocusOwner = (Component) focusEvent.getNewValue();
if (newFocusOwner == null) {
return;
}
if (isDescendingFrom(newFocusOwner, messageDataContent)) {
//if the focus owner is within the MessageContentViewer ( the attachments table)
proxyLookup.setNewLookups(createLookup(messageDataContent.getExplorerManager(), getActionMap()));
} else if (isDescendingFrom(newFocusOwner, messagesResultPanel)) {
//... or if it is within the Messages table.
proxyLookup.setNewLookups(createLookup(gacExplorerManager, getActionMap()));
}
}
}
};
/**
* Constructs the right hand side of the Communications Visualization Tool
* (CVT).
*
* @param tableEM An explorer manager to listen to as the driver
* of the Message Table.
* @param gacExplorerManager An explorer manager associated with the
* GlobalActionsContext (GAC) so that selections
* in the messages browser can be exposed to
* context-sensitive actions.
*/
@NbBundle.Messages({"MessageBrowser.DataResultViewerTable.title=Messages"})
MessageBrowser(final ExplorerManager tableEM, final ExplorerManager gacExplorerManager) {
this.tableEM = tableEM;
this.gacExplorerManager = gacExplorerManager;
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);
messagesResultPanel.addResultViewer(new DataResultViewerTable(gacExplorerManager,
Bundle.MessageBrowser_DataResultViewerTable_title()));
messagesResultPanel.open();
this.tableEM.addPropertyChangeListener(new PropertyChangeListener() {
/**
* Listener that pushes selections in the tableEM (the Accounts
* table) into the Messages table.
*
* @param pce The ExplorerManager event.
*/
@Override
public void propertyChange(PropertyChangeEvent pce) {
if (pce.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
final Node[] selectedNodes = MessageBrowser.this.tableEM.getSelectedNodes();
messagesResultPanel.setNumberOfChildNodes(0);
messagesResultPanel.setNode(null);
messagesResultPanel.setPath("");
if (selectedNodes.length > 0) {
Node rootNode;
final Node selectedNode = selectedNodes[0];
if (selectedNode instanceof AccountDeviceInstanceNode) {
rootNode = makeRootNodeFromAccountDeviceInstanceNodes(selectedNodes);
} else {
rootNode = selectedNode;
}
messagesResultPanel.setPath(rootNode.getDisplayName());
messagesResultPanel.setNode(new TableFilterNode(new DataResultFilterNode(rootNode, gacExplorerManager), true));
}
}
}
private Node makeRootNodeFromAccountDeviceInstanceNodes(final Node[] selectedNodes) {
//Use lookup here?
final AccountDeviceInstanceNode adiNode = (AccountDeviceInstanceNode) selectedNodes[0];
final Set<AccountDeviceInstanceKey> accountDeviceInstances = new HashSet<>();
for (final Node n : selectedNodes) {
//Use lookup here?
accountDeviceInstances.add(((AccountDeviceInstanceNode) n).getAccountDeviceInstanceKey());
}
return SelectionNode.createFromAccounts(accountDeviceInstances, adiNode.getFilter(), adiNode.getCommsManager());
}
}
);
}
@Override
public ExplorerManager getExplorerManager() {
return gacExplorerManager;
}
@Override
public Lookup getLookup() {
return proxyLookup;
}
@Override
public void addNotify() {
super.addNotify();
//add listener that maintains correct selection in the Global Actions Context
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addPropertyChangeListener("focusOwner", focusPropertyListener);
}
@Override
public void removeNotify() {
super.removeNotify();
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.removePropertyChangeListener("focusOwner", focusPropertyListener);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
splitPane = new javax.swing.JSplitPane();
messageDataContent = new org.sleuthkit.autopsy.communications.MessageDataContent();
splitPane.setDividerLocation(400);
splitPane.setDividerSize(10);
splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
splitPane.setResizeWeight(0.5);
splitPane.setBottomComponent(messageDataContent);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(splitPane))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(splitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1083, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.communications.MessageDataContent messageDataContent;
private javax.swing.JSplitPane splitPane;
// End of variables declaration//GEN-END:variables
}

View File

@ -26,9 +26,9 @@ import org.openide.util.lookup.ProxyLookup;
* delegated to.
*
*/
final class ModifiableProxyLookup extends ProxyLookup {
final public class ModifiableProxyLookup extends ProxyLookup {
ModifiableProxyLookup(final Lookup... lookups) {
public ModifiableProxyLookup(final Lookup... lookups) {
super(lookups);
}

View File

@ -1,35 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.communications;
import java.util.Collection;
import java.util.List;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Node;
import org.sleuthkit.datamodel.BlackboardArtifact;
/**
*
*/
public class RelaionshipSetNodeFactory extends ChildFactory<BlackboardArtifact> {
private final Collection<BlackboardArtifact> artifacts;
public RelaionshipSetNodeFactory(Collection<BlackboardArtifact> artifacts) {
this.artifacts = artifacts;
}
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
list.addAll(artifacts);
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact key) {
return new RelationshipNode(key);
}
}

View File

@ -1,140 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.Iterables;
import com.google.common.collect.Sets;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.lookup.Lookups;
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.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
* 'Root' Node for the Account/Messages area. Represents all the relationships
* that are selected in the AccountsBrowser or the VisualizationPanel. Can be
* populated with AccountDeviceInstance and/or directly with relationships
* (Content).
*/
final class SelectionNode extends AbstractNode {
private SelectionNode(Children children, Lookup lookup) {
super(children, lookup);
}
static SelectionNode createFromAccountsAndRelationships(
Set<Content> edgeRelationshipArtifacts,
Set<AccountDeviceInstanceKey> accountDeviceInstanceKeys,
CommunicationsFilter filter,
CommunicationsManager commsManager) {
Set<AccountDeviceInstance> accountDeviceInstances = accountDeviceInstanceKeys.stream()
.map(AccountDeviceInstanceKey::getAccountDeviceInstance)
.collect(Collectors.toSet());
SelectionNode node = new SelectionNode(Children.create(
new RelationshipChildren(
edgeRelationshipArtifacts,
accountDeviceInstances,
commsManager,
filter),
true), Lookups.fixed(accountDeviceInstanceKeys.toArray()));
//This is not good for internationalization!!!
String name = "";
final int accounts = accountDeviceInstances.size();
if (accounts > 1) {
name = accounts + " accounts";
} else if (accounts == 1) {
name = Iterables.getOnlyElement(accountDeviceInstances).getAccount().getTypeSpecificID();
}
final int edges = edgeRelationshipArtifacts.size();
if (edges > 0) {
name = name + (name.isEmpty() ? "" : " and ") + edges + " relationship" + (edges > 1 ? "s" : "");
}
node.setDisplayName(name);
return node;
}
static SelectionNode createFromAccounts(
Set<AccountDeviceInstanceKey> accountDeviceInstances,
CommunicationsFilter filter,
CommunicationsManager commsManager) {
return createFromAccountsAndRelationships(Collections.emptySet(), accountDeviceInstances, filter, commsManager);
}
/**
* Children object for the relationships that the accounts are part of.
*/
private static class RelationshipChildren extends ChildFactory<Content> {
static final private Logger logger = Logger.getLogger(RelationshipChildren.class.getName());
private final Set<Content> edgeRelationshipArtifacts;
private final Set<AccountDeviceInstance> accountDeviceInstances;
private final CommunicationsManager commsManager;
private final CommunicationsFilter filter;
private RelationshipChildren(Set<Content> selectedEdgeRelationshipSources, Set<AccountDeviceInstance> selecedAccountDeviceInstances, CommunicationsManager commsManager, CommunicationsFilter filter) {
this.edgeRelationshipArtifacts = selectedEdgeRelationshipSources;
this.accountDeviceInstances = selecedAccountDeviceInstances;
this.commsManager = commsManager;
this.filter = filter;
}
@Override
protected boolean createKeys(List<Content> list) {
try {
final Set<Content> relationshipSources = commsManager.getRelationshipSources(accountDeviceInstances, filter);
list.addAll(Sets.union(relationshipSources, edgeRelationshipArtifacts));
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting communications", ex);
}
return true;
}
@Override
protected Node createNodeForKey(Content content) {
if (content instanceof BlackboardArtifact) {
return new RelationshipNode((BlackboardArtifact) content);
} else {
throw new UnsupportedOperationException("Cannot create a RelationshipNode for non BlackboardArtifact content.");
}
}
}
}

View File

@ -28,12 +28,12 @@ import org.sleuthkit.datamodel.Account;
/**
* Utility class with helpers for dealing with accounts.
*/
class Utils {
public final class Utils {
private Utils() {
}
static ZoneId getUserPreferredZoneId() {
static public ZoneId getUserPreferredZoneId() {
ZoneId zone = UserPreferences.displayTimesInLocalTime() ?
ZoneOffset.systemDefault() : TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()).toZoneId();
return zone;
@ -44,7 +44,7 @@ class Utils {
*
* @return The path of the icon for the given Account Type.
*/
static final String getIconFilePath(Account.Type type) {
static public final String getIconFilePath(Account.Type type) {
return Accounts.getIconFilePath(type);
}

View File

@ -54,7 +54,6 @@ import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@ -62,11 +61,11 @@ import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@ -98,23 +97,20 @@ import org.apache.commons.lang3.StringUtils;
import org.controlsfx.control.Notifications;
import org.jdesktop.layout.GroupLayout;
import org.jdesktop.layout.LayoutStyle;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.ExplorerUtils;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ProxyLookup;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.communications.relationships.RelationshipBrowser;
import org.sleuthkit.autopsy.communications.relationships.SelectionInfo;
import org.sleuthkit.autopsy.communications.snapshot.CommSnapShotReportWriter;
import org.sleuthkit.autopsy.coreutils.FileUtil;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator;
import org.sleuthkit.datamodel.AccountDeviceInstance;
import org.sleuthkit.datamodel.CommunicationsFilter;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A panel that goes in the Visualize tab of the Communications Visualization
@ -127,7 +123,7 @@ import org.sleuthkit.datamodel.TskCoreException;
* actions to work correctly.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final public class VisualizationPanel extends JPanel implements Lookup.Provider {
final public class VisualizationPanel extends JPanel {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(VisualizationPanel.class.getName());
@ -140,9 +136,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
@NbBundle.Messages("VisualizationPanel.cancelButton.text=Cancel")
private static final String CANCEL = Bundle.VisualizationPanel_cancelButton_text();
private final ExplorerManager vizEM = new ExplorerManager();
private final ExplorerManager gacEM = new ExplorerManager();
private final ProxyLookup proxyLookup;
private Frame windowAncestor;
private CommunicationsManager commsManager;
@ -161,6 +154,8 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
private final Map<NamedGraphLayout, JButton> layoutButtons = new HashMap<>();
private NamedGraphLayout currentLayout;
private final RelationshipBrowser relationshipBrowser;
private final StateManager stateManager;
@ -225,13 +220,9 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
final GraphMouseListener graphMouseListener = new GraphMouseListener();
graphComponent.getGraphControl().addMouseWheelListener(graphMouseListener);
graphComponent.getGraphControl().addMouseListener(graphMouseListener);
final MessageBrowser messageBrowser = new MessageBrowser(vizEM, gacEM);
splitPane.setRightComponent(messageBrowser);
proxyLookup = new ProxyLookup(
ExplorerUtils.createLookup(vizEM, getActionMap()),
messageBrowser.getLookup()
);
relationshipBrowser = new RelationshipBrowser();
splitPane.setRightComponent(relationshipBrowser);
//feed selection to explorermanager
graph.getSelectionModel().addListener(mxEvent.CHANGE, new SelectionListener());
@ -257,12 +248,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
setStateButtonsEnabled();
}
@Override
public Lookup getLookup() {
return proxyLookup;
}
@Subscribe
void handle(LockedVertexModel.VertexLockEvent event) {
final Set<mxCell> vertices = event.getVertices();
@ -387,219 +373,223 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
splitPane = new JSplitPane();
borderLayoutPanel = new JPanel();
placeHolderPanel = new JPanel();
jTextArea1 = new JTextArea();
toolbar = new JPanel();
fastOrganicLayoutButton = new JButton();
zoomOutButton = new JButton();
zoomInButton = new JButton();
zoomActualButton = new JButton();
fitZoomButton = new JButton();
jLabel2 = new JLabel();
zoomLabel = new JLabel();
clearVizButton = new JButton();
jSeparator2 = new JToolBar.Separator();
backButton = new JButton();
forwardButton = new JButton();
snapshotButton = new JButton();
jSeparator3 = new JToolBar.Separator();
jSeparator4 = new JToolBar.Separator();
notificationsJFXPanel = new JFXPanel();
splitPane = new javax.swing.JSplitPane();
borderLayoutPanel = new javax.swing.JPanel();
placeHolderPanel = new javax.swing.JPanel();
jTextArea1 = new javax.swing.JTextArea();
toolbar = new javax.swing.JPanel();
fastOrganicLayoutButton = new javax.swing.JButton();
zoomOutButton = new javax.swing.JButton();
zoomInButton = new javax.swing.JButton();
zoomActualButton = new javax.swing.JButton();
fitZoomButton = new javax.swing.JButton();
jLabel2 = new javax.swing.JLabel();
zoomLabel = new javax.swing.JLabel();
clearVizButton = new javax.swing.JButton();
jSeparator2 = new javax.swing.JToolBar.Separator();
backButton = new javax.swing.JButton();
forwardButton = new javax.swing.JButton();
snapshotButton = new javax.swing.JButton();
jSeparator3 = new javax.swing.JToolBar.Separator();
jSeparator4 = new javax.swing.JToolBar.Separator();
notificationsJFXPanel = new javafx.embed.swing.JFXPanel();
setLayout(new BorderLayout());
setLayout(new java.awt.BorderLayout());
splitPane.setDividerLocation(800);
splitPane.setResizeWeight(0.5);
borderLayoutPanel.setLayout(new BorderLayout());
borderLayoutPanel.setLayout(new java.awt.BorderLayout());
jTextArea1.setBackground(new Color(240, 240, 240));
jTextArea1.setBackground(new java.awt.Color(240, 240, 240));
jTextArea1.setColumns(20);
jTextArea1.setLineWrap(true);
jTextArea1.setRows(5);
jTextArea1.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.jTextArea1.text")); // NOI18N
jTextArea1.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.jTextArea1.text")); // NOI18N
GroupLayout placeHolderPanelLayout = new GroupLayout(placeHolderPanel);
org.jdesktop.layout.GroupLayout placeHolderPanelLayout = new org.jdesktop.layout.GroupLayout(placeHolderPanel);
placeHolderPanel.setLayout(placeHolderPanelLayout);
placeHolderPanelLayout.setHorizontalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING)
placeHolderPanelLayout.setHorizontalGroup(
placeHolderPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(placeHolderPanelLayout.createSequentialGroup()
.addContainerGap(250, Short.MAX_VALUE)
.add(jTextArea1, GroupLayout.PREFERRED_SIZE, 424, GroupLayout.PREFERRED_SIZE)
.add(jTextArea1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 424, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addContainerGap(423, Short.MAX_VALUE))
);
placeHolderPanelLayout.setVerticalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING)
placeHolderPanelLayout.setVerticalGroup(
placeHolderPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(placeHolderPanelLayout.createSequentialGroup()
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(jTextArea1, GroupLayout.PREFERRED_SIZE, 47, GroupLayout.PREFERRED_SIZE)
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(jTextArea1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 47, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
borderLayoutPanel.add(placeHolderPanel, BorderLayout.CENTER);
borderLayoutPanel.add(placeHolderPanel, java.awt.BorderLayout.CENTER);
fastOrganicLayoutButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png"))); // NOI18N
fastOrganicLayoutButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.text")); // NOI18N
fastOrganicLayoutButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.toolTipText")); // NOI18N
fastOrganicLayoutButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png"))); // NOI18N
fastOrganicLayoutButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.text")); // NOI18N
fastOrganicLayoutButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.toolTipText")); // NOI18N
fastOrganicLayoutButton.setFocusable(false);
fastOrganicLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
fastOrganicLayoutButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
zoomOutButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out-red.png"))); // NOI18N
zoomOutButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.text")); // NOI18N
zoomOutButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.toolTipText")); // NOI18N
zoomOutButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out-red.png"))); // NOI18N
zoomOutButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.text")); // NOI18N
zoomOutButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.toolTipText")); // NOI18N
zoomOutButton.setFocusable(false);
zoomOutButton.setHorizontalTextPosition(SwingConstants.CENTER);
zoomOutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
zoomOutButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
zoomOutButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
zoomOutButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
zoomOutButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
zoomOutButtonActionPerformed(evt);
}
});
zoomInButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png"))); // NOI18N
zoomInButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.text")); // NOI18N
zoomInButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.toolTipText")); // NOI18N
zoomInButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png"))); // NOI18N
zoomInButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.text")); // NOI18N
zoomInButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.toolTipText")); // NOI18N
zoomInButton.setFocusable(false);
zoomInButton.setHorizontalTextPosition(SwingConstants.CENTER);
zoomInButton.setVerticalTextPosition(SwingConstants.BOTTOM);
zoomInButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
zoomInButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
zoomInButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
zoomInButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
zoomInButtonActionPerformed(evt);
}
});
zoomActualButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png"))); // NOI18N
zoomActualButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.text")); // NOI18N
zoomActualButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.toolTipText")); // NOI18N
zoomActualButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png"))); // NOI18N
zoomActualButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.text")); // NOI18N
zoomActualButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.toolTipText")); // NOI18N
zoomActualButton.setFocusable(false);
zoomActualButton.setHorizontalTextPosition(SwingConstants.CENTER);
zoomActualButton.setVerticalTextPosition(SwingConstants.BOTTOM);
zoomActualButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
zoomActualButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
zoomActualButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
zoomActualButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
zoomActualButtonActionPerformed(evt);
}
});
fitZoomButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png"))); // NOI18N
fitZoomButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.text")); // NOI18N
fitZoomButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.toolTipText")); // NOI18N
fitZoomButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png"))); // NOI18N
fitZoomButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.text")); // NOI18N
fitZoomButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.toolTipText")); // NOI18N
fitZoomButton.setFocusable(false);
fitZoomButton.setHorizontalTextPosition(SwingConstants.CENTER);
fitZoomButton.setVerticalTextPosition(SwingConstants.BOTTOM);
fitZoomButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
fitZoomButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
fitZoomButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
fitZoomButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
fitZoomButtonActionPerformed(evt);
}
});
jLabel2.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.jLabel2.text")); // NOI18N
jLabel2.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.jLabel2.text")); // NOI18N
zoomLabel.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomLabel.text")); // NOI18N
zoomLabel.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomLabel.text")); // NOI18N
clearVizButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/broom.png"))); // NOI18N
clearVizButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.text_1")); // NOI18N
clearVizButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.toolTipText")); // NOI18N
clearVizButton.setActionCommand(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.actionCommand")); // NOI18N
clearVizButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
clearVizButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/broom.png"))); // NOI18N
clearVizButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.text_1")); // NOI18N
clearVizButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.toolTipText")); // NOI18N
clearVizButton.setActionCommand(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.actionCommand")); // NOI18N
clearVizButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
clearVizButtonActionPerformed(evt);
}
});
jSeparator2.setOrientation(SwingConstants.VERTICAL);
jSeparator2.setOrientation(javax.swing.SwingConstants.VERTICAL);
backButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_previous.png"))); // NOI18N
backButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.text_1")); // NOI18N
backButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.toolTipText")); // NOI18N
backButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_previous.png"))); // NOI18N
backButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.text_1")); // NOI18N
backButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.toolTipText")); // NOI18N
backButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
backButtonActionPerformed(evt);
}
});
forwardButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_next.png"))); // NOI18N
forwardButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.text")); // NOI18N
forwardButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.toolTipText")); // NOI18N
forwardButton.setHorizontalTextPosition(SwingConstants.LEADING);
forwardButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_next.png"))); // NOI18N
forwardButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.text")); // NOI18N
forwardButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.toolTipText")); // NOI18N
forwardButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
forwardButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
forwardButtonActionPerformed(evt);
}
});
snapshotButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/report/images/image.png"))); // NOI18N
snapshotButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.snapshotButton.text_1")); // NOI18N
snapshotButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
snapshotButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/report/images/image.png"))); // NOI18N
snapshotButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.snapshotButton.text_1")); // NOI18N
snapshotButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
snapshotButtonActionPerformed(evt);
}
});
jSeparator3.setOrientation(SwingConstants.VERTICAL);
jSeparator3.setOrientation(javax.swing.SwingConstants.VERTICAL);
jSeparator4.setOrientation(SwingConstants.VERTICAL);
jSeparator4.setOrientation(javax.swing.SwingConstants.VERTICAL);
GroupLayout toolbarLayout = new GroupLayout(toolbar);
org.jdesktop.layout.GroupLayout toolbarLayout = new org.jdesktop.layout.GroupLayout(toolbar);
toolbar.setLayout(toolbarLayout);
toolbarLayout.setHorizontalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING)
toolbarLayout.setHorizontalGroup(
toolbarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(toolbarLayout.createSequentialGroup()
.addContainerGap()
.add(backButton)
.addPreferredGap(LayoutStyle.RELATED)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(forwardButton)
.addPreferredGap(LayoutStyle.RELATED)
.add(jSeparator4, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.RELATED)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(jSeparator4, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 10, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(fastOrganicLayoutButton)
.addPreferredGap(LayoutStyle.RELATED)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(clearVizButton)
.addPreferredGap(LayoutStyle.RELATED)
.add(jSeparator2, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.RELATED)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(jSeparator2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 10, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(jLabel2)
.addPreferredGap(LayoutStyle.RELATED)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(zoomLabel)
.addPreferredGap(LayoutStyle.RELATED)
.add(zoomOutButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.RELATED)
.add(zoomInButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.RELATED)
.add(zoomActualButton, GroupLayout.PREFERRED_SIZE, 33, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.RELATED)
.add(fitZoomButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.RELATED)
.add(jSeparator3, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.RELATED)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(zoomOutButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 32, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(zoomInButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 32, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(zoomActualButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 33, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(fitZoomButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 32, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(jSeparator3, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 10, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(snapshotButton)
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
toolbarLayout.setVerticalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING)
toolbarLayout.setVerticalGroup(
toolbarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(toolbarLayout.createSequentialGroup()
.add(3, 3, 3)
.add(toolbarLayout.createParallelGroup(GroupLayout.CENTER)
.add(toolbarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.CENTER)
.add(fastOrganicLayoutButton)
.add(zoomOutButton)
.add(zoomInButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(zoomActualButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(fitZoomButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(zoomInButton, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(zoomActualButton, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(fitZoomButton, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(jLabel2)
.add(zoomLabel)
.add(clearVizButton)
.add(jSeparator2, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(jSeparator2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(backButton)
.add(forwardButton)
.add(snapshotButton)
.add(jSeparator3, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(jSeparator4, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.add(jSeparator3, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(jSeparator4, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.add(3, 3, 3))
);
borderLayoutPanel.add(toolbar, BorderLayout.PAGE_START);
borderLayoutPanel.add(notificationsJFXPanel, BorderLayout.PAGE_END);
borderLayoutPanel.add(toolbar, java.awt.BorderLayout.PAGE_START);
borderLayoutPanel.add(notificationsJFXPanel, java.awt.BorderLayout.PAGE_END);
splitPane.setLeftComponent(borderLayoutPanel);
add(splitPane, BorderLayout.CENTER);
add(splitPane, java.awt.BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents
private void fitZoomButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_fitZoomButtonActionPerformed
@ -890,26 +880,26 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private JButton backButton;
private JPanel borderLayoutPanel;
private JButton clearVizButton;
private JButton fastOrganicLayoutButton;
private JButton fitZoomButton;
private JButton forwardButton;
private JLabel jLabel2;
private JToolBar.Separator jSeparator2;
private JToolBar.Separator jSeparator3;
private JToolBar.Separator jSeparator4;
private JTextArea jTextArea1;
private JFXPanel notificationsJFXPanel;
private JPanel placeHolderPanel;
private JButton snapshotButton;
private JSplitPane splitPane;
private JPanel toolbar;
private JButton zoomActualButton;
private JButton zoomInButton;
private JLabel zoomLabel;
private JButton zoomOutButton;
private javax.swing.JButton backButton;
private javax.swing.JPanel borderLayoutPanel;
private javax.swing.JButton clearVizButton;
private javax.swing.JButton fastOrganicLayoutButton;
private javax.swing.JButton fitZoomButton;
private javax.swing.JButton forwardButton;
private javax.swing.JLabel jLabel2;
private javax.swing.JToolBar.Separator jSeparator2;
private javax.swing.JToolBar.Separator jSeparator3;
private javax.swing.JToolBar.Separator jSeparator4;
private javax.swing.JTextArea jTextArea1;
private javafx.embed.swing.JFXPanel notificationsJFXPanel;
private javax.swing.JPanel placeHolderPanel;
private javax.swing.JButton snapshotButton;
private javax.swing.JSplitPane splitPane;
private javax.swing.JPanel toolbar;
private javax.swing.JButton zoomActualButton;
private javax.swing.JButton zoomInButton;
private javax.swing.JLabel zoomLabel;
private javax.swing.JButton zoomOutButton;
// End of variables declaration//GEN-END:variables
/**
@ -922,40 +912,25 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
@Override
public void invoke(Object sender, mxEventObject evt) {
Object[] selectionCells = graph.getSelectionCells();
Node rootNode = Node.EMPTY;
Node[] selectedNodes = new Node[0];
if (selectionCells.length > 0) {
mxICell[] selectedCells = Arrays.asList(selectionCells).toArray(new mxCell[selectionCells.length]);
HashSet<Content> relationshipSources = new HashSet<>();
HashSet<AccountDeviceInstanceKey> adis = new HashSet<>();
HashSet<AccountDeviceInstance> deviceInstances = new HashSet<>();
for (mxICell cell : selectedCells) {
if (cell.isEdge()) {
mxICell source = (mxICell) graph.getModel().getTerminal(cell, true);
AccountDeviceInstanceKey account1 = (AccountDeviceInstanceKey) source.getValue();
mxICell target = (mxICell) graph.getModel().getTerminal(cell, false);
AccountDeviceInstanceKey account2 = (AccountDeviceInstanceKey) target.getValue();
try {
final List<Content> relationshipSources1 = commsManager.getRelationshipSources(
account1.getAccountDeviceInstance(),
account2.getAccountDeviceInstance(),
currentFilter);
relationshipSources.addAll(relationshipSources1);
} catch (TskCoreException tskCoreException) {
logger.log(Level.SEVERE, " Error getting relationsips....", tskCoreException);
}
deviceInstances.add(((AccountDeviceInstanceKey) source.getValue()).getAccountDeviceInstance());
deviceInstances.add(((AccountDeviceInstanceKey) target.getValue()).getAccountDeviceInstance());
} else if (cell.isVertex()) {
adis.add((AccountDeviceInstanceKey) cell.getValue());
deviceInstances.add(((AccountDeviceInstanceKey) cell.getValue()).getAccountDeviceInstance());
}
}
rootNode = SelectionNode.createFromAccountsAndRelationships(relationshipSources, adis, currentFilter, commsManager);
selectedNodes = new Node[]{rootNode};
}
vizEM.setRootContext(rootNode);
try {
vizEM.setSelectedNodes(selectedNodes);
} catch (PropertyVetoException ex) {
logger.log(Level.SEVERE, "Selection vetoed.", ex);
relationshipBrowser.setSelectionInfo(new SelectionInfo(deviceInstances, currentFilter));
} else {
relationshipBrowser.setSelectionInfo(new SelectionInfo(Collections.EMPTY_SET, currentFilter));
}
}
}

View File

@ -0,0 +1,108 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.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.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.AccountFileInstance;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
* ChildFactory that creates ContentNode representing the files that reference
* the given list of accounts.
*/
final class AccountSourceContentChildNodeFactory extends ChildFactory<Content> {
private static final Logger logger = Logger.getLogger(AccountSourceContentChildNodeFactory.class.getName());
private final Set<Account> accounts;
AccountSourceContentChildNodeFactory(Set<Account> accounts) {
this.accounts = accounts;
}
@Override
protected boolean createKeys(List<Content> list) {
if (accounts == null || accounts.isEmpty()) {
return true;
}
CommunicationsManager communicationManager;
try {
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
} catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.WARNING, "Failed to get communications manager from case.", ex); //NON-NLS
return false;
}
accounts.forEach((account) -> {
try {
List<AccountFileInstance> accountFileInstanceList = communicationManager.getAccountFileInstances(account);
for (AccountFileInstance fileInstance : accountFileInstanceList) {
list.add(fileInstance.getFile());
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Failed to getAccountFileInstances for account: %d", account.getAccountID()), ex); //NON-NLS
}
});
return true;
}
@Override
protected Node createNodeForKey(Content content) {
return new ContentNode(content);
}
/**
* Simple AbstractNode for a Content (file) object.
*/
final class ContentNode extends AbstractNode {
private final Content content;
ContentNode(Content content) {
super(Children.LEAF);
this.content = content;
try {
setDisplayName(content.getUniquePath());
} catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Unable to getUniquePath for Content: %d", content.getId()), ex); //NON-NLS
setDisplayName(content.getName());
}
setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon.png"); //NON-NLS
}
}
}

View File

@ -0,0 +1,127 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obt ain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Factory for creating thumbnail children nodes.
*/
final class AttachmentsChildren extends Children.Keys<AbstractFile> {
private static final Logger logger = Logger.getLogger(AttachmentsChildren.class.getName());
private final Set<BlackboardArtifact> artifacts;
/*
* Creates the list of thumbnails from the given list of
* BlackboardArtifacts.
*
* The thumbnails will be initialls sorted by size, then name so that they
* appear sorted by size by default.
*/
AttachmentsChildren(Set<BlackboardArtifact> artifacts) {
super(false);
this.artifacts = artifacts;
}
@Override
protected Node[] createNodes(AbstractFile t) {
return new Node[]{new AttachementNode(t)};
}
@Override
protected void addNotify() {
super.addNotify();
Set<AbstractFile> thumbnails = new TreeSet<>((AbstractFile file1, AbstractFile file2) -> {
int result = Long.compare(file1.getSize(), file2.getSize());
if (result == 0) {
result = file1.getName().compareTo(file2.getName());
}
return result;
});
artifacts.forEach((bba) -> {
try {
for (Content childContent : bba.getChildren()) {
if (childContent instanceof AbstractFile) {
thumbnails.add((AbstractFile) childContent);
}
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Unable to get children from artifact.", ex); //NON-NLS
}
});
setKeys(thumbnails);
}
/**
* A node for representing a thumbnail.
*/
static class AttachementNode extends FileNode {
AttachementNode(AbstractFile file) {
super(file, false);
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Set<String> keepProps = new HashSet<>(Arrays.asList(
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.sizeColLbl"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.mimeType"),
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.knownColLbl")));
//Remove all other props except for the ones above
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
for (Node.Property<?> p : sheetSet.getProperties()) {
if (!keepProps.contains(p.getName())) {
sheetSet.remove(p.getName());
}
}
return sheet;
}
}
}

View File

@ -0,0 +1,15 @@
ContactDetailsPane.nameLabel.text=Placeholder
SummaryViewer.countsPanel.border.title=Counts
SummaryViewer.emailLabel.text=Emails:
SummaryViewer.contactsLabel.text=Contacts:
SummaryViewer.attachmentsLabel.text=Attachments:
SummaryViewer.fileReferencesPanel.border.title=File References in Current Case
SummaryViewer.caseReferencesPanel.border.title=Other Occurrences
OutlineViewPanel.messageLabel.text=<Control Disabled>
SummaryViewer.messagesDataLabel.text=messages
SummaryViewer.callLogsDataLabel.text=callLogs
SummaryViewer.contactsDataLabel.text=contacts
SummaryViewer.emailDataLabel.text=emails
SummaryViewer.attachmentsDataLabel.text=attachments
SummaryViewer.messagesLabel.text=Messages:
SummaryViewer.callLogsLabel.text=Call Logs:

View File

@ -0,0 +1,44 @@
ContactDetailsPane.nameLabel.text=Placeholder
ContactNode_Email=Email Address
ContactNode_Home_Number=Home Number
ContactNode_Mobile_Number=Mobile Number
ContactNode_Name=Name
ContactNode_Office_Number=Office Number
ContactNode_Phone=Phone Number
ContactNode_URL=URL
ContactsViewer_columnHeader_Email=Email
ContactsViewer_columnHeader_Name=Name
ContactsViewer_columnHeader_Phone=Phone
ContactsViewer_tabTitle=Contacts
MediaViewer_Name=Media
MessageNode_Node_Property_Attms=Attachments
MessageNode_Node_Property_Date=Date
MessageNode_Node_Property_From=From
MessageNode_Node_Property_Subject=Subject
MessageNode_Node_Property_To=To
MessageNode_Node_Property_Type=Type
MessageViewer_columnHeader_Attms=Attachments
MessageViewer_columnHeader_Date=Date
MessageViewer_columnHeader_From=From
MessageViewer_columnHeader_Subject=Subject
MessageViewer_columnHeader_To=To
MessageViewer_tabTitle=Messages
SummaryViewer.countsPanel.border.title=Counts
SummaryViewer.emailLabel.text=Emails:
SummaryViewer.contactsLabel.text=Contacts:
SummaryViewer.attachmentsLabel.text=Attachments:
SummaryViewer.fileReferencesPanel.border.title=File References in Current Case
SummaryViewer.caseReferencesPanel.border.title=Other Occurrences
OutlineViewPanel.messageLabel.text=<Control Disabled>
SummaryViewer.messagesDataLabel.text=messages
SummaryViewer.callLogsDataLabel.text=callLogs
SummaryViewer.contactsDataLabel.text=contacts
SummaryViewer.emailDataLabel.text=emails
SummaryViewer.attachmentsDataLabel.text=attachments
SummaryViewer.messagesLabel.text=Messages:
SummaryViewer.callLogsLabel.text=Call Logs:
SummaryViewer_CaseRefNameColumn_Title=Case Name
SummaryViewer_CentralRepository_Message=<Enable Central Resposity to see Case References>
SummaryViewer_Creation_Date_Title=Creation Date
SummaryViewer_FileRefNameColumn_Title=Path
SummaryViewer_TabTitle=Summary

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="org.sleuthkit.autopsy.contentviewers.MessageContentViewer" name="messageContentViewer1">
</Component>
</NonVisualComponents>
<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" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="propertySheet" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="nameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace 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 max="-2" attributes="0"/>
<Component id="nameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="propertySheet" pref="283" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="nameLabel">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="24" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="ContactDetailsPane.nameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="org.openide.explorer.propertysheet.PropertySheet" name="propertySheet">
<Properties>
<Property name="descriptionAreaVisible" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,116 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import org.openide.explorer.ExplorerManager;
import org.openide.nodes.Node;
/**
* Displays the propertied of a ContactNode in a PropertySheet.
*/
public final class ContactDetailsPane extends javax.swing.JPanel implements ExplorerManager.Provider {
final private ExplorerManager explorerManager = new ExplorerManager();
/**
* Displays the propertied of a ContactNode in a PropertySheet.
*/
public ContactDetailsPane() {
initComponents();
this.setEnabled(false);
nameLabel.setText("");
}
/**
* Sets the list of nodes for the property sheet.
*
* @param nodes List of nodes to set
*/
public void setNode(Node[] nodes) {
if (nodes != null && nodes.length == 1) {
nameLabel.setText(nodes[0].getDisplayName());
propertySheet.setNodes(nodes);
} else {
nameLabel.setText("");
propertySheet.setNodes(null);
}
}
@Override
public ExplorerManager getExplorerManager() {
return explorerManager;
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
nameLabel.setEnabled(enabled);
propertySheet.setEnabled(enabled);
}
/**
* 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() {
messageContentViewer1 = new org.sleuthkit.autopsy.contentviewers.MessageContentViewer();
nameLabel = new javax.swing.JLabel();
propertySheet = new org.openide.explorer.propertysheet.PropertySheet();
nameLabel.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(ContactDetailsPane.class, "ContactDetailsPane.nameLabel.text")); // NOI18N
propertySheet.setDescriptionAreaVisible(false);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(propertySheet, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(nameLabel)
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(nameLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(propertySheet, javax.swing.GroupLayout.DEFAULT_SIZE, 283, Short.MAX_VALUE)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer messageContentViewer1;
private javax.swing.JLabel nameLabel;
private org.openide.explorer.propertysheet.PropertySheet propertySheet;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,161 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import java.util.logging.Level;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT;
import org.sleuthkit.datamodel.BlackboardAttribute;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME_PERSON;
import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME;
import org.sleuthkit.datamodel.TimeUtilities;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.communications.Utils;
/**
* Extends BlackboardArtifactNode to override createSheet to create a contact
* artifact specific sheet.
*/
final class ContactNode extends BlackboardArtifactNode {
private static final Logger logger = Logger.getLogger(ContactNode.class.getName());
@Messages({
"ContactNode_Name=Name",
"ContactNode_Phone=Phone Number",
"ContactNode_Email=Email Address",
"ContactNode_Mobile_Number=Mobile Number",
"ContactNode_Office_Number=Office Number",
"ContactNode_URL=URL",
"ContactNode_Home_Number=Home Number",})
ContactNode(BlackboardArtifact artifact) {
super(artifact);
String name = getAttributeDisplayString(artifact, TSK_NAME);
if (name == null || name.trim().isEmpty()) {
// VCards use TSK_NAME_PERSON instead of TSK_NAME
name = getAttributeDisplayString(artifact, TSK_NAME_PERSON);
}
setDisplayName(name);
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
final BlackboardArtifact artifact = getArtifact();
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
if (fromID != TSK_CONTACT) {
return sheet;
}
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
// Sorting the attributes by type so that the duplicates can be removed
// and they can be grouped by type for display. The attribute prefixes
// are used so that all attributed of that type are found, including
// ones that are not predefined as part of BlackboardAttributes
try {
HashMap<String, BlackboardAttribute> phoneNumMap = new HashMap<>();
HashMap<String, BlackboardAttribute> emailMap = new HashMap<>();
HashMap<String, BlackboardAttribute> nameMap = new HashMap<>();
HashMap<String, BlackboardAttribute> otherMap = new HashMap<>();
for (BlackboardAttribute bba : artifact.getAttributes()) {
if (bba.getAttributeType().getTypeName().startsWith("TSK_PHONE")) {
phoneNumMap.put(bba.getDisplayString(), bba);
} else if (bba.getAttributeType().getTypeName().startsWith("TSK_EMAIL")) {
emailMap.put(bba.getDisplayString(), bba);
} else if (bba.getAttributeType().getTypeName().startsWith("TSK_NAME")) {
nameMap.put(bba.getDisplayString(), bba);
} else {
otherMap.put(bba.getDisplayString(), bba);
}
}
addPropertiesToSheet(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getLabel(),
sheetSet, nameMap);
addPropertiesToSheet(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getLabel(),
sheetSet, phoneNumMap);
addPropertiesToSheet(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL.getLabel(),
sheetSet, emailMap);
for (BlackboardAttribute bba : otherMap.values()) {
sheetSet.put(new NodeProperty<>(bba.getAttributeType().getTypeName(), bba.getAttributeType().getDisplayName(), "", bba.getDisplayString()));
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error getting attribute values.", ex); //NON-NLS
}
return sheet;
}
private void addPropertiesToSheet(String propertyID, Sheet.Set sheetSet, Map<String, BlackboardAttribute> attributeMap) {
int count = 0;
for (BlackboardAttribute bba : attributeMap.values()) {
if (count++ > 0) {
sheetSet.put(new NodeProperty<>(propertyID + "_" + count, bba.getAttributeType().getDisplayName(), "", bba.getDisplayString()));
} else {
sheetSet.put(new NodeProperty<>(propertyID, bba.getAttributeType().getDisplayName(), "", bba.getDisplayString()));
}
}
}
private static String getAttributeDisplayString(final BlackboardArtifact artifact, final BlackboardAttribute.ATTRIBUTE_TYPE attributeType) {
try {
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(attributeType.getTypeID())));
if (attribute == null) {
return "";
} else if (attributeType.getValueType() == DATETIME) {
return TimeUtilities.epochToTime(attribute.getValueLong(),
TimeZone.getTimeZone(Utils.getUserPreferredZoneId()));
} else {
return attribute.getDisplayString();
}
} catch (TskCoreException tskCoreException) {
logger.log(Level.WARNING, "Error getting attribute value.", tskCoreException); //NON-NLS
return "";
}
}
/**
* Circumvent DataResultFilterNode's slightly odd delegation to
* BlackboardArtifactNode.getSourceName().
*
* @return the displayName of this Node, which is the type.
*/
@Override
public String getSourceName() {
return getDisplayName();
}
}

View File

@ -0,0 +1,109 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
* ChildFactory for ContactNodes.
*/
final class ContactsChildNodeFactory extends ChildFactory<BlackboardArtifact>{
private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName());
private SelectionInfo selectionInfo;
/**
* Construct a new ContactsChildNodeFactory from the currently selectionInfo
*
* @param selectionInfo SelectionInfo object for the currently selected
* accounts
*/
ContactsChildNodeFactory(SelectionInfo selectionInfo) {
this.selectionInfo = selectionInfo;
}
/**
* Updates the current instance of selectionInfo and calls the refresh method.
*
* @param selectionInfo New instance of the currently selected accounts
*/
public void refresh(SelectionInfo selectionInfo) {
this.selectionInfo = selectionInfo;
refresh(true);
}
/**
* Creates a list of Keys (BlackboardArtifact) for only contacts of the
* currently selected accounts
* @param list List of BlackboardArtifact to populate
* @return True on success
*/
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
CommunicationsManager communicationManager;
try {
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
} catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS
return false;
}
if(selectionInfo == null) {
return true;
}
final Set<Content> relationshipSources;
try {
relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter());
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
BlackboardArtifact bba = (BlackboardArtifact) content;
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID());
if (fromID == TSK_CONTACT) {
list.add(bba);
}
});
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS
}
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact key) {
return new ContactNode(key);
}
}

View File

@ -0,0 +1,42 @@
<?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">
<Component id="outlineView" max="32767" attributes="0"/>
<Component id="contactPane" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="outlineView" pref="350" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="1" max="-2" attributes="0"/>
<Component id="contactPane" pref="400" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="org.openide.explorer.view.OutlineView" name="outlineView">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new org.openide.explorer.view.OutlineView()"/>
</AuxValues>
</Component>
<Component class="org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane" name="contactPane">
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,186 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obt ain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.awt.Component;
import java.awt.KeyboardFocusManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JPanel;
import javax.swing.ListSelectionModel;
import static javax.swing.SwingUtilities.isDescendingFrom;
import org.netbeans.swing.outline.DefaultOutlineModel;
import org.netbeans.swing.outline.Outline;
import org.openide.explorer.ExplorerManager;
import static org.openide.explorer.ExplorerUtils.createLookup;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
import org.sleuthkit.datamodel.BlackboardAttribute;
/**
* Visualization for contact nodes.
*
*/
@ServiceProvider(service = RelationshipsViewer.class)
public final class ContactsViewer extends JPanel implements RelationshipsViewer, ExplorerManager.Provider, Lookup.Provider {
private final ExplorerManager tableEM;
private final Outline outline;
private final ModifiableProxyLookup proxyLookup;
private final PropertyChangeListener focusPropertyListener;
private final ContactsChildNodeFactory nodeFactory;
@NbBundle.Messages({
"ContactsViewer_tabTitle=Contacts",
"ContactsViewer_columnHeader_Name=Name",
"ContactsViewer_columnHeader_Phone=Phone",
"ContactsViewer_columnHeader_Email=Email",})
/**
* Visualization for contact nodes.
*/
public ContactsViewer() {
tableEM = new ExplorerManager();
proxyLookup = new ModifiableProxyLookup(createLookup(tableEM, getActionMap()));
nodeFactory = new ContactsChildNodeFactory(null);
// See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
// explaination of focusPropertyListener
focusPropertyListener = (final PropertyChangeEvent focusEvent) -> {
if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
final Component newFocusOwner = (Component) focusEvent.getNewValue();
if (newFocusOwner == null) {
return;
}
if (isDescendingFrom(newFocusOwner, contactPane)) {
//if the focus owner is within the MessageContentViewer (the attachments table)
proxyLookup.setNewLookups(createLookup(contactPane.getExplorerManager(), getActionMap()));
} else if (isDescendingFrom(newFocusOwner, ContactsViewer.this)) {
//... or if it is within the Results table.
proxyLookup.setNewLookups(createLookup(tableEM, getActionMap()));
}
}
};
initComponents();
outline = outlineView.getOutline();
outlineView.setPropertyColumns(
"TSK_EMAIL", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL.getDisplayName(),
"TSK_PHONE_NUMBER", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getDisplayName()
);
outline.setRootVisible(false);
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.ContactsViewer_columnHeader_Name());
tableEM.addPropertyChangeListener((PropertyChangeEvent evt) -> {
if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
final Node[] nodes = tableEM.getSelectedNodes();
contactPane.setNode(nodes);
}
});
tableEM.setRootContext(new TableFilterNode(new DataResultFilterNode(new AbstractNode(Children.create(nodeFactory, true)), getExplorerManager()), true));
}
@Override
public String getDisplayName() {
return Bundle.ContactsViewer_tabTitle();
}
@Override
public JPanel getPanel() {
return this;
}
@Override
public void setSelectionInfo(SelectionInfo info) {
contactPane.setNode(new Node[]{new AbstractNode(Children.LEAF)});
contactPane.setEnabled(false);
nodeFactory.refresh(info);
}
@Override
public ExplorerManager getExplorerManager() {
return tableEM;
}
@Override
public Lookup getLookup() {
return proxyLookup;
}
@Override
public void addNotify() {
super.addNotify();
//add listener that maintains correct selection in the Global Actions Context
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addPropertyChangeListener("focusOwner", focusPropertyListener);
}
@Override
public void removeNotify() {
super.removeNotify();
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.removePropertyChangeListener("focusOwner", focusPropertyListener);
}
/**
* 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();
contactPane = new org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane();
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(contactPane, 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()
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 350, Short.MAX_VALUE)
.addGap(1, 1, 1)
.addComponent(contactPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane contactPane;
private org.openide.explorer.view.OutlineView outlineView;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,169 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.openide.nodes.Sheet;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.Account;
/**
* ChildFactory for CorrelationCases. Finds the cases that reference the given
* list of accounts.
*/
final class CorrelationCaseChildNodeFactory extends ChildFactory<CorrelationCase> {
private static final Logger logger = Logger.getLogger(CorrelationCaseChildNodeFactory.class.getName());
private Map<Integer, CorrelationAttributeInstance.Type> correlationTypeMap;
private final Set<Account> accounts;
/**
* ChildFactory for CorrelationCases.
*
* @param accounts List of Account objects
*/
CorrelationCaseChildNodeFactory(Set<Account> accounts) {
this.accounts = accounts;
}
@Override
protected boolean createKeys(List<CorrelationCase> list) {
if (!EamDb.isEnabled()) {
return true;
}
EamDb dbInstance;
try {
dbInstance = EamDb.getInstance();
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Unable to connect to the Central Repository database.", ex); //NON-NLS
return false;
}
Map<String, CorrelationCase> uniqueCaseMap = new HashMap<>();
accounts.forEach((account) -> {
try {
CorrelationAttributeInstance.Type correlationType = getCorrelationType(account.getAccountType());
if (correlationType != null) {
List<CorrelationAttributeInstance> correlationInstances = dbInstance.getArtifactInstancesByTypeValue(correlationType, account.getTypeSpecificID());
correlationInstances.forEach((correlationInstance) -> {
CorrelationCase correlationCase = correlationInstance.getCorrelationCase();
uniqueCaseMap.put(correlationCase.getCaseUUID(), correlationCase);
});
}
} catch (EamDbException | CorrelationAttributeNormalizationException ex) {
logger.log(Level.WARNING, String.format("Unable to getArtifactInstance for accountID: %d", account.getAccountID()), ex); //NON-NLS
}
});
list.addAll(uniqueCaseMap.values());
return true;
}
@Override
protected Node createNodeForKey(CorrelationCase correlationCase) {
return new CaseNode(correlationCase);
}
/**
* Find the CorrelationAttributeInstance.Type for the given Account.Type.
*
* @param accountType Account type
*
* @return CorrelationAttributeInstance.Type for given account or null if
* there is no match
*
* @throws EamDbException
*/
private CorrelationAttributeInstance.Type getCorrelationType(Account.Type accountType) throws EamDbException {
if (correlationTypeMap == null) {
correlationTypeMap = new HashMap<>();
List<CorrelationAttributeInstance.Type> correcationTypeList = CorrelationAttributeInstance.getDefaultCorrelationTypes();
correcationTypeList.forEach((type) -> {
correlationTypeMap.put(type.getId(), type);
});
}
if (Account.Type.EMAIL.equals(accountType)) {
return correlationTypeMap.get(CorrelationAttributeInstance.EMAIL_TYPE_ID);
} else if (Account.Type.PHONE.equals(accountType)) {
return correlationTypeMap.get(CorrelationAttributeInstance.PHONE_TYPE_ID);
} else {
return null;
}
}
/**
* Simple AbstractNode for a CorrelationCase. The property sheet only
* contains the creation date.
*/
final class CaseNode extends AbstractNode {
private final CorrelationCase correlationCase;
/**
* Construct the object, set the display name and icon.
*
* @param correlationCase
*/
CaseNode(CorrelationCase correlationCase) {
super(Children.LEAF);
this.correlationCase = correlationCase;
setDisplayName(correlationCase.getDisplayName());
setIconBaseWithExtension("org/sleuthkit/autopsy/images/briefcase.png"); //NON-NLS
}
@Override
protected Sheet createSheet() {
super.createSheet();
Sheet sheet = new Sheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
sheetSet.put(new NodeProperty<>("creationDate", //NON-NLS
correlationCase.getTitleCreationDate(),
correlationCase.getTitleCreationDate(),
correlationCase.getCreationDate()));
return sheet;
}
}
}

View File

@ -0,0 +1,68 @@
<?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">
<Component id="thumbnailViewer" alignment="1" max="32767" attributes="0"/>
<Component id="contentViewer" alignment="1" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="separator" max="32767" attributes="0"/>
<EmptySpace 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="thumbnailViewer" pref="350" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="separator" min="-2" pref="2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="contentViewer" min="-2" pref="450" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail" name="thumbnailViewer">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[350, 102]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[450, 400]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail(tableEM)"/>
</AuxValues>
</Component>
<Component class="org.sleuthkit.autopsy.contentviewers.MessageContentViewer" name="contentViewer">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[450, 400]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MessageDataContent()"/>
</AuxValues>
</Component>
<Component class="javax.swing.JSeparator" name="separator">
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,233 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obt ain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.awt.Component;
import java.awt.KeyboardFocusManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import javax.swing.JPanel;
import static javax.swing.SwingUtilities.isDescendingFrom;
import org.openide.explorer.ExplorerManager;
import static org.openide.explorer.ExplorerUtils.createLookup;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
import org.sleuthkit.datamodel.AbstractContent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A Panel that shows the media (thumbnails) for the selected account.
*/
final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerManager.Provider, Lookup.Provider {
private static final Logger logger = Logger.getLogger(MediaViewer.class.getName());
private final ExplorerManager tableEM = new ExplorerManager();
private final PropertyChangeListener focusPropertyListener;
private final ModifiableProxyLookup proxyLookup;
@Messages({
"MediaViewer_Name=Media"
})
/**
* Creates new form ThumbnailViewer
*/
public MediaViewer() {
proxyLookup = new ModifiableProxyLookup(createLookup(tableEM, getActionMap()));
// See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
// explaination of focusPropertyListener
focusPropertyListener = (final PropertyChangeEvent focusEvent) -> {
if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
final Component newFocusOwner = (Component) focusEvent.getNewValue();
if (newFocusOwner == null) {
return;
}
if (isDescendingFrom(newFocusOwner, contentViewer)) {
//if the focus owner is within the MessageContentViewer (the attachments table)
proxyLookup.setNewLookups(createLookup(((MessageDataContent) contentViewer).getExplorerManager(), getActionMap()));
} else if (isDescendingFrom(newFocusOwner, MediaViewer.this)) {
//... or if it is within the Results table.
proxyLookup.setNewLookups(createLookup(tableEM, getActionMap()));
}
}
};
initComponents();
tableEM.addPropertyChangeListener((PropertyChangeEvent evt) -> {
if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
handleNodeSelectionChange();
}
});
thumbnailViewer.resetComponent();
}
@Override
public String getDisplayName() {
return Bundle.MediaViewer_Name();
}
@Override
public JPanel getPanel() {
return this;
}
@Override
public void setSelectionInfo(SelectionInfo info) {
final Set<Content> relationshipSources;
CommunicationsManager communicationManager;
Set<BlackboardArtifact> artifactList = new HashSet<>();
try {
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
relationshipSources = communicationManager.getRelationshipSources(info.getAccountDevicesInstances(), info.getCommunicationsFilter());
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
artifactList.add((BlackboardArtifact) content);
});
} catch (TskCoreException | NoCurrentCaseException ex) {
logger.log(Level.WARNING, "Unable to update selection." , ex);
}
if(artifactList.size() == 0) {
thumbnailViewer.resetComponent();
}
thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(new AttachmentsChildren(artifactList)), tableEM), true, this.getClass().getName()));
}
@Override
public ExplorerManager getExplorerManager() {
return tableEM;
}
@Override
public Lookup getLookup() {
return proxyLookup;
}
@Override
public void addNotify() {
super.addNotify();
//add listener that maintains correct selection in the Global Actions Context
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addPropertyChangeListener("focusOwner", focusPropertyListener);
}
@Override
public void removeNotify() {
super.removeNotify();
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.removePropertyChangeListener("focusOwner", focusPropertyListener);
}
/**
* Handle the change in thumbnail node selection.
*/
private void handleNodeSelectionChange() {
final Node[] nodes = tableEM.getSelectedNodes();
if (nodes != null && nodes.length == 1) {
AbstractContent thumbnail = nodes[0].getLookup().lookup(AbstractContent.class);
if (thumbnail != null) {
try {
Content parentContent = thumbnail.getParent();
if (parentContent != null && parentContent instanceof BlackboardArtifact) {
contentViewer.setNode(new BlackboardArtifactNode((BlackboardArtifact) parentContent));
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Unable to get parent Content from AbstraceContent instance.", ex); //NON-NLS
}
}
} else {
contentViewer.setNode(null);
}
}
/**
* 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() {
thumbnailViewer = new org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail(tableEM);
contentViewer = new MessageDataContent();
separator = new javax.swing.JSeparator();
thumbnailViewer.setMinimumSize(new java.awt.Dimension(350, 102));
thumbnailViewer.setPreferredSize(new java.awt.Dimension(450, 400));
contentViewer.setPreferredSize(new java.awt.Dimension(450, 400));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(thumbnailViewer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(contentViewer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(separator)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(thumbnailViewer, javax.swing.GroupLayout.DEFAULT_SIZE, 350, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(contentViewer, javax.swing.GroupLayout.PREFERRED_SIZE, 450, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(3, 3, 3))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer contentViewer;
private javax.swing.JSeparator separator;
private org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail thumbnailViewer;
// End of variables declaration//GEN-END:variables
}

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications;
package org.sleuthkit.autopsy.communications.relationships;
import java.beans.PropertyChangeEvent;
import org.openide.explorer.ExplorerManager;

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017-2018 Basis Technology Corp.
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications;
package org.sleuthkit.autopsy.communications.relationships;
import java.util.List;
import java.util.TimeZone;
@ -25,12 +25,12 @@ import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.openide.util.NbBundle.Messages;
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;
@ -43,24 +43,35 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBU
import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.datamodel.TimeUtilities;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.communications.Utils;
/**
* Node for a relationship, as represented by a BlackboardArtifact.
* Wraps a BlackboardArtifact as an AbstractNode for use in an OutlookView
*/
final class RelationshipNode extends BlackboardArtifactNode {
final class MessageNode extends BlackboardArtifactNode {
private static final Logger logger = Logger.getLogger(RelationshipNode.class.getName());
private static final Logger logger = Logger.getLogger(MessageNode.class.getName());
RelationshipNode(BlackboardArtifact artifact) {
MessageNode(BlackboardArtifact artifact) {
super(artifact);
final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s");
String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message");
final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s"); // NON-NLS
String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message"); // NON-NLS
setDisplayName(removeEndIgnoreCase.isEmpty() ? stripEnd : removeEndIgnoreCase);
}
@Messages({
"MessageNode_Node_Property_Type=Type",
"MessageNode_Node_Property_From=From",
"MessageNode_Node_Property_To=To",
"MessageNode_Node_Property_Date=Date",
"MessageNode_Node_Property_Subject=Subject",
"MessageNode_Node_Property_Attms=Attachments"
})
@Override
protected Sheet createSheet() {
Sheet sheet = new Sheet();
Sheet sheet = super.createSheet();
List<Tag> tags = getAllTagsFromDatabase();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
@ -68,62 +79,63 @@ final class RelationshipNode extends BlackboardArtifactNode {
sheet.put(sheetSet);
}
sheetSet.put(new NodeProperty<>("Type", "Type", "Type", getDisplayName()));
sheetSet.put(new NodeProperty<>("Type", Bundle.MessageNode_Node_Property_Type(), "", getDisplayName())); //NON-NLS
addScoreProperty(sheetSet, tags);
CorrelationAttributeInstance correlationAttribute = null;
if (UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
correlationAttribute = getCorrelationAttributeInstance();
}
addCommentProperty(sheetSet, tags, correlationAttribute);
if (UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
addCountProperty(sheetSet, correlationAttribute);
}
final BlackboardArtifact artifact = getArtifact();
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(getArtifact().getArtifactTypeID());
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
if (null != fromID) {
//Consider refactoring this to reduce boilerplate
switch (fromID) {
case TSK_EMAIL_MSG:
sheetSet.put(new NodeProperty<>("From", "From", "From",
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_FROM), " \t\n;")));
sheetSet.put(new NodeProperty<>("To", "To", "To",
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_TO), " \t\n;")));
sheetSet.put(new NodeProperty<>("Date", "Date", "Date",
getAttributeDisplayString(artifact, TSK_DATETIME_SENT)));
sheetSet.put(new NodeProperty<>("Subject", "Subject", "Subject",
getAttributeDisplayString(artifact, TSK_SUBJECT)));
sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "",
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_FROM), " \t\n;"))); //NON-NLS
sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "",
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_TO), " \t\n;"))); //NON-NLS
sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "",
getAttributeDisplayString(artifact, TSK_DATETIME_SENT))); //NON-NLS
sheetSet.put(new NodeProperty<>("Subject", Bundle.MessageNode_Node_Property_Subject(), "",
getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS
try {
sheetSet.put(new NodeProperty<>("Attms", "Attms", "Attms", artifact.getChildrenCount()));
sheetSet.put(new NodeProperty<>("Attms", Bundle.MessageNode_Node_Property_Attms(), "", artifact.getChildrenCount())); //NON-NLS
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex);
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS
}
break;
case TSK_MESSAGE:
sheetSet.put(new NodeProperty<>("From", "From", "From",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM)));
sheetSet.put(new NodeProperty<>("To", "To", "To",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO)));
sheetSet.put(new NodeProperty<>("Date", "Date", "Date",
getAttributeDisplayString(artifact, TSK_DATETIME)));
sheetSet.put(new NodeProperty<>("Subject", "Subject", "Subject",
getAttributeDisplayString(artifact, TSK_SUBJECT)));
sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM))); //NON-NLS
sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO))); //NON-NLS
sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "",
getAttributeDisplayString(artifact, TSK_DATETIME))); //NON-NLS
sheetSet.put(new NodeProperty<>("Subject", Bundle.MessageNode_Node_Property_Subject(), "",
getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS
try {
sheetSet.put(new NodeProperty<>("Attms", "Attms", "Attms", artifact.getChildrenCount()));
sheetSet.put(new NodeProperty<>("Attms", Bundle.MessageNode_Node_Property_Attms(), "", artifact.getChildrenCount())); //NON-NLS
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex);
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS
}
break;
case TSK_CALLLOG:
sheetSet.put(new NodeProperty<>("From", "From", "From",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM)));
sheetSet.put(new NodeProperty<>("To", "To", "To",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO)));
sheetSet.put(new NodeProperty<>("Date", "Date", "Date",
getAttributeDisplayString(artifact, TSK_DATETIME_START)));
sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM))); //NON-NLS
sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "",
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO))); //NON-NLS
sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "",
getAttributeDisplayString(artifact, TSK_DATETIME_START))); //NON-NLS
break;
default:
break;
@ -144,7 +156,7 @@ final class RelationshipNode extends BlackboardArtifactNode {
* @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) {
private static String getAttributeDisplayString(final BlackboardArtifact artifact, final BlackboardAttribute.ATTRIBUTE_TYPE attributeType) {
try {
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(attributeType.getTypeID())));
if (attribute == null) {
@ -156,7 +168,7 @@ final class RelationshipNode extends BlackboardArtifactNode {
return attribute.getDisplayString();
}
} catch (TskCoreException tskCoreException) {
logger.log(Level.WARNING, "Error getting attribute value.", tskCoreException);
logger.log(Level.WARNING, "Error getting attribute value.", tskCoreException); //NON-NLS
return "";
}
}

View File

@ -0,0 +1,115 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
* ChildFactory that creates createKeys and nodes from a given selectionInfo for
* only emails, call logs and messages.
*
*/
final class MessagesChildNodeFactory extends ChildFactory<BlackboardArtifact> {
private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName());
private SelectionInfo selectionInfo;
/**
* Construct a new MessageChildNodeFactory from the currently selectionInfo
*
* @param selectionInfo SelectionInfo object for the currently selected
* accounts
*/
MessagesChildNodeFactory(SelectionInfo selectionInfo) {
this.selectionInfo = selectionInfo;
}
/**
* Updates the current instance of selectionInfo and calls the refresh method.
*
* @param selectionInfo New instance of the currently selected accounts
*/
public void refresh(SelectionInfo selectionInfo) {
this.selectionInfo = selectionInfo;
refresh(true);
}
/**
* Creates a list of Keys (BlackboardArtifact) for only messages for the
* currently selected accounts
*
* @param list List of BlackboardArtifact to populate
*
* @return True on success
*/
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
CommunicationsManager communicationManager;
try {
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
} catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS
return false;
}
if(selectionInfo == null) {
return true;
}
final Set<Content> relationshipSources;
try {
relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter());
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
BlackboardArtifact bba = (BlackboardArtifact) content;
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID());
if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG
|| fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG
|| fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) {
list.add(bba);
}
});
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS
}
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact key) {
return new MessageNode(key);
}
}

View File

@ -0,0 +1,42 @@
<?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">
<Component id="outlineView" alignment="0" max="32767" attributes="0"/>
<Component id="contentViewer" alignment="1" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="outlineView" pref="300" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="contentViewer" pref="500" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="org.openide.explorer.view.OutlineView" name="outlineView">
</Component>
<Component class="org.sleuthkit.autopsy.contentviewers.MessageContentViewer" name="contentViewer">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MessageDataContent()"/>
</AuxValues>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,194 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obt ain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.awt.Component;
import java.awt.KeyboardFocusManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JPanel;
import javax.swing.ListSelectionModel;
import static javax.swing.SwingUtilities.isDescendingFrom;
import org.netbeans.swing.outline.DefaultOutlineModel;
import org.netbeans.swing.outline.Outline;
import org.openide.explorer.ExplorerManager;
import static org.openide.explorer.ExplorerUtils.createLookup;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
/**
* Visualation for the messages of the currently selected accounts.
*/
@ServiceProvider(service = RelationshipsViewer.class)
public final class MessagesViewer extends JPanel implements RelationshipsViewer, ExplorerManager.Provider, Lookup.Provider {
private final ExplorerManager tableEM;
private final Outline outline;
private final ModifiableProxyLookup proxyLookup;
private final PropertyChangeListener focusPropertyListener;
private final MessagesChildNodeFactory nodeFactory;
@Messages({
"MessageViewer_tabTitle=Messages",
"MessageViewer_columnHeader_From=From",
"MessageViewer_columnHeader_To=To",
"MessageViewer_columnHeader_Date=Date",
"MessageViewer_columnHeader_Subject=Subject",
"MessageViewer_columnHeader_Attms=Attachments"
})
/**
* Visualation for the messages of the currently selected accounts.
*/
public MessagesViewer() {
tableEM = new ExplorerManager();
proxyLookup = new ModifiableProxyLookup(createLookup(tableEM, getActionMap()));
nodeFactory = new MessagesChildNodeFactory(null);
// See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
// explaination of focusPropertyListener
focusPropertyListener = (final PropertyChangeEvent focusEvent) -> {
if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
final Component newFocusOwner = (Component) focusEvent.getNewValue();
if (newFocusOwner == null) {
return;
}
if (isDescendingFrom(newFocusOwner, contentViewer)) {
//if the focus owner is within the MessageContentViewer (the attachments table)
proxyLookup.setNewLookups(createLookup(((MessageDataContent) contentViewer).getExplorerManager(), getActionMap()));
} else if (isDescendingFrom(newFocusOwner, MessagesViewer.this)) {
//... or if it is within the Results table.
proxyLookup.setNewLookups(createLookup(tableEM, getActionMap()));
}
}
};
initComponents();
outline = outlineView.getOutline();
outlineView.setPropertyColumns(
"From", Bundle.MessageViewer_columnHeader_From(),
"To", Bundle.MessageViewer_columnHeader_To(),
"Date", Bundle.MessageViewer_columnHeader_Date(),
"Subject", Bundle.MessageViewer_columnHeader_Subject(),
"Attms", Bundle.MessageViewer_columnHeader_Attms(),
"Type", "Type"
);
outline.setRootVisible(false);
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel("Type");
tableEM.addPropertyChangeListener((PropertyChangeEvent evt) -> {
if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
final Node[] nodes = tableEM.getSelectedNodes();
if (nodes != null && nodes.length == 1) {
contentViewer.setNode(nodes[0]);
}
else {
contentViewer.setNode(null);
}
}
});
tableEM.setRootContext(new TableFilterNode(new DataResultFilterNode(new AbstractNode(Children.create(nodeFactory, true)), getExplorerManager()), true));
}
@Override
public String getDisplayName() {
return Bundle.MessageViewer_tabTitle();
}
@Override
public JPanel getPanel() {
return this;
}
@Override
public void setSelectionInfo(SelectionInfo info) {
nodeFactory.refresh(info);
}
@Override
public ExplorerManager getExplorerManager() {
return tableEM;
}
@Override
public Lookup getLookup() {
return proxyLookup;
}
@Override
public void addNotify() {
super.addNotify();
//add listener that maintains correct selection in the Global Actions Context
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addPropertyChangeListener("focusOwner", focusPropertyListener);
}
@Override
public void removeNotify() {
super.removeNotify();
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.removePropertyChangeListener("focusOwner", focusPropertyListener);
}
/**
* 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();
contentViewer = new MessageDataContent();
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(contentViewer, javax.swing.GroupLayout.Alignment.TRAILING, 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()
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(contentViewer, javax.swing.GroupLayout.DEFAULT_SIZE, 500, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer contentViewer;
private org.openide.explorer.view.OutlineView outlineView;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,60 @@
<?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"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,-45,0,0,1,-32"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignCardLayout">
<Property name="horizontalGap" type="int" value="5"/>
<Property name="verticalGap" type="int" value="5"/>
</Layout>
<SubComponents>
<Component class="org.openide.explorer.view.OutlineView" name="outlineView">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[300, 400]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
<CardConstraints cardName="outlineCard"/>
</Constraint>
</Constraints>
</Component>
<Container class="javax.swing.JPanel" name="messagePanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
<CardConstraints cardName="messageCard"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="messageLabel">
<Properties>
<Property name="horizontalAlignment" type="int" value="0"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="OutlineViewPanel.messageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,132 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obt ain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.awt.CardLayout;
import org.openide.explorer.ExplorerManager;
import static org.openide.explorer.ExplorerUtils.createLookup;
import org.openide.explorer.view.OutlineView;
import org.openide.nodes.Node;;
import org.openide.util.Lookup;
/**
* This class is a simple wrapper around a OutlineView with its own ExplorerManager.
*
* This panel has the added feature of being able to hide the OutlineView and show
* a message.
*
*/
public class OutlineViewPanel extends javax.swing.JPanel implements ExplorerManager.Provider, Lookup.Provider{
private final ExplorerManager tableEm;
private final Lookup lookup;
/**
* Creates new form OutlineViewPanel
*/
public OutlineViewPanel() {
tableEm = new ExplorerManager();
lookup = createLookup(tableEm, getActionMap());
initComponents();
}
@Override
public ExplorerManager getExplorerManager() {
return tableEm;
}
@Override
public Lookup getLookup() {
return lookup;
}
/**
* Hide the OutlineView and replace with a panel with the given message.
*
* @param message String message to show on the panel.
*/
public void hideOutlineView(String message) {
CardLayout layout = (CardLayout)this.getLayout();
layout.show(this, "messageCard"); //NON-NLS
messageLabel.setText(message);
}
/**
* Hides the message panel and shows the OutlineView.
*/
public void showOutlineView() {
CardLayout layout = (CardLayout)this.getLayout();
layout.show(this, "outlineCard"); //NON-NLS
}
/**
* Returns the OutlineView instance for ease of customization.
*
* @return Returns the OutlineView
*/
public OutlineView getOutlineView() {
return outlineView;
}
public void setNode(Node node) {
tableEm.setRootContext(node);
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
outlineView.setEnabled(enabled);
}
/**
* 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();
messagePanel = new javax.swing.JPanel();
messageLabel = new javax.swing.JLabel();
setLayout(new java.awt.CardLayout(5, 5));
outlineView.setPreferredSize(new java.awt.Dimension(300, 400));
add(outlineView, "outlineCard");
messagePanel.setLayout(new java.awt.BorderLayout());
messageLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
org.openide.awt.Mnemonics.setLocalizedText(messageLabel, org.openide.util.NbBundle.getMessage(OutlineViewPanel.class, "OutlineViewPanel.messageLabel.text")); // NOI18N
messageLabel.setEnabled(false);
messagePanel.add(messageLabel, java.awt.BorderLayout.CENTER);
add(messagePanel, "messageCard");
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel messageLabel;
private javax.swing.JPanel messagePanel;
private org.openide.explorer.view.OutlineView outlineView;
// End of variables declaration//GEN-END:variables
}

View File

@ -5,7 +5,7 @@
<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_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"/>
@ -16,40 +16,36 @@
<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"/>
<EmptySpace min="0" pref="400" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="scrollPane" alignment="1" 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"/>
<EmptySpace min="0" pref="300" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="scrollPane" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="splitPane">
<Container class="javax.swing.JScrollPane" name="scrollPane">
<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"/>
<Property name="verticalScrollBarPolicy" type="int" value="21"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<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>
<Container class="javax.swing.JTabbedPane" name="tabPane">
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="tabPaneStateChanged"/>
</Events>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
</Container>
</SubComponents>
</Container>
</SubComponents>

View File

@ -0,0 +1,132 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obt ain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.awt.Component;
import javax.swing.JPanel;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
/**
* Displays the Relationship information for the currently selected accounts.
*
*/
public final class RelationshipBrowser extends JPanel implements Lookup.Provider {
private SelectionInfo currentSelection;
private final MessagesViewer messagesViewer;
private final ContactsViewer contactsViewer;
private final SummaryViewer summaryViewer;
private final MediaViewer mediaViewer;
private final ModifiableProxyLookup proxyLookup;
/**
* Creates new form RelationshipBrowser
*/
public RelationshipBrowser() {
messagesViewer = new MessagesViewer();
contactsViewer = new ContactsViewer();
summaryViewer = new SummaryViewer();
mediaViewer = new MediaViewer();
proxyLookup = new ModifiableProxyLookup(messagesViewer.getLookup());
initComponents();
tabPane.add(summaryViewer.getDisplayName(), summaryViewer);
tabPane.add(messagesViewer.getDisplayName(), messagesViewer);
tabPane.add(contactsViewer.getDisplayName(), contactsViewer);
tabPane.add(mediaViewer.getDisplayName(), mediaViewer);
}
/**
* Sets the value of currentSelection and passes the SelectionInfo onto the
* currently selected\visible tab.
*
* @param info Currently selected account nodes
*/
public void setSelectionInfo(SelectionInfo info) {
currentSelection = info;
((RelationshipsViewer) tabPane.getSelectedComponent()).setSelectionInfo(info);
}
/**
* 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() {
scrollPane = new javax.swing.JScrollPane();
tabPane = new javax.swing.JTabbedPane();
scrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
tabPane.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
tabPaneStateChanged(evt);
}
});
scrollPane.setViewportView(tabPane);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(scrollPane, javax.swing.GroupLayout.Alignment.TRAILING))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(scrollPane))
);
}// </editor-fold>//GEN-END:initComponents
private void tabPaneStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tabPaneStateChanged
if(currentSelection != null) {
((RelationshipsViewer) tabPane.getSelectedComponent()).setSelectionInfo(currentSelection);
}
Component selectedComponent = tabPane.getSelectedComponent();
if(selectedComponent instanceof Lookup.Provider) {
Lookup lookup = ((Lookup.Provider)selectedComponent).getLookup();
proxyLookup.setNewLookups(lookup);
}
}//GEN-LAST:event_tabPaneStateChanged
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JScrollPane scrollPane;
private javax.swing.JTabbedPane tabPane;
// End of variables declaration//GEN-END:variables
@Override
public Lookup getLookup() {
return proxyLookup;
}
}

View File

@ -0,0 +1,50 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obt ain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import javax.swing.JPanel;
import org.openide.util.Lookup;
/**
* Interface for Controls wishing to appear in the RelationshipBrowser tabPane.
*/
public interface RelationshipsViewer extends Lookup.Provider {
/**
* Returns the value to be displayed on the "tab"
*
* @return String display name
*/
public String getDisplayName();
/**
* Returns the JPanel to be displayed in the RelationshipBrowser.
*
* @return JPanel to be displayed
*/
public JPanel getPanel();
/**
* Sets current SelectionInfo allowing the panel to update accordingly.
*
* @param info SelectionInfo instance representing the currently selected
* accounts
*/
public void setSelectionInfo(SelectionInfo info);
}

View File

@ -0,0 +1,185 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obt ain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.AccountDeviceInstance;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.CommunicationsFilter;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Class to wrap the details of the current selection from the AccountBrowser or
* VisualizationPane
*/
public final class SelectionInfo {
private static final Logger logger = Logger.getLogger(SelectionInfo.class.getName());
private final Set<AccountDeviceInstance> accountDeviceInstances;
private final CommunicationsFilter communicationFilter;
private final Set<Account> accounts;
private Set<BlackboardArtifact> accountArtifacts = null;
private SelectionSummary summary = null;
/**
* Wraps the details of the currently selected accounts.
*
* @param accountDeviceInstances Selected accountDecivedInstances
* @param communicationFilter Currently selected communications filters
*/
public SelectionInfo(Set<AccountDeviceInstance> accountDeviceInstances, CommunicationsFilter communicationFilter) {
this.accountDeviceInstances = accountDeviceInstances;
this.communicationFilter = communicationFilter;
accounts = new HashSet<>();
accountDeviceInstances.forEach((instance) -> {
accounts.add(instance.getAccount());
});
}
/**
* Returns the currently selected accountDeviceInstances
*
* @return Set of AccountDeviceInstance
*/
public Set<AccountDeviceInstance> getAccountDevicesInstances() {
return accountDeviceInstances;
}
/**
* Returns the currently selected communications filters.
*
* @return Instance of CommunicationsFilter
*/
public CommunicationsFilter getCommunicationsFilter() {
return communicationFilter;
}
public Set<Account> getAccounts() {
return accounts;
}
public Set<BlackboardArtifact> getArtifacts() {
if(accountArtifacts == null) {
accountArtifacts = new HashSet<>();
CommunicationsManager communicationManager;
try {
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
} catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS
return null;
}
final Set<Content> relationshipSources;
try {
relationshipSources = communicationManager.getRelationshipSources(getAccountDevicesInstances(), getCommunicationsFilter());
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
accountArtifacts.add((BlackboardArtifact) content);
});
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS
}
}
return accountArtifacts;
}
public SelectionSummary getSummary() {
if(summary == null) {
summary = new SelectionSummary();
}
return summary;
}
final class SelectionSummary{
int attachmentCnt;
int messagesCnt;
int emailCnt;
int callLogCnt;
int contactsCnt;
SelectionSummary() {
getCounts();
}
private void getCounts(){
for(BlackboardArtifact artifact: getArtifacts()) {
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
if(null != fromID) switch (fromID) {
case TSK_EMAIL_MSG:
emailCnt++;
break;
case TSK_CALLLOG:
callLogCnt++;
break;
case TSK_MESSAGE:
messagesCnt++;
break;
case TSK_CONTACT:
contactsCnt++;
break;
default:
break;
}
try{
attachmentCnt+= artifact.getChildrenCount();
} catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Exception thrown "
+ "from getChildrenCount artifactID: %d",
artifact.getArtifactID()), ex); //NON-NLS
}
}
}
public int getAttachmentCnt() {
return attachmentCnt;
}
public int getMessagesCnt() {
return messagesCnt;
}
public int getEmailCnt() {
return emailCnt;
}
public int getCallLogCnt() {
return callLogCnt;
}
public int getContactsCnt() {
return contactsCnt;
}
}
}

View File

@ -0,0 +1,215 @@
<?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" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="countsPanel" max="32767" attributes="0"/>
<Component id="fileReferencesPanel" alignment="0" pref="485" max="32767" attributes="0"/>
<Component id="caseReferencesPanel" alignment="1" max="32767" attributes="0"/>
</Group>
<EmptySpace 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 max="-2" attributes="0"/>
<Component id="countsPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="fileReferencesPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="caseReferencesPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="countsPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Counts">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.countsPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="attachmentsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="messagesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="callLogsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="contactsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="emailLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="emailDataLabel" min="-2" max="-2" attributes="0"/>
<Component id="contactsDataLabel" min="-2" max="-2" attributes="0"/>
<Component id="callLogsDataLabel" min="-2" max="-2" attributes="0"/>
<Component id="messagesDataLabel" min="-2" max="-2" attributes="0"/>
<Component id="attachmentsDataLabel" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace 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="7" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="attachmentsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="attachmentsDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="messagesLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="messagesDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="callLogsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="callLogsDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="contactsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="contactsDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="emailLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="emailDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="emailLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.emailLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="contactsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="SummaryViewer.contactsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="messagesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.messagesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="callLogsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.callLogsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="attachmentsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.attachmentsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="attachmentsDataLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.attachmentsDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="messagesDataLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.messagesDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="callLogsDataLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.callLogsDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="contactsDataLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.contactsDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="emailDataLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.emailDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="org.sleuthkit.autopsy.communications.OutlineViewPanel" name="fileReferencesPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="File References in Current Case">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.fileReferencesPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[472, 300]"/>
</Property>
</Properties>
</Component>
<Component class="org.sleuthkit.autopsy.communications.OutlineViewPanel" name="caseReferencesPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Other Occurrences">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.caseReferencesPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[472, 300]"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,313 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obt ain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.util.Set;
import javax.swing.JPanel;
import org.netbeans.swing.outline.DefaultOutlineModel;
import org.netbeans.swing.outline.Outline;
import org.openide.explorer.view.OutlineView;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.communications.relationships.SelectionInfo.SelectionSummary;
import org.sleuthkit.datamodel.Account;
/**
* Account Summary View Panel. This panel shows a list of various counts related
* to the currently selected account. As well has a panel showing a list of
* cases and files that reference the account.
*
*/
public class SummaryViewer extends javax.swing.JPanel implements RelationshipsViewer {
private final Lookup lookup;
@Messages({
"SummaryViewer_TabTitle=Summary",
"SummaryViewer_FileRefNameColumn_Title=Path",
"SummaryViewer_CaseRefNameColumn_Title=Case Name",
"SummaryViewer_CentralRepository_Message=<Enable Central Resposity to see Case References>",
"SummaryViewer_Creation_Date_Title=Creation Date"
})
/**
* Creates new form SummaryViewer
*/
public SummaryViewer() {
lookup = Lookup.getDefault();
initComponents();
OutlineView outlineView = fileReferencesPanel.getOutlineView();
Outline outline = outlineView.getOutline();
outline.setRootVisible(false);
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.SummaryViewer_FileRefNameColumn_Title());
outlineView = caseReferencesPanel.getOutlineView();
outline = outlineView.getOutline();
outlineView.setPropertyColumns("creationDate", Bundle.SummaryViewer_Creation_Date_Title()); //NON-NLS
outline.setRootVisible(false);
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.SummaryViewer_CaseRefNameColumn_Title());
clearControls();
}
@Override
public String getDisplayName() {
return Bundle.SummaryViewer_TabTitle();
}
@Override
public JPanel getPanel() {
return this;
}
@Override
public void setSelectionInfo(SelectionInfo info) {
if (!EamDb.isEnabled()) {
caseReferencesPanel.hideOutlineView(Bundle.SummaryViewer_CentralRepository_Message());
} else {
caseReferencesPanel.showOutlineView();
}
// Request is that the SummaryViewer only show information if one
// account is selected
if (info.getAccounts().size() != 1) {
setEnabled(false);
clearControls();
} else {
SelectionSummary summaryDetails = info.getSummary();
attachmentsDataLabel.setText(Integer.toString(summaryDetails.getAttachmentCnt()));
callLogsDataLabel.setText(Integer.toString(summaryDetails.getCallLogCnt()));
contactsDataLabel.setText(Integer.toString(summaryDetails.getContactsCnt()));
emailDataLabel.setText(Integer.toString(summaryDetails.getEmailCnt()));
messagesDataLabel.setText(Integer.toString(summaryDetails.getMessagesCnt()));
fileReferencesPanel.setNode(new AbstractNode(Children.create(new AccountSourceContentChildNodeFactory(info.getAccounts()), true)));
caseReferencesPanel.setNode(new AbstractNode(Children.create(new CorrelationCaseChildNodeFactory(info.getAccounts()), true)));
setEnabled(true);
}
}
@Override
public Lookup getLookup() {
return lookup;
}
/**
* Sets whether or not the text fields are enabled.
*
* @param enabled true if this component should be enabled, false otherwise
*/
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
attachmentsLabel.setEnabled(enabled);
callLogsLabel.setEnabled(enabled);
contactsLabel.setEnabled(enabled);
emailLabel.setEnabled(enabled);
messagesLabel.setEnabled(enabled);
caseReferencesPanel.setEnabled(enabled);
fileReferencesPanel.setEnabled(enabled);
countsPanel.setEnabled(enabled);
}
/**
* Clears the text fields and OutlookViews.
*/
private void clearControls() {
attachmentsDataLabel.setText("");
callLogsDataLabel.setText("");
contactsDataLabel.setText("");
emailDataLabel.setText("");
messagesDataLabel.setText("");
fileReferencesPanel.setNode(new AbstractNode(Children.LEAF));
caseReferencesPanel.setNode(new AbstractNode(Children.LEAF));
}
/**
* For the given accounts create a comma separated string of all of the
* names (TypeSpecificID).
*
* @param accounts Set of selected accounts
*
* @return String listing the account names
*/
private String createAccountLabel(Set<Account> accounts) {
StringBuilder buffer = new StringBuilder();
accounts.stream().map((account) -> {
buffer.append(account.getTypeSpecificID());
return account;
}).forEachOrdered((_item) -> {
buffer.append(", ");
});
return buffer.toString().substring(0, buffer.length() - 2);
}
/**
* 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() {
countsPanel = new javax.swing.JPanel();
emailLabel = new javax.swing.JLabel();
contactsLabel = new javax.swing.JLabel();
messagesLabel = new javax.swing.JLabel();
callLogsLabel = new javax.swing.JLabel();
attachmentsLabel = new javax.swing.JLabel();
attachmentsDataLabel = new javax.swing.JLabel();
messagesDataLabel = new javax.swing.JLabel();
callLogsDataLabel = new javax.swing.JLabel();
contactsDataLabel = new javax.swing.JLabel();
emailDataLabel = new javax.swing.JLabel();
fileReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
caseReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
countsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.countsPanel.border.title"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(emailLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.emailLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(contactsLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.contactsLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(messagesLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.messagesLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(callLogsLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.callLogsLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(attachmentsLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.attachmentsLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(attachmentsDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.attachmentsDataLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(messagesDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.messagesDataLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(callLogsDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.callLogsDataLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(contactsDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.contactsDataLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(emailDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.emailDataLabel.text")); // NOI18N
javax.swing.GroupLayout countsPanelLayout = new javax.swing.GroupLayout(countsPanel);
countsPanel.setLayout(countsPanelLayout);
countsPanelLayout.setHorizontalGroup(
countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(countsPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(attachmentsLabel)
.addComponent(messagesLabel)
.addComponent(callLogsLabel)
.addComponent(contactsLabel)
.addComponent(emailLabel))
.addGap(18, 18, 18)
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(emailDataLabel)
.addComponent(contactsDataLabel)
.addComponent(callLogsDataLabel)
.addComponent(messagesDataLabel)
.addComponent(attachmentsDataLabel))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
countsPanelLayout.setVerticalGroup(
countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(countsPanelLayout.createSequentialGroup()
.addGap(7, 7, 7)
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(attachmentsLabel)
.addComponent(attachmentsDataLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(messagesLabel)
.addComponent(messagesDataLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(callLogsLabel)
.addComponent(callLogsDataLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(contactsLabel)
.addComponent(contactsDataLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(emailLabel)
.addComponent(emailDataLabel))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
fileReferencesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.fileReferencesPanel.border.title"))); // NOI18N
fileReferencesPanel.setPreferredSize(new java.awt.Dimension(472, 300));
caseReferencesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.caseReferencesPanel.border.title"))); // NOI18N
caseReferencesPanel.setPreferredSize(new java.awt.Dimension(472, 300));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(countsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(fileReferencesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 485, Short.MAX_VALUE)
.addComponent(caseReferencesPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(countsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(fileReferencesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(caseReferencesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel attachmentsDataLabel;
private javax.swing.JLabel attachmentsLabel;
private javax.swing.JLabel callLogsDataLabel;
private javax.swing.JLabel callLogsLabel;
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel caseReferencesPanel;
private javax.swing.JLabel contactsDataLabel;
private javax.swing.JLabel contactsLabel;
private javax.swing.JPanel countsPanel;
private javax.swing.JLabel emailDataLabel;
private javax.swing.JLabel emailLabel;
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel fileReferencesPanel;
private javax.swing.JLabel messagesDataLabel;
private javax.swing.JLabel messagesLabel;
// End of variables declaration//GEN-END:variables
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*s
* Licensed under the Apache License, Version 2.0 (the "License");
@ -36,6 +36,7 @@ import org.sleuthkit.datamodel.AbstractFile;
class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
private static final Logger LOGGER = Logger.getLogger(MediaFileViewer.class.getName());
private static final long serialVersionUID = 1L;
private AbstractFile lastFile;
//UI
private MediaPlayerPanel mediaPlayerPanel;
@ -48,7 +49,7 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
/**
* Creates a new MediaFileViewer.
*/
public MediaFileViewer() {
MediaFileViewer() {
initComponents();
@ -69,8 +70,8 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
private void customizeComponents() {
add(imagePanel, IMAGE_VIEWER_LAYER);
if(mediaPlayerPanel != null) {
if (mediaPlayerPanel != null) {
add(mediaPlayerPanel, MEDIA_PLAYER_LAYER);
}
@ -103,10 +104,10 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
List<String> mimeTypes = new ArrayList<>();
mimeTypes.addAll(this.imagePanel.getSupportedMimeTypes());
if(mediaPlayerPanel != null) {
if (mediaPlayerPanel != null) {
mimeTypes.addAll(this.mediaPlayerPanel.getSupportedMimeTypes());
}
return mimeTypes;
}

View File

@ -49,6 +49,10 @@ import javax.swing.JPanel;
import org.controlsfx.control.MaskerPane;
import org.openide.util.NbBundle;
import org.python.google.common.collect.Lists;
import javafx.scene.Group;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.autopsy.datamodel.FileNode;
@ -70,18 +74,20 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
private final boolean fxInited;
private JFXPanel fxPanel;
private Group imageGroup;
private ImageTaggingTool tagger;
private ImageView fxImageView;
private ScrollPane scrollPane;
private final ProgressBar progressBar = new ProgressBar();
private final MaskerPane maskerPane = new MaskerPane();
private double zoomRatio;
private double rotation; // Can be 0, 90, 180, and 270.
private static final double[] ZOOM_STEPS = {
0.0625, 0.125, 0.25, 0.375, 0.5, 0.75,
1, 1.5, 2, 2.5, 3, 4, 5, 6, 8, 10};
private static final double MIN_ZOOM_RATIO = 0.0625; // 6.25%
private static final double MAX_ZOOM_RATIO = 10.0; // 1000%
@ -115,11 +121,13 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
// build jfx ui (we could do this in FXML?)
fxImageView = new ImageView(); // will hold image
scrollPane = new ScrollPane(fxImageView); // scrolls and sizes imageview
imageGroup = new Group();
imageGroup.getChildren().add(fxImageView);
scrollPane = new ScrollPane(imageGroup); // scrolls and sizes imageview
scrollPane.getStyleClass().add("bg"); //NOI18N
scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
fxPanel = new JFXPanel(); // bridge jfx-swing
Scene scene = new Scene(scrollPane); //root of jfx tree
scene.getStylesheets().add(MediaViewImagePanel.class.getResource("MediaViewImagePanel.css").toExternalForm()); //NOI18N
@ -146,9 +154,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
Platform.runLater(() -> {
fxImageView.setViewport(new Rectangle2D(0, 0, 0, 0));
fxImageView.setImage(null);
tagger.defaultSettings();
scrollPane.setContent(null);
scrollPane.setContent(fxImageView);
scrollPane.setContent(imageGroup);
});
}
@ -160,7 +169,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
* TODO: why is the name passed into the action constructor? it
* means we duplicate this string all over the place -jm
*/ new ExternalViewerAction(Bundle.MediaViewImagePanel_externalViewerButton_text(), new FileNode(file))
.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "")) //Swing ActionEvent
.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "")) //Swing ActionEvent
);
final VBox errorNode = new VBox(10, new Label(errorMessage), externalViewerButton);
@ -199,8 +208,11 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
if (nonNull(fxImage)) {
// We have a non-null image, so let's show it.
fxImageView.setImage(fxImage);
imageGroup.getChildren().remove(tagger);
tagger = new ImageTaggingTool(fxImageView, Color.RED);
imageGroup.getChildren().add(tagger);
resetView();
scrollPane.setContent(fxImageView);
scrollPane.setContent(imageGroup);
} else {
showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
}
@ -410,7 +422,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
private void zoomInButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomInButtonActionPerformed
// Find the next zoom step.
for (int i=0; i < ZOOM_STEPS.length; i++) {
for (int i = 0; i < ZOOM_STEPS.length; i++) {
if (zoomRatio < ZOOM_STEPS[i]) {
zoomRatio = ZOOM_STEPS[i];
break;
@ -421,7 +433,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
private void zoomOutButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomOutButtonActionPerformed
// Find the next zoom step.
for (int i=ZOOM_STEPS.length-1; i >= 0; i--) {
for (int i = ZOOM_STEPS.length - 1; i >= 0; i--) {
if (zoomRatio > ZOOM_STEPS[i]) {
zoomRatio = ZOOM_STEPS[i];
break;
@ -450,12 +462,12 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
private javax.swing.JButton zoomResetButton;
private javax.swing.JTextField zoomTextField;
// End of variables declaration//GEN-END:variables
/**
* Reset the zoom and rotation values to their defaults. The zoom level gets
* defaulted to the current size of the panel. The rotation will be set to
* zero.
*
*
* Note: This method will make a call to 'updateView()' after the values
* have been reset.
*/
@ -464,28 +476,28 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
if (image == null) {
return;
}
double imageWidth = image.getWidth();
double imageHeight = image.getHeight();
double scrollPaneWidth = fxPanel.getWidth();
double scrollPaneHeight = fxPanel.getHeight();
double zoomRatioWidth = scrollPaneWidth / imageWidth;
double zoomRatioHeight = scrollPaneHeight / imageHeight;
// Use the smallest ratio size to fit the entire image in the view area.
zoomRatio = zoomRatioWidth < zoomRatioHeight ? zoomRatioWidth : zoomRatioHeight;
rotation = 0;
scrollPane.setHvalue(0);
scrollPane.setVvalue(0);
updateView();
}
/**
* Update the image to use the current zoom and rotation values.
*
*
* Note: For zoom levels less than 100%, special accomodations are made in
* order to keep the image fully visible. This is because the viewport size
* change occurs before any transforms execute, thus chopping off part of
@ -498,39 +510,39 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
if (image == null) {
return;
}
// Image dimensions
double imageWidth = image.getWidth();
double imageHeight = image.getHeight();
// Image dimensions with zooming applied
double adjustedImageWidth = imageWidth * zoomRatio;
double adjustedImageHeight = imageHeight * zoomRatio;
// ImageView viewport dimensions
double viewportWidth;
double viewportHeight;
// Panel dimensions
double panelWidth = fxPanel.getWidth();
double panelHeight = fxPanel.getHeight();
// Coordinates to center the image on the panel
double centerOffsetX = (panelWidth / 2) - (imageWidth / 2);
double centerOffsetY = (panelHeight / 2) - (imageHeight / 2);
// Coordinates to keep the image inside the left/top boundaries
double leftOffsetX;
double topOffsetY;
// Scroll bar positions
double scrollX = scrollPane.getHvalue();
double scrollY = scrollPane.getVvalue();
// Scroll bar position boundaries (work-around for viewport size bug)
double maxScrollX;
double maxScrollY;
// Set viewport size and translation offsets.
if ((rotation % 180) == 0) {
// Rotation is 0 or 180.
@ -549,7 +561,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
maxScrollX = (adjustedImageHeight - panelWidth) / (imageWidth - panelWidth);
maxScrollY = (adjustedImageWidth - panelHeight) / (imageHeight - panelHeight);
}
// Work around bug that truncates image if dimensions are too small.
if (viewportWidth < imageWidth) {
viewportWidth = imageWidth;
@ -563,7 +575,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
scrollY = maxScrollY;
}
}
// Update the viewport size.
fxImageView.setViewport(new Rectangle2D(
0, 0, viewportWidth, viewportHeight));
@ -589,9 +601,9 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
// Add the transforms in reverse order of intended execution.
// Note: They MUST be added in this order to ensure translate is
// executed last.
fxImageView.getTransforms().clear();
fxImageView.getTransforms().addAll(translate, rotate, scale);
imageGroup.getTransforms().clear();
imageGroup.getTransforms().addAll(translate, rotate, scale);
// Adjust scroll bar positions for view changes.
if (viewportWidth > fxPanel.getWidth()) {
scrollPane.setHvalue(scrollX);
@ -599,11 +611,114 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
if (viewportHeight > fxPanel.getHeight()) {
scrollPane.setVvalue(scrollY);
}
// Update all image controls to reflect the current values.
zoomOutButton.setEnabled(zoomRatio > MIN_ZOOM_RATIO);
zoomInButton.setEnabled(zoomRatio < MAX_ZOOM_RATIO);
rotationTextField.setText((int) rotation + "°");
zoomTextField.setText((Math.round(zoomRatio * 100.0)) + "%");
}
/**
* Enables users to 'tag' a region of an image by clicking and dragging a
* rectangle overtop.
*/
class ImageTaggingTool extends Rectangle {
private final double imageWidth;
private final double imageHeight;
private final double imageOriginX;
private final double imageOriginY;
//Origin of the drag event.
private double rectangleOriginX;
private double rectangleOriginY;
//Rectangle lines should be 1.5% of the image. This level of thickness has
//a good balance between visual acuity and loss of selection at the borders
//of the image.
private double lineThicknessAsPercent = 1.5;
/**
* Adds tagging support to an image, where the 'tag' rectangle will be
* the specified color.
*
* @param image Image to tag
* @param color Color of the 'tag' rectangle
*/
private ImageTaggingTool(ImageView image, Color color) {
defaultSettings();
imageWidth = image.getImage().getWidth();
imageHeight = image.getImage().getHeight();
imageOriginX = image.getX();
imageOriginY = image.getY();
setStroke(color);
setFill(color.deriveColor(0, 0, 0, 0));
//Calculate how many pixels the stroke width should be to guarentee
//a consistent % of image consumed by the rectangle border.
double min = Math.min(imageWidth, imageHeight);
double lineThicknessPixels = min * lineThicknessAsPercent / 100.0;
setStrokeWidth(lineThicknessPixels);
setVisible(false);
//Create a rectangle by left clicking on the image
image.setOnMousePressed((MouseEvent event) -> {
if (event.isSecondaryButtonDown()) {
return;
}
//Reset box on new click.
defaultSettings();
rectangleOriginX = event.getX();
rectangleOriginY = event.getY();
setX(rectangleOriginX);
setY(rectangleOriginY);
});
//Adjust the rectangle by dragging the left mouse button
image.setOnMouseDragged((MouseEvent event) -> {
if (event.isSecondaryButtonDown()) {
return;
}
/**
* Ensure the rectangle is contained within image boundaries and
* that the line thickness is kept within bounds.
*/
double newX = Math.min(Math.max(event.getX(), imageOriginX)
+ lineThicknessPixels / 2, imageWidth - lineThicknessPixels / 2);
double newY = Math.min(Math.max(event.getY(), imageOriginY)
+ lineThicknessPixels / 2, imageHeight - lineThicknessPixels / 2);
setVisible(true);
double offsetX = newX - rectangleOriginX;
if (offsetX < 0) {
setX(newX);
}
setWidth(Math.abs(offsetX));
double offsetY = newY - rectangleOriginY;
if (offsetY < 0) {
setY(newY);
}
setHeight(Math.abs(offsetY));
});
}
/**
* Reset the rectangle to default dimensions.
*/
public final void defaultSettings() {
setX(0);
setY(0);
setWidth(0);
setHeight(0);
setVisible(false);
}
}
}

View File

@ -467,6 +467,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
htmlPanel.reset();
textbodyTextArea.setText("");
msgbodyTabbedPane.setEnabled(false);
drp.setNode(null);
}
@Override
@ -561,7 +562,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
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));
new AttachmentsChildren(attachments))), true));
}
private static String wrapInHtmlBody(String htmlText) {

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 Basis Technology Corp.
* Copyright 2018-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -79,7 +79,7 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
/**
* Creates new form PListViewer
*/
public PListViewer() {
PListViewer() {
// Create an Outlineview and add to the panel
outlineView = new org.openide.explorer.view.OutlineView();
@ -193,16 +193,16 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
Case openCase;
try {
openCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
JOptionPane.showMessageDialog(this,
"Failed to export plist file.",
Bundle.PListViewer_ExportFailed_message(),
JOptionPane.ERROR_MESSAGE);
} catch (NoCurrentCaseException ex) {
JOptionPane.showMessageDialog(this,
"Failed to export plist file.",
Bundle.PListViewer_ExportFailed_message(),
JOptionPane.ERROR_MESSAGE);
logger.log(Level.SEVERE, "Exception while getting open case.", ex);
return;
logger.log(Level.SEVERE, "Exception while getting open case.", ex);
return;
}
final JFileChooser fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new File(openCase.getExportDirectory()));
fileChooser.setFileFilter(new FileNameExtensionFilter("XML file", "xml"));
@ -289,11 +289,11 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
// Read in and parse the file
final byte[] plistFileBuf = new byte[(int) plistFile.getSize()];
plistFile.read(plistFileBuf, 0, plistFile.getSize());
final List<PropKeyValue> plist = parsePList(plistFileBuf);
final List<PropKeyValue> plist = parsePList(plistFileBuf);
return plist;
}
@Override
protected void done() {
super.done();
@ -301,28 +301,28 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
try {
plist = get();
setupTable(plist);
SwingUtilities.invokeLater(() -> {
setColumnWidths();
setColumnWidths();
});
} catch (InterruptedException ex) {
logger.log(Level.SEVERE, "Interruption while parsing/dislaying plist file " + plistFile.getName(), ex);
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
ex.getMessage(),
Bundle.PListViewer_processPlist_interruptedMessage(),
JOptionPane.ERROR_MESSAGE);
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
ex.getMessage(),
Bundle.PListViewer_processPlist_interruptedMessage(),
JOptionPane.ERROR_MESSAGE);
} catch (ExecutionException ex) {
logger.log(Level.SEVERE, "Exception while parsing/dislaying plist file " + plistFile.getName(), ex);
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
ex.getCause().getMessage(),
Bundle.PListViewer_processPlist_errorMessage(),
JOptionPane.ERROR_MESSAGE);
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
ex.getCause().getMessage(),
Bundle.PListViewer_processPlist_errorMessage(),
JOptionPane.ERROR_MESSAGE);
}
}
}.execute();
}.execute();
}
/**
@ -431,16 +431,16 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
* else is unexpected and will be ignored.
*/
if (rootDict instanceof NSArray) {
for (int i=0; i < ((NSArray)rootDict).count(); i++) {
final PropKeyValue pkv = parseProperty("", ((NSArray)rootDict).objectAtIndex(i));
for (int i = 0; i < ((NSArray) rootDict).count(); i++) {
final PropKeyValue pkv = parseProperty("", ((NSArray) rootDict).objectAtIndex(i));
if (null != pkv) {
plist.add(pkv);
}
}
} else if (rootDict instanceof NSDictionary) {
final String[] keys = ((NSDictionary)rootDict).allKeys();
final String[] keys = ((NSDictionary) rootDict).allKeys();
for (final String key : keys) {
final PropKeyValue pkv = parseProperty(key, ((NSDictionary)rootDict).objectForKey(key));
final PropKeyValue pkv = parseProperty(key, ((NSDictionary) rootDict).objectForKey(key));
if (null != pkv) {
plist.add(pkv);
}
@ -533,7 +533,7 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
.map(child -> new PropKeyValue(child))
.toArray(PropKeyValue[]::new);
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 Basis Technology Corp.
* Copyright 2018-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -74,7 +74,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
/**
* Constructs a file content viewer for SQLite database files.
*/
public SQLiteViewer() {
SQLiteViewer() {
initComponents();
jTableDataPanel.add(selectedTableView, BorderLayout.CENTER);
}
@ -544,19 +544,19 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
@Override
public void accept(String columnName) {
columnIndex++;
String csvString = columnName;
//Format the value to adhere to the format of a CSV file
if (columnIndex == 1) {
columnName = "\"" + columnName + "\"";
csvString = "\"" + csvString + "\"";
} else {
columnName = ",\"" + columnName + "\"";
csvString = ",\"" + csvString + "\"";
}
if (columnIndex == totalColumnCount) {
columnName += "\n";
csvString += "\n";
}
try {
out.write(columnName.getBytes());
out.write(csvString.getBytes());
} catch (IOException ex) {
/*
* If we can no longer write to the output stream, toss a
@ -613,7 +613,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
*/
throw new RuntimeException(ex);
}
rowIndex = rowIndex % totalColumnCount;
rowIndex %= totalColumnCount;
}
};
}

View File

@ -60,6 +60,7 @@ public final class UserPreferences {
private static final String MESSAGE_SERVICE_USER = "MessageServiceUser"; //NON-NLS
private static final String MESSAGE_SERVICE_HOST = "MessageServiceHost"; //NON-NLS
private static final String MESSAGE_SERVICE_PORT = "MessageServicePort"; //NON-NLS
private static final String TEXT_TRANSLATOR_NAME = "TextTranslatorName";
public static final String PROCESS_TIME_OUT_ENABLED = "ProcessTimeOutEnabled"; //NON-NLS
public static final String PROCESS_TIME_OUT_HOURS = "ProcessTimeOutHours"; //NON-NLS
private static final int DEFAULT_PROCESS_TIMEOUT_HR = 60;
@ -335,6 +336,14 @@ public final class UserPreferences {
public static void setIndexingServerPort(int port) {
preferences.putInt(INDEXING_SERVER_PORT, port);
}
public static void setTextTranslatorName(String textTranslatorName){
preferences.put(TEXT_TRANSLATOR_NAME, textTranslatorName);
}
public static String getTextTranslatorName(){
return preferences.get(TEXT_TRANSLATOR_NAME, null);
}
/**
* Persists message service connection info.

View File

@ -386,7 +386,13 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer {
rootNodeChildren.cancelLoadingThumbnails();
}
try {
if (givenNode != null) {
// There is an issue with ThumbnailViewChildren
// addNotify, that it's call to getChildren.getNodes() does not cause the
// children nodes to be created. Adding a call to getChildren.getNodesCount()
// here will assure that the children nodes are created particularly in the
// case where the DataResultViewerThumbnail stands along from the
// DataResultViewer. See DataResultViewer setNode for more information.
if (givenNode != null && givenNode.getChildren().getNodesCount() > 0) {
rootNode = (TableFilterNode) givenNode;
/*
* Wrap the given node in a ThumbnailViewChildren that will

View File

@ -29,6 +29,7 @@ import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.ArrayList;
@ -798,7 +799,12 @@ public class ImageUtils {
imageSaver.execute(() -> {
try {
synchronized (cacheFile) {
Files.createParentDirs(cacheFile);
Path path = Paths.get(cacheFile.getParent());
File thumbsDir = Paths.get(cacheFile.getParent()).toFile();
if (!thumbsDir.exists()) {
thumbsDir.mkdirs();
}
if (cacheFile.exists()) {
cacheFile.delete();
}

View File

@ -95,7 +95,20 @@ public class DataResultFilterNode extends FilterNode {
static private final DisplayableItemNodeVisitor<List<Action>> getActionsDIV = new GetPopupActionsDisplayableItemNodeVisitor();
private final DisplayableItemNodeVisitor<AbstractAction> getPreferredActionsDIV = new GetPreferredActionsDisplayableItemNodeVisitor();
// Assumptions are made in GetPreferredActionsDisplayableItemNodeVisitor that
// sourceEm is the directory tree explorer manager.
private final ExplorerManager sourceEm;
/**
* Constructs a node used to wrap another node before passing it to the
* result viewers. The wrapper node defines the actions associated with the
* wrapped node and may filter out some of its children.
*
* @param node The node to wrap.
*/
public DataResultFilterNode(Node node) {
this(node, null);
}
/**
* Constructs a node used to wrap another node before passing it to the
@ -549,6 +562,9 @@ public class DataResultFilterNode extends FilterNode {
// is a DirectoryTreeFilterNode that wraps the dataModelNode. We need
// to set that wrapped node as the selection and root context of the
// directory tree explorer manager (sourceEm)
if(sourceEm == null) {
return null;
}
final Node currentSelectionInDirectoryTree = sourceEm.getSelectedNodes()[0];
return new AbstractAction() {
@ -589,6 +605,9 @@ public class DataResultFilterNode extends FilterNode {
* @return
*/
private AbstractAction openParent(AbstractNode node) {
if(sourceEm == null) {
return null;
}
// @@@ Why do we ignore node?
Node[] selectedFilterNodes = sourceEm.getSelectedNodes();
Node selectedFilterNode = selectedFilterNodes[0];

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -163,6 +163,8 @@ final class ContactAnalyzer {
data1 = resultSet.getString("data1"); //NON-NLS
mimetype = resultSet.getString("mimetype"); //NON-NLS
if (name.equals(oldName) == false) {
bba = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT);
attributes = new ArrayList<>();
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, moduleName, name));
}
if (mimetype.equals("vnd.android.cursor.item/phone_v2")) { //NON-NLS
@ -170,6 +172,12 @@ final class ContactAnalyzer {
} else {
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, moduleName, data1));
}
// TODO: If this code comes back to life, add code to create the account
// and relationship between the phone numbers & emails. Also
// investigate if the mimetype "vnd.android.cursor.item/phone_v2"
// makes sense in an ios word
oldName = name;
bba.addAttributes(attributes);

View File

@ -1,15 +1,15 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2018 Basis Technology Corp.
*
* Copyright 2013-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -18,12 +18,15 @@
*/
package org.sleuthkit.autopsy.modules.stix;
import com.williballenthin.rejistry.RegistryHiveFile;
import com.williballenthin.rejistry.RegistryKey;
import com.williballenthin.rejistry.RegistryParseException;
import com.williballenthin.rejistry.RegistryValue;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.datamodel.AbstractFile;
import java.util.List;
import java.util.ArrayList;
import java.io.IOException;
@ -31,10 +34,8 @@ import java.io.UnsupportedEncodingException;
import java.io.File;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import org.mitre.cybox.objects.WindowsRegistryKey;
import org.mitre.cybox.common_2.ConditionTypeEnum;
import com.williballenthin.rejistry.*;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
/**
@ -43,9 +44,9 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
class EvalRegistryObj extends EvaluatableObject {
private final WindowsRegistryKey obj;
private final List<RegistryFileInfo> regFiles = new ArrayList<RegistryFileInfo>();
private final List<RegistryFileInfo> regFiles = new ArrayList<>();
public EvalRegistryObj(WindowsRegistryKey a_obj, String a_id, String a_spacing, List<RegistryFileInfo> a_regFiles) {
EvalRegistryObj(WindowsRegistryKey a_obj, String a_id, String a_spacing, List<RegistryFileInfo> a_regFiles) {
obj = a_obj;
id = a_id;
spacing = a_spacing;
@ -80,7 +81,7 @@ class EvalRegistryObj extends EvaluatableObject {
setUnsupportedFieldWarnings();
// Make a list of hives to test
List<RegistryFileInfo> hiveList = new ArrayList<RegistryFileInfo>();
List<RegistryFileInfo> hiveList = new ArrayList<>();
if (obj.getHive() == null) {
// If the hive field is missing, add everything
hiveList.addAll(regFiles);
@ -88,9 +89,9 @@ class EvalRegistryObj extends EvaluatableObject {
// If the hive name is HKEY_LOCAL_MACHINE, add the ones from the config directory.
// Otherwise, add the others
for (RegistryFileInfo regFile : regFiles) {
if (regFile.abstractFile.getParentPath() != null) {
if (regFile.getAbstractFile().getParentPath() != null) {
Pattern pattern = Pattern.compile("system32", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(regFile.abstractFile.getParentPath());
Matcher matcher = pattern.matcher(regFile.getAbstractFile().getParentPath());
if (matcher.find()) {
// Looking for system files and found one, so add it to the list
if (obj.getHive().getValue().toString().equalsIgnoreCase("HKEY_LOCAL_MACHINE")) { //NON-NLS
@ -112,7 +113,7 @@ class EvalRegistryObj extends EvaluatableObject {
Pattern pattern = Pattern.compile("Temp.STIX." + stixHiveName, Pattern.CASE_INSENSITIVE);
for (RegistryFileInfo hive : regFiles) {
Matcher matcher = pattern.matcher(hive.tempFileName);
Matcher matcher = pattern.matcher(hive.getTempFileName());
if (matcher.find()) {
hiveList.add(hive);
}
@ -163,7 +164,7 @@ class EvalRegistryObj extends EvaluatableObject {
*/
private ObservableResult testRegistryFile(RegistryFileInfo a_regInfo) {
try {
RegistryKey root = openRegistry(a_regInfo.tempFileName);
RegistryKey root = openRegistry(a_regInfo.getTempFileName());
RegistryKey result = findKey(root, obj.getKey().getValue().toString());
if (result == null) {
@ -192,8 +193,8 @@ class EvalRegistryObj extends EvaluatableObject {
if ((obj.getValues() == null) || (obj.getValues().getValues().isEmpty())) {
// No values to test
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
artData.add(new StixArtifactData(a_regInfo.abstractFile.getId(), id, "Registry")); //NON-NLS
List<StixArtifactData> artData = new ArrayList<>();
artData.add(new StixArtifactData(a_regInfo.getAbstractFile().getId(), id, "Registry")); //NON-NLS
return new ObservableResult(id, "RegistryObject: Found key " + obj.getKey().getValue(), //NON-NLS
spacing, ObservableResult.ObservableState.TRUE, artData);
}
@ -262,8 +263,8 @@ class EvalRegistryObj extends EvaluatableObject {
if (nameSuccess && valueSuccess) {
// Found a match for all values
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
artData.add(new StixArtifactData(a_regInfo.abstractFile.getId(), id, "Registry")); //NON-NLS
List<StixArtifactData> artData = new ArrayList<>();
artData.add(new StixArtifactData(a_regInfo.getAbstractFile().getId(), id, "Registry")); //NON-NLS
return new ObservableResult(id, "RegistryObject: Found key " + obj.getKey().getValue() //NON-NLS
+ " and value " + stixRegValue.getName().getValue().toString() //NON-NLS
+ " = " + stixRegValue.getData().getValue().toString(),
@ -343,13 +344,13 @@ class EvalRegistryObj extends EvaluatableObject {
List<AbstractFile> regFilesAbstract = findRegistryFiles();
// List to hold all the extracted file names plus their abstract file
List<RegistryFileInfo> regFilesLocal = new ArrayList<RegistryFileInfo>();
List<RegistryFileInfo> regFilesLocal = new ArrayList<>();
// Make the temp directory
String tmpDir;
try {
tmpDir = Case.getCurrentCaseThrows().getTempDirectory() + File.separator + "STIX"; //NON-NLS
} catch (NoCurrentCaseException ex) {
tmpDir = Case.getCurrentCaseThrows().getTempDirectory() + File.separator + "STIX"; //NON-NLS
} catch (NoCurrentCaseException ex) {
throw new TskCoreException(ex.getLocalizedMessage());
}
File dir = new File(tmpDir);
@ -382,11 +383,11 @@ class EvalRegistryObj extends EvaluatableObject {
* RecentActivity
*/
private static List<AbstractFile> findRegistryFiles() throws TskCoreException {
List<AbstractFile> registryFiles = new ArrayList<AbstractFile>();
List<AbstractFile> registryFiles = new ArrayList<>();
Case openCase;
try {
openCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
} catch (NoCurrentCaseException ex) {
throw new TskCoreException(ex.getLocalizedMessage());
}
org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = openCase.getServices().getFileManager();
@ -413,7 +414,7 @@ class EvalRegistryObj extends EvaluatableObject {
}
private void setUnsupportedFieldWarnings() {
List<String> fieldNames = new ArrayList<String>();
List<String> fieldNames = new ArrayList<>();
if (obj.getNumberValues() != null) {
fieldNames.add("Number_Values"); //NON-NLS
@ -462,5 +463,23 @@ class EvalRegistryObj extends EvaluatableObject {
tempFileName = a_tempFileName;
}
/**
* Get the AbstractFile for this RegistryFileInfo
*
* @return the abstractFile
*/
AbstractFile getAbstractFile() {
return abstractFile;
}
/**
* Get the Temporary file name for this RegistryFileInfo
*
* @return the tempFileName
*/
String getTempFileName() {
return tempFileName;
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -22,7 +22,9 @@ import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import net.htmlparser.jericho.Attributes;
import net.htmlparser.jericho.Config;
@ -71,7 +73,7 @@ final class HtmlTextExtractor implements TextExtractor {
/**
* Determines if this content type is supported by this extractor.
*
* @param content Content instance to be analyzed
* @param content Content instance to be analyzed
* @param detectedFormat Mimetype of content instance
*
* @return flag indicating support
@ -84,27 +86,21 @@ final class HtmlTextExtractor implements TextExtractor {
}
/**
* Returns a reader that will iterate over the text of an HTML document.
*
* @param content Html document source
*
* @return A reader instance containing the document source text
*
* @throws TextExtractorException
* Get the metadata as a key -> value map. HTML metadata will include
* scripts, links, images, comments, and misc attributes.
*
* @return Map containing metadata key -> value pairs.
*/
@Override
public Reader getReader() throws InitReaderException {
//TODO JIRA-4467, there is only harm in excluding HTML documents greater
//than 50MB due to our troubled approach of extraction.
ReadContentInputStream stream = new ReadContentInputStream(file);
//Parse the stream with Jericho and put the results in a Reader
public Map<String, String> getMetadata() {
Map<String, String> metadataMap = new HashMap<>();
try {
StringBuilder scripts = new StringBuilder();
StringBuilder links = new StringBuilder();
StringBuilder images = new StringBuilder();
StringBuilder comments = new StringBuilder();
StringBuilder others = new StringBuilder();
ReadContentInputStream stream = new ReadContentInputStream(file);
StringBuilder scripts = new StringBuilder("\n");
StringBuilder links = new StringBuilder("\n");
StringBuilder images = new StringBuilder("\n");
StringBuilder comments = new StringBuilder("\n");
StringBuilder others = new StringBuilder("\n");
int numScripts = 0;
int numLinks = 0;
int numImages = 0;
@ -113,17 +109,8 @@ final class HtmlTextExtractor implements TextExtractor {
Source source = new Source(stream);
source.fullSequentialParse();
Renderer renderer = source.getRenderer();
renderer.setNewLine("\n");
renderer.setIncludeHyperlinkURLs(false);
renderer.setDecorateFontStyles(false);
renderer.setIncludeAlternateText(false);
String text = renderer.toString();
// Get all the tags in the source
List<StartTag> tags = source.getAllStartTags();
StringBuilder stringBuilder = new StringBuilder();
for (StartTag tag : tags) {
if (tag.getName().equals("script")) { //NON-NLS
// If the <script> tag has attributes
@ -164,30 +151,54 @@ final class HtmlTextExtractor implements TextExtractor {
}
}
}
stringBuilder.append(text).append("\n\n");
stringBuilder.append("----------NONVISIBLE TEXT----------\n\n"); //NON-NLS
if (numScripts > 0) {
stringBuilder.append("---Scripts---\n"); //NON-NLS
stringBuilder.append(scripts).append("\n");
metadataMap.put("Scripts", scripts.toString());
}
if (numLinks > 0) {
stringBuilder.append("---Links---\n"); //NON-NLS
stringBuilder.append(links).append("\n");
metadataMap.put("Links", links.toString());
}
if (numImages > 0) {
stringBuilder.append("---Images---\n"); //NON-NLS
stringBuilder.append(images).append("\n");
metadataMap.put("Images", images.toString());
}
if (numComments > 0) {
stringBuilder.append("---Comments---\n"); //NON-NLS
stringBuilder.append(comments).append("\n");
metadataMap.put("Comments", comments.toString());
}
if (numOthers > 0) {
stringBuilder.append("---Others---\n"); //NON-NLS
stringBuilder.append(others).append("\n");
metadataMap.put("Others", others.toString());
}
// All done, now make it a reader
return new StringReader(stringBuilder.toString());
} catch (IOException ex) {
logger.log(Level.WARNING, "Error extracting HTML metadata from content.", ex);
}
return metadataMap;
}
/**
* Returns a reader that will iterate over the text of an HTML document.
*
* @param content Html document source
*
* @return A reader instance containing the document source text
*
* @throws TextExtractorException
*/
@Override
public Reader getReader() throws InitReaderException {
//TODO JIRA-4467, there is only harm in excluding HTML documents greater
//than 50MB due to our troubled approach of extraction.
ReadContentInputStream stream = new ReadContentInputStream(file);
//Parse the stream with Jericho and put the results in a Reader
try {
Source source = new Source(stream);
source.fullSequentialParse();
Renderer renderer = source.getRenderer();
renderer.setNewLine("\n");
renderer.setIncludeHyperlinkURLs(false);
renderer.setDecorateFontStyles(false);
renderer.setIncludeAlternateText(false);
return new StringReader(renderer.toString());
} catch (IOException ex) {
logger.log(Level.WARNING, "Error extracting HTML from content.", ex);
throw new InitReaderException("Error extracting HTML from content.", ex);

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-18 Basis Technology Corp.
* Copyright 2011-19 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -19,6 +19,8 @@
package org.sleuthkit.autopsy.textextractors;
import java.io.Reader;
import java.util.Collections;
import java.util.Map;
import org.openide.util.Lookup;
/**
@ -61,6 +63,15 @@ public interface TextExtractor {
default void setExtractionSettings(Lookup context) {
//no-op by default
}
/**
* Retrieves content metadata, if any.
*
* @return Metadata as key -> value map
*/
default Map<String, String> getMetadata() {
return Collections.emptyMap();
}
/**
* System level exception for reader initialization.

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2018 Basis Technology Corp.
* Copyright 2011-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -29,8 +29,10 @@ import java.io.InputStream;
import java.io.PushbackReader;
import java.io.Reader;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -40,8 +42,8 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.tika.Tika;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
@ -65,6 +67,10 @@ import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.google.common.collect.ImmutableMap;
/**
* Extracts text from Tika supported content. Protects against Tika parser hangs
@ -136,7 +142,8 @@ final class TikaTextExtractor implements TextExtractor {
private static final File TESSERACT_PATH = locateTesseractExecutable();
private String languagePacks = formatLanguagePacks(PlatformUtil.getOcrLanguagePacks());
private static final String TESSERACT_OUTPUT_FILE_NAME = "tess_output"; //NON-NLS
private Map<String, String> metadataMap;
private ProcessTerminator processTerminator;
private static final List<String> TIKA_SUPPORTED_TYPES
@ -151,8 +158,8 @@ final class TikaTextExtractor implements TextExtractor {
/**
* If Tesseract has been installed and is set to be used through
* configuration, then ocr is enabled. OCR can only currently be run on
* 64 bit Windows OS.
* configuration, then ocr is enabled. OCR can only currently be run on 64
* bit Windows OS.
*
* @return Flag indicating if OCR is set to be used.
*/
@ -201,7 +208,7 @@ final class TikaTextExtractor implements TextExtractor {
TesseractOCRConfig ocrConfig = new TesseractOCRConfig();
String tesseractFolder = TESSERACT_PATH.getParent();
ocrConfig.setTesseractPath(tesseractFolder);
ocrConfig.setLanguage(languagePacks);
ocrConfig.setTessdataPath(PlatformUtil.getOcrLanguagePacksPath());
parseContext.set(TesseractOCRConfig.class, ocrConfig);
@ -233,9 +240,16 @@ final class TikaTextExtractor implements TextExtractor {
+ "Tika returned empty reader for " + content);
}
pushbackReader.unread(read);
//concatenate parsed content and meta data into a single reader.
CharSource metaDataCharSource = getMetaDataCharSource(metadata);
return CharSource.concat(new ReaderCharSource(pushbackReader), metaDataCharSource).openStream();
//Save the metadata if it has not been fetched already.
if (metadataMap == null) {
metadataMap = new HashMap<>();
for (String mtdtKey : metadata.names()) {
metadataMap.put(mtdtKey, metadata.get(mtdtKey));
}
}
return new ReaderCharSource(pushbackReader).openStream();
} catch (TimeoutException te) {
final String msg = NbBundle.getMessage(this.getClass(),
"AbstractFileTikaTextExtract.index.tikaParseTimeout.text",
@ -273,7 +287,7 @@ final class TikaTextExtractor implements TextExtractor {
File outputFile = null;
try {
String tempDirectory = Case.getCurrentCaseThrows().getTempDirectory();
//Appending file id makes the name unique
String tempFileName = FileUtil.escapeFileName(file.getId() + file.getName());
inputFile = Paths.get(tempDirectory, tempFileName).toFile();
@ -314,7 +328,7 @@ final class TikaTextExtractor implements TextExtractor {
}
}
}
/**
* Wraps the creation of a TikaReader into a Future so that it can be
* cancelled.
@ -403,20 +417,33 @@ final class TikaTextExtractor implements TextExtractor {
}
/**
* Gets a CharSource that wraps a formated representation of the given
* Metadata.
* Get the content metadata, if any.
*
* @param metadata The Metadata to wrap as a CharSource
*
* @return A CharSource for the given MetaData
* @return Metadata as a name -> value map
*/
static private CharSource getMetaDataCharSource(Metadata metadata) {
return CharSource.wrap(
new StringBuilder("\n\n------------------------------METADATA------------------------------\n\n")
.append(Stream.of(metadata.names()).sorted()
.map(key -> key + ": " + metadata.get(key))
.collect(Collectors.joining("\n"))
));
@Override
public Map<String, String> getMetadata() {
if (metadataMap != null) {
return ImmutableMap.copyOf(metadataMap);
}
try {
metadataMap = new HashMap<>();
InputStream stream = new ReadContentInputStream(content);
ContentHandler doNothingContentHandler = new DefaultHandler();
Metadata mtdt = new Metadata();
parser.parse(stream, doNothingContentHandler, mtdt);
for (String mtdtKey : mtdt.names()) {
metadataMap.put(mtdtKey, mtdt.get(mtdtKey));
}
} catch (IOException | SAXException | TikaException ex) {
AUTOPSY_LOGGER.log(Level.WARNING, String.format("Error getting metadata for file [id=%d] %s, see Tika log for details...", //NON-NLS
content.getId(), content.getName()));
TIKA_LOGGER.log(Level.WARNING, "Exception: Unable to get metadata for " //NON-NLS
+ "content" + content.getId() + ": " + content.getName(), ex); //NON-NLS
}
return metadataMap;
}
/**
@ -426,11 +453,11 @@ final class TikaTextExtractor implements TextExtractor {
*/
@Override
public boolean isSupported() {
if(!(content instanceof AbstractFile)) {
if (!(content instanceof AbstractFile)) {
return false;
}
String detectedType = ((AbstractFile)content).getMIMEType();
String detectedType = ((AbstractFile) content).getMIMEType();
if (detectedType == null
|| BINARY_MIME_TYPES.contains(detectedType) //any binary unstructured blobs (string extraction will be used)
|| ARCHIVE_MIME_TYPES.contains(detectedType)
@ -439,7 +466,7 @@ final class TikaTextExtractor implements TextExtractor {
) {
return false;
}
return TIKA_SUPPORTED_TYPES.contains(detectedType);
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018-2018 Basis Technology Corp.
* Copyright 2018-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,34 +18,52 @@
*/
package org.sleuthkit.autopsy.texttranslation;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.core.UserPreferences;
/**
* Performs a lookup for a TextTranslator service provider and if present,
* will use this provider to run translation on the input.
* Performs a lookup for a TextTranslator service provider and if present, will
* use this provider to run translation on the input.
*/
public final class TextTranslationService {
private final static TextTranslationService tts = new TextTranslationService();
private final Optional<TextTranslator> translator;
private TextTranslationService(){
private final Collection<? extends TextTranslator> translators;
private Optional<TextTranslator> selectedTranslator;
private TextTranslationService() {
//Perform look up for Text Translation implementations ONLY ONCE during
//class loading.
translator = Optional.ofNullable(Lookup.getDefault()
.lookup(TextTranslator.class));
translators = Lookup.getDefault().lookupAll(TextTranslator.class);
updateSelectedTranslator();
}
public static TextTranslationService getInstance() {
return tts;
}
/**
* Translates the input string using whichever TextTranslator Service Provider
* was found during lookup.
* Update the translator currently in use to match the one saved to the user
* preferences
*/
public void updateSelectedTranslator() {
String translatorName = UserPreferences.getTextTranslatorName();
for (TextTranslator translator : translators) {
if (translator.getName().equals(translatorName)) {
selectedTranslator = Optional.ofNullable(translator);
return;
}
}
selectedTranslator = Optional.empty();
}
/**
* Translates the input string using whichever TextTranslator Service
* Provider was found during lookup.
*
* @param input Input string to be translated
*
@ -58,20 +76,48 @@ public final class TextTranslationService {
* implementations fail
*/
public String translate(String input) throws NoServiceProviderException, TranslationException {
if (translator.isPresent()) {
return translator.get().translate(input);
if (hasProvider()) {
return selectedTranslator.get().translate(input);
}
throw new NoServiceProviderException(
"Could not find a TextTranslator service provider");
}
/**
* Get a specific translator by name
*
* @param translatorName the name of the translator to get
*
* @return the translator which matches the name specified
*
* @throws NoServiceProviderException
*/
public TextTranslator getTranslatorByName(String translatorName) throws NoServiceProviderException {
for (TextTranslator translator : translators) {
if (translator.getName().equals(translatorName)) {
return translator;
}
}
throw new NoServiceProviderException(
"Could not find the specified TextTranslator service provider: " + translatorName);
}
/**
* Get all the TextTranslator implementations which were found to exist
*
* @return an unmodifiable collection of TextTranslators
*/
public Collection<? extends TextTranslator> getTranslators() {
return Collections.unmodifiableCollection(translators);
}
/**
* Returns if a TextTranslator lookup successfully found an implementing
* class.
*
* @return
* @return
*/
public boolean hasProvider() {
return translator.isPresent();
return selectedTranslator.isPresent();
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018-2018 Basis Technology Corp.
* Copyright 2018-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,12 +18,42 @@
*/
package org.sleuthkit.autopsy.texttranslation;
import java.awt.Component;
/**
* Interface for creating text translators. Implementing classes will be picked
* up and run by the Text Translation Service.
*/
public interface TextTranslator {
/**
* Translates a provided string
*
* @param input the String to translate
*
* @return the translated String
*
* @throws TranslationException
*/
String translate(String input) throws TranslationException;
/**
* Get the name of the TextTranslator implementation
*
* @return the name of the TextTranslator
*/
String getName();
/**
* Get the component to display on the settings options panel when this
* TextTranslator is selected
*
* @return the component which displays the settings options
*/
Component getComponent();
/**
* Save the settings as they have been modified in the component.
*/
void saveSettings();
}

View File

@ -0,0 +1,8 @@
OptionsCategory_Name_Machine_Translation=Machine Translation
OptionsCategory_Keywords_Machine_Translation_Settings=Machine Translation Settings
TranslationContentPanel.ShowLabel.text=Show:
TranslationContentPanel.warningLabel2MB.text=Only the first 1MB of text will be displayed
TranslationContentPanel.ocrLabel.text=OCR:
TranslationOptionsPanel.translationServiceLabel.text=Text translator:
TranslationOptionsPanelController.moduleErr=Module Error
TranslationOptionsPanelController.moduleErr.msg=A module caused an error listening to TranslationSettingsPanelController updates. See log to determine which module. Some data could be incomplete.

View File

@ -1,3 +1,5 @@
OptionsCategory_Name_Machine_Translation=Machine Translation
OptionsCategory_Keywords_Machine_Translation_Settings=Machine Translation Settings
TranslatedContentPanel.comboBoxOption.originalText=Original Text
TranslatedContentPanel.comboBoxOption.translatedText=Translated Text
TranslatedContentViewer.emptyTranslation=The resulting translation was empty.
@ -13,6 +15,13 @@ TranslatedContentViewer.translationException=Error encountered while attempting
TranslatedTextViewer.title=Translation
TranslatedTextViewer.toolTip=Displays translated file text.
TranslationContentPanel.autoDetectOCR=Autodetect language
TranslationContentPanel.warningLabel2MB.text=Only the first 1MB of text will be displayed
TranslationContentPanel.ShowLabel.text=Show:
TranslationContentPanel.warningLabel2MB.text=Only the first 1MB of text will be displayed
TranslationContentPanel.ocrLabel.text=OCR:
TranslationOptionsPanel.noTextTranslators.text=No text translators exist, translation is disabled.
TranslationOptionsPanel.noTextTranslatorSelected.text=No text translator selected, translation is disabled.
TranslationOptionsPanel.textTranslatorsUnavailable.text=Unable to get selected text translator, translation is disabled.
TranslationOptionsPanel.translationDisabled.text=Translation disabled
TranslationOptionsPanel.translationServiceLabel.text=Text translator:
TranslationOptionsPanelController.moduleErr=Module Error
TranslationOptionsPanelController.moduleErr.msg=A module caused an error listening to TranslationSettingsPanelController updates. See log to determine which module. Some data could be incomplete.

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.translation;
package org.sleuthkit.autopsy.texttranslation.ui;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
@ -53,7 +53,7 @@ import org.sleuthkit.autopsy.texttranslation.TranslationException;
import org.sleuthkit.datamodel.Content;
import java.util.List;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.translation.TranslationContentPanel.DisplayDropdownOptions;
import org.sleuthkit.autopsy.texttranslation.ui.TranslationContentPanel.DisplayDropdownOptions;
/**
* A TextViewer that displays machine translation of text.
@ -204,7 +204,7 @@ public final class TranslatedTextViewer implements TextViewer {
@Override
public void done() {
try {
String result = get();
String result = get();
if (this.isCancelled()) {
throw new InterruptedException();
}
@ -294,12 +294,15 @@ public final class TranslatedTextViewer implements TextViewer {
/**
* Fetches text from a file.
*
* @param fileReader Reader instance containing file text
* @param source the AbstractFile source to get a Reader for
* @param ocrEnabled true if OCR is enabled false otherwise
*
* @return Extracted Text
*
* @throws IOException
* @throws InterruptedException
* @throws
* org.sleuthkit.autopsy.textextractors.TextExtractor.InitReaderException
*/
private String extractText(AbstractFile source, boolean ocrEnabled) throws IOException, InterruptedException, TextExtractor.InitReaderException {
Reader textExtractor = getTextExtractor(source, ocrEnabled);

View File

@ -102,7 +102,7 @@
<Component class="javax.swing.JLabel" name="ShowLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/translation/Bundle.properties" key="TranslationContentPanel.ShowLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties" key="TranslationContentPanel.ShowLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -148,7 +148,7 @@
<Component class="javax.swing.JLabel" name="ocrLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/translation/Bundle.properties" key="TranslationContentPanel.ocrLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties" key="TranslationContentPanel.ocrLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
@ -159,7 +159,7 @@
<Image iconType="3" name="/org/sleuthkit/autopsy/images/warning16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/translation/Bundle.properties" key="TranslationContentPanel.warningLabel2MB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties" key="TranslationContentPanel.warningLabel2MB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.translation;
package org.sleuthkit.autopsy.texttranslation.ui;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableBiMap;
@ -362,7 +362,7 @@ public class TranslationContentPanel extends javax.swing.JPanel {
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 628, Short.MAX_VALUE)
.addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 628, Short.MAX_VALUE)
.addComponent(jScrollPane1)
);
layout.setVerticalGroup(

View File

@ -0,0 +1,70 @@
<?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" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="translationServiceLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="translatorComboBox" min="-2" pref="214" max="-2" attributes="0"/>
<EmptySpace min="0" pref="162" max="32767" attributes="0"/>
</Group>
<Component id="translationServicePanel" alignment="1" max="32767" attributes="0"/>
</Group>
<EmptySpace 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 max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="translatorComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="translationServiceLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="translationServicePanel" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JComboBox" name="translatorComboBox">
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="translatorComboBoxActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="translationServiceLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties" key="TranslationOptionsPanel.translationServiceLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="translationServicePanel">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,198 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.texttranslation.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.logging.Level;
import javax.swing.JLabel;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException;
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Options panel to display translation options
*/
public class TranslationOptionsPanel extends javax.swing.JPanel {
private final static Logger logger = Logger.getLogger(TranslationOptionsPanel.class.getName());
private static final long serialVersionUID = 1L;
private final TranslationOptionsPanelController controller;
private String currentSelection = "";
/**
* Creates new form TranslationOptionsPanel
*/
@Messages({"TranslationOptionsPanel.translationDisabled.text=Translation disabled"})
public TranslationOptionsPanel(TranslationOptionsPanelController theController) {
initComponents();
controller = theController;
translatorComboBox.addItem(Bundle.TranslationOptionsPanel_translationDisabled_text());
TextTranslationService.getInstance().getTranslators().forEach((translator) -> {
translatorComboBox.addItem(translator.getName());
});
translatorComboBox.setEnabled(translatorComboBox.getItemCount() > 1);
load();
}
/**
* Private helper method to update the panel if the selected TextTranslator
* has changed
*/
private void updatePanel() {
if (!currentSelection.equals(translatorComboBox.getSelectedItem().toString())) {
currentSelection = translatorComboBox.getSelectedItem().toString();
loadSelectedPanelSettings();
controller.changed();
}
}
/**
* Load the settings for the selected TextTranslator's panel
*/
@Messages({"TranslationOptionsPanel.textTranslatorsUnavailable.text=Unable to get selected text translator, translation is disabled.",
"TranslationOptionsPanel.noTextTranslatorSelected.text=No text translator selected, translation is disabled.",
"TranslationOptionsPanel.noTextTranslators.text=No text translators exist, translation is disabled."})
private void loadSelectedPanelSettings() {
translationServicePanel.removeAll();
if (translatorComboBox.getSelectedItem() != null && !translatorComboBox.getSelectedItem().toString().equals(Bundle.TranslationOptionsPanel_translationDisabled_text())) {
try {
Component panel = TextTranslationService.getInstance().getTranslatorByName(translatorComboBox.getSelectedItem().toString()).getComponent();
panel.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
controller.changed();
}
});
translationServicePanel.add(panel, BorderLayout.PAGE_START);
} catch (NoServiceProviderException ex) {
logger.log(Level.WARNING, "Unable to get TextExtractor named: " + translatorComboBox.getSelectedItem().toString(), ex);
JLabel label = new JLabel(Bundle.TranslationOptionsPanel_textTranslatorsUnavailable_text());
label.setForeground(Color.RED);
translationServicePanel.add(label, BorderLayout.PAGE_START);
}
} else {
if (translatorComboBox.getItemCount() < 2) {
translationServicePanel.add(new JLabel(Bundle.TranslationOptionsPanel_noTextTranslators_text()), BorderLayout.PAGE_START);
} else {
translationServicePanel.add(new JLabel(Bundle.TranslationOptionsPanel_noTextTranslatorSelected_text()), BorderLayout.PAGE_START);
}
}
revalidate();
repaint();
}
/**
* Load settings from user preferences and update the UI
*/
final void load() {
currentSelection = UserPreferences.getTextTranslatorName();
if (currentSelection == null) {
currentSelection = Bundle.TranslationOptionsPanel_translationDisabled_text();
}
translatorComboBox.setSelectedItem(currentSelection);
loadSelectedPanelSettings();
}
/**
* Save the current settings
*/
void store() {
//The current text translator name is saved to user preferences
UserPreferences.setTextTranslatorName(currentSelection);
//The TextTranslationService updates the TextTranslator in use from user preferences
TextTranslationService.getInstance().updateSelectedTranslator();
if (currentSelection != null && !currentSelection.equals(Bundle.TranslationOptionsPanel_translationDisabled_text())) {
try {
TextTranslationService.getInstance().getTranslatorByName(currentSelection).saveSettings();
} catch (NoServiceProviderException ex) {
logger.log(Level.WARNING, "Unable to save settings for TextTranslator named: " + currentSelection, ex);
}
}
}
/**
* 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() {
translatorComboBox = new javax.swing.JComboBox<>();
translationServiceLabel = new javax.swing.JLabel();
translationServicePanel = new javax.swing.JPanel();
translatorComboBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
translatorComboBoxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(translationServiceLabel, org.openide.util.NbBundle.getMessage(TranslationOptionsPanel.class, "TranslationOptionsPanel.translationServiceLabel.text")); // NOI18N
translationServicePanel.setLayout(new java.awt.BorderLayout());
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(translationServiceLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(translatorComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 214, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 162, Short.MAX_VALUE))
.addComponent(translationServicePanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(translatorComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(translationServiceLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(translationServicePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
private void translatorComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_translatorComboBoxActionPerformed
updatePanel();
}//GEN-LAST:event_translatorComboBoxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel translationServiceLabel;
private javax.swing.JPanel translationServicePanel;
private javax.swing.JComboBox<String> translatorComboBox;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,141 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.texttranslation.ui;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import javax.swing.JComponent;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Controller for the TranslationOptionsPanel
*/
@OptionsPanelController.TopLevelRegistration(categoryName = "#OptionsCategory_Name_Machine_Translation",
iconBase = "org/sleuthkit/autopsy/images/translate32.png",
position = 7,
keywords = "#OptionsCategory_Keywords_Machine_Translation_Settings",
keywordsCategory = "Machine Translation")
public class TranslationOptionsPanelController extends OptionsPanelController {
private static final Logger logger = Logger.getLogger(TranslationOptionsPanelController.class.getName());
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private boolean changed;
private TranslationOptionsPanel panel;
@Override
public void update() {
getPanel().load();
changed = false;
}
@Override
public void applyChanges() {
getPanel().store();
changed = false;
}
@Override
public void cancel() {
}
@Override
public boolean isValid() {
return true;
}
@Override
public boolean isChanged() {
return changed;
}
@Override
public HelpCtx getHelpCtx() {
return null;
}
@Override
public JComponent getComponent(Lookup masterLookup) {
return getPanel();
}
@Override
public void addPropertyChangeListener(PropertyChangeListener l) {
if (pcs.getPropertyChangeListeners().length == 0) {
pcs.addPropertyChangeListener(l);
}
}
@Override
public void removePropertyChangeListener(PropertyChangeListener l) {
/**
* Note the NetBeans Framework does not appear to call this at all. We
* are using NetBeans 7.3.1 Build 201306052037. Perhaps in a future
* version of the Framework this will be resolved, but for now, simply
* don't unregister anything and add one time only in the
* addPropertyChangeListener() method above.
*/
}
/**
* Get the translation options panel
*
* @return
*/
private TranslationOptionsPanel getPanel() {
if (panel == null) {
panel = new TranslationOptionsPanel(this);
}
return panel;
}
/**
* Indicate that a setting has been changed in the options panel
*/
void changed() {
if (!changed) {
changed = true;
try {
pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true);
} catch (Exception e) {
logger.log(Level.SEVERE, "TranslationOptionsPanelController listener threw exception", e); //NON-NLS
MessageNotifyUtil.Notify.show(
NbBundle.getMessage(this.getClass(), "TranslationOptionsPanelController.moduleErr"),
NbBundle.getMessage(this.getClass(), "TranslationOptionsPanelController.moduleErr.msg"),
MessageNotifyUtil.MessageType.ERROR);
}
}
try {
pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
} catch (Exception e) {
logger.log(Level.SEVERE, "TranslationOptionsPanelController listener threw exception", e); //NON-NLS
MessageNotifyUtil.Notify.show(
NbBundle.getMessage(this.getClass(), "TranslationOptionsPanelController.moduleErr"),
NbBundle.getMessage(this.getClass(), "TranslationOptionsPanelController.moduleErr.msg"),
MessageNotifyUtil.MessageType.ERROR);
}
}
}

View File

@ -1,4 +1,4 @@
/*
/*=
* Autopsy Forensic Browser
*
* Copyright 2013-15 Basis Technology Corp.
@ -14,8 +14,8 @@
* 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.
*/
*=limitations under the License.
*/=
AbstractTimelineChart.defaultTooltip.text=Drag the mouse to select a time interval to zoom into.\nRight-click for more actions.
HistoryToolBar.historyLabel.text=History

View File

@ -1,3 +0,0 @@
TranslationContentPanel.warningLabel2MB.text=Only the first 1MB of text will be displayed
TranslationContentPanel.ShowLabel.text=Show:
TranslationContentPanel.ocrLabel.text=OCR:

View File

@ -141,6 +141,7 @@ class ContactAnalyzer(general.AndroidComponentAnalyzer):
name = resultSet.getString("display_name")
data1 = resultSet.getString("data1") # the phone number or email
mimetype = resultSet.getString("mimetype") # either phone or email
attributes = ArrayList()
if name != oldName:
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT)
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))

View File

@ -24,6 +24,7 @@ KeywordSearchIngestModule.init.badInitMsg=Keyword search server was not properly
KeywordSearchIngestModule.init.exception.errConnToSolr.msg=Error connecting to SOLR server: {0}.
# {0} - Reason for not starting Solr
KeywordSearchIngestModule.init.tryStopSolrMsg={0}<br />Please try stopping Java Solr processes if any exist and restart the application.
KeywordSearchIngestModule.metadataTitle=METADATA
KeywordSearchIngestModule.noOpenCase.errMsg=No open case available.
KeywordSearchIngestModule.startUp.noOpenCore.msg=The index could not be opened or does not exist.
# {0} - schema version number
@ -35,7 +36,7 @@ KeywordSearchResultFactory.createNodeForKey.noResultsFound.text=No results found
KeywordSearchResultFactory.query.exception.msg=Could not perform the query
OpenIDE-Module-Display-Category=Ingest Module
OpenIDE-Module-Long-Description=Keyword Search ingest module.\n\nThe module indexes files found in the disk image at ingest time.\nIt then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\n\The module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword search bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found.
OpenIDE-Module-Long-Description=Keyword Search ingest module.\n\nThe module indexes files found in the disk image at ingest time.\nIt then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\nThe module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword search bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found.
OpenIDE-Module-Name=KeywordSearch
OptionsCategory_Name_KeywordSearchOptions=Keyword Search
OptionsCategory_Keywords_KeywordSearchOptions=Keyword Search

View File

@ -123,15 +123,13 @@ class Ingester {
}
/**
* Use the given TextExtractor to extract text from the given source. The
* text will be chunked and each chunk passed to Solr to add to the index.
* Read and chunk the source text for indexing in Solr.
*
*
* @param <A> The type of the Appendix provider that provides
* additional text to append to the final chunk.
* @param <T> A subclass of SleuthkitVisibleItem.
* @param extractor The TextExtractor that will be used to extract text from
* the given source.
* @param Reader The reader containing extracted text.
* @param source The source from which text will be extracted, chunked,
* and indexed.
* @param context The ingest job context that can be used to cancel this

View File

@ -19,12 +19,15 @@
package org.sleuthkit.autopsy.keywordsearch;
import com.google.common.collect.ImmutableList;
import com.google.common.io.CharSource;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.stream.Collectors;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
@ -170,8 +173,8 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
* for final statistics at the end of the job.
*
* @param ingestJobId id of ingest job
* @param fileId id of file
* @param status ingest status of the file
* @param fileId id of file
* @param status ingest status of the file
*/
private static void putIngestStatus(long ingestJobId, long fileId, IngestStatus status) {
synchronized (ingestStatus) {
@ -469,15 +472,14 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
* streaming) from the file Divide the file into chunks and index the
* chunks
*
* @param aFile file to extract strings from, divide into
* chunks and index
* @param detectedFormat mime-type detected, or null if none detected
* @param aFile file to extract strings from, divide into chunks and
* index
*
* @return true if the file was text_ingested, false otherwise
*
* @throws IngesterException exception thrown if indexing failed
*/
private boolean extractTextAndIndex(AbstractFile aFile, String detectedFormat) throws IngesterException {
private boolean extractTextAndIndex(AbstractFile aFile) throws IngesterException {
ImageConfig imageConfig = new ImageConfig();
imageConfig.setOCREnabled(KeywordSearchSettings.getOcrOption());
ProcessTerminator terminator = () -> context.fileIngestIsCancelled();
@ -485,20 +487,59 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
try {
TextExtractor extractor = TextExtractorFactory.getExtractor(aFile, extractionContext);
Reader extractedTextReader = extractor.getReader();
Reader fileText = extractor.getReader();
Reader finalReader;
try {
Map<String, String> metadata = extractor.getMetadata();
CharSource formattedMetadata = getMetaDataCharSource(metadata);
//Append the metadata to end of the file text
finalReader = CharSource.concat(new CharSource() {
//Wrap fileText reader for concatenation
@Override
public Reader openStream() throws IOException {
return fileText;
}
}, formattedMetadata).openStream();
} catch (IOException ex) {
logger.log(Level.WARNING, String.format("Could not format extracted metadata for file %s [id=%d]",
aFile.getName(), aFile.getId()), ex);
//Just send file text.
finalReader = fileText;
}
//divide into chunks and index
return Ingester.getDefault().indexText(extractedTextReader, aFile.getId(), aFile.getName(), aFile, context);
return Ingester.getDefault().indexText(finalReader, aFile.getId(), aFile.getName(), aFile, context);
} catch (TextExtractorFactory.NoTextExtractorFound | TextExtractor.InitReaderException ex) {
//No text extractor found... run the default instead
return false;
}
}
/**
* Pretty print the text extractor metadata.
*
* @param metadata The Metadata map to wrap as a CharSource
*
* @return A CharSource for the given Metadata
*/
@NbBundle.Messages({
"KeywordSearchIngestModule.metadataTitle=METADATA"
})
private CharSource getMetaDataCharSource(Map<String, String> metadata) {
return CharSource.wrap(new StringBuilder(
String.format("\n\n------------------------------%s------------------------------\n\n",
Bundle.KeywordSearchIngestModule_metadataTitle()))
.append(metadata.entrySet().stream().sorted(Map.Entry.comparingByKey())
.map(entry -> entry.getKey() + ": " + entry.getValue())
.collect(Collectors.joining("\n"))
));
}
/**
* Extract strings using heuristics from the file and add to index.
*
* @param aFile file to extract strings from, divide into chunks and
* index
* index
*
* @return true if the file was text_ingested, false otherwise
*/
@ -527,9 +568,9 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
/**
* Adds the file to the index. Detects file type, calls extractors, etc.
*
* @param aFile File to analyze
* @param aFile File to analyze
* @param indexContent False if only metadata should be text_ingested.
* True if content and metadata should be index.
* True if content and metadata should be index.
*/
private void indexFile(AbstractFile aFile, boolean indexContent) {
//logger.log(Level.INFO, "Processing AbstractFile: " + abstractFile.getName());
@ -595,7 +636,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
extractStringsAndIndex(aFile);
return;
}
if (!extractTextAndIndex(aFile, fileType)) {
if (!extractTextAndIndex(aFile)) {
// Text extractor not found for file. Extract string only.
putIngestStatus(jobId, aFile.getId(), IngestStatus.SKIPPED_ERROR_TEXTEXTRACT);
} else {

View File

@ -64,7 +64,7 @@ ExtractZone_progress_Msg=Extracting :Zone.Identifer files
ExtractZone_Restricted=Restricted Sites Zone
ExtractZone_Trusted=Trusted Sites Zone
OpenIDE-Module-Display-Category=Ingest Module
OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\n\The module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web activity (sites visited, stored cookies, book marked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\nThe module currently supports Windows only disk images.\nThe plugin is also fully functional when deployed on Windows version of Autopsy.
OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\nThe module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web activity (sites visited, stored cookies, book marked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\nThe module currently supports Windows only disk images.\nThe plugin is also fully functional when deployed on Windows version of Autopsy.
OpenIDE-Module-Name=RecentActivity
OpenIDE-Module-Short-Description=Recent Activity finder ingest module
Chrome.moduleName=Chrome

View File

@ -22,11 +22,16 @@
*/
package org.sleuthkit.autopsy.recentactivity;
import java.io.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.Level;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@ -40,7 +45,6 @@ import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProcessTerminator;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.recentactivity.UsbDeviceIdMapper.USBInfo;
import org.sleuthkit.datamodel.*;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.w3c.dom.Document;
@ -50,6 +54,14 @@ import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.HashSet;
import static java.util.TimeZone.getTimeZone;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
@ -57,7 +69,13 @@ import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
import org.sleuthkit.datamodel.Report;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Extract windows registry data using regripper. Runs two versions of
@ -72,21 +90,19 @@ import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamExce
})
class ExtractRegistry extends Extract {
private final Logger logger = Logger.getLogger(this.getClass().getName());
private String RR_PATH;
private String RR_FULL_PATH;
private Path rrHome; // Path to the Autopsy version of RegRipper
private Path rrFullHome; // Path to the full version of RegRipper
private Content dataSource;
private IngestJobContext context;
final private static UsbDeviceIdMapper USB_MAPPER = new UsbDeviceIdMapper();
final private static String RIP_EXE = "rip.exe";
final private static String RIP_PL = "rip.pl";
final private static int MS_IN_SEC = 1000;
final private static String NEVER_DATE = "Never";
final private static String SECTION_DIVIDER = "-------------------------";
final private static Logger logger = Logger.getLogger(ExtractRegistry.class.getName());
private final List<String> rrCmd = new ArrayList<>();
private final List<String> rrFullCmd = new ArrayList<>();
private final Path rrHome; // Path to the Autopsy version of RegRipper
private final Path rrFullHome; // Path to the full version of RegRipper
private Content dataSource;
private IngestJobContext context;
ExtractRegistry() throws IngestModuleException {
moduleName = NbBundle.getMessage(ExtractIE.class, "ExtractRegistry.moduleName.text");
@ -106,19 +122,19 @@ class ExtractRegistry extends Extract {
executableToRun = RIP_PL;
}
rrHome = rrRoot.toPath();
RR_PATH = rrHome.resolve(executableToRun).toString();
String rrPath = rrHome.resolve(executableToRun).toString();
rrFullHome = rrFullRoot.toPath();
RR_FULL_PATH = rrFullHome.resolve(executableToRun).toString();
if (!(new File(RR_PATH).exists())) {
if (!(new File(rrPath).exists())) {
throw new IngestModuleException(Bundle.RegRipperNotFound());
}
if (!(new File(RR_FULL_PATH).exists())) {
String rrFullPath = rrFullHome.resolve(executableToRun).toString();
if (!(new File(rrFullPath).exists())) {
throw new IngestModuleException(Bundle.RegRipperFullNotFound());
}
if (PlatformUtil.isWindowsOS()) {
rrCmd.add(RR_PATH);
rrFullCmd.add(RR_FULL_PATH);
rrCmd.add(rrPath);
rrFullCmd.add(rrFullPath);
} else {
String perl;
File usrBin = new File("/usr/bin/perl");
@ -131,9 +147,9 @@ class ExtractRegistry extends Extract {
throw new IngestModuleException("perl not found in your system");
}
rrCmd.add(perl);
rrCmd.add(RR_PATH);
rrCmd.add(rrPath);
rrFullCmd.add(perl);
rrFullCmd.add(RR_FULL_PATH);
rrFullCmd.add(rrFullPath);
}
}
@ -224,23 +240,19 @@ class ExtractRegistry extends Extract {
}
// parse the autopsy-specific output
if (regOutputFiles.autopsyPlugins.isEmpty() == false) {
if (parseAutopsyPluginOutput(regOutputFiles.autopsyPlugins, regFile) == false) {
this.addErrorMessage(
NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
this.getName(), regFileName));
}
if (regOutputFiles.autopsyPlugins.isEmpty() == false && parseAutopsyPluginOutput(regOutputFiles.autopsyPlugins, regFile) == false) {
this.addErrorMessage(
NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
this.getName(), regFileName));
}
// create a report for the full output
if (!regOutputFiles.fullPlugins.isEmpty()) {
//parse the full regripper output from SAM hive files
if (regFileNameLocal.toLowerCase().contains("sam")) {
if (parseSamPluginOutput(regOutputFiles.fullPlugins, regFile) == false) {
this.addErrorMessage(
NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
this.getName(), regFileName));
}
if (regFileNameLocal.toLowerCase().contains("sam") && parseSamPluginOutput(regOutputFiles.fullPlugins, regFile) == false) {
this.addErrorMessage(
NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
this.getName(), regFileName));
}
try {
Report report = currentCase.addReport(regOutputFiles.fullPlugins,
@ -259,7 +271,6 @@ class ExtractRegistry extends Extract {
this.addErrorMessage("Error adding regripper output as Autopsy report: " + e.getLocalizedMessage()); //NON-NLS
}
}
// delete the hive
regFileNameLocalFile.delete();
}
@ -273,12 +284,6 @@ class ExtractRegistry extends Extract {
}
}
private class RegOutputFiles {
public String autopsyPlugins = "";
public String fullPlugins = "";
}
/**
* Execute regripper on the given registry.
*
@ -392,11 +397,11 @@ class ExtractRegistry extends Extract {
// that we will submit in a ModuleDataEvent for additional processing.
Collection<BlackboardArtifact> wifiBBartifacts = new ArrayList<>();
for (int i = 0; i < len; i++) {
if (context.dataSourceIngestIsCancelled()) {
return false;
}
Element tempnode = (Element) children.item(i);
String dataType = tempnode.getNodeName();
@ -406,12 +411,11 @@ class ExtractRegistry extends Extract {
Element timenode = (Element) timenodes.item(0);
String etime = timenode.getTextContent();
try {
Long epochtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy").parse(etime).getTime();
mtime = epochtime;
mtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy").parse(etime).getTime();
String Tempdate = mtime.toString();
mtime = Long.valueOf(Tempdate) / MS_IN_SEC;
} catch (ParseException ex) {
logger.log(Level.WARNING, "Failed to parse epoch time when parsing the registry."); //NON-NLS
logger.log(Level.WARNING, "Failed to parse epoch time when parsing the registry.", ex); //NON-NLS
}
}
@ -424,7 +428,6 @@ class ExtractRegistry extends Extract {
Element artroot = (Element) artroots.item(0);
NodeList myartlist = artroot.getChildNodes();
String parentModuleName = RecentActivityExtracterModuleFactory.getModuleName();
String winver = "";
// If all artifact nodes should really go under one Blackboard artifact, need to process it differently
switch (dataType) {
@ -508,7 +511,6 @@ class ExtractRegistry extends Extract {
case "Profiler": // NON-NLS
String os = "";
String procArch = "";
String procId = "";
String tempDir = "";
for (int j = 0; j < myartlist.getLength(); j++) {
Node artchild = myartlist.item(j);
@ -526,7 +528,6 @@ class ExtractRegistry extends Extract {
procArch = value;
break;
case "PROCESSOR_IDENTIFIER": //NON-NLS
procId = value;
break;
case "TEMP": //NON-NLS
tempDir = value;
@ -652,7 +653,7 @@ class ExtractRegistry extends Extract {
try {
Long epochtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy").parse(artnode.getAttribute("mtime")).getTime(); //NON-NLS
itemMtime = epochtime;
itemMtime = itemMtime / MS_IN_SEC;
itemMtime /= MS_IN_SEC;
} catch (ParseException e) {
logger.log(Level.WARNING, "Failed to parse epoch time for installed program artifact."); //NON-NLS
}
@ -738,7 +739,7 @@ class ExtractRegistry extends Extract {
} else {
//add attributes to existing artifact
BlackboardAttribute bbattr = bbart.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_NAME));
if (bbattr == null) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
parentModuleName, username));
@ -852,10 +853,9 @@ class ExtractRegistry extends Extract {
String line = bufferedReader.readLine();
Set<UserInfo> userSet = new HashSet<>();
while (line != null) {
if (line.contains(SECTION_DIVIDER) && previousLine != null) {
if (previousLine.contains(userInfoSection)) {
readUsers(bufferedReader, userSet);
}
if (line.contains(SECTION_DIVIDER) && previousLine != null && previousLine.contains(userInfoSection)) {
readUsers(bufferedReader, userSet);
}
previousLine = line;
line = bufferedReader.readLine();
@ -923,7 +923,7 @@ class ExtractRegistry extends Extract {
} catch (ParseException ex) {
logger.log(Level.SEVERE, "Error parsing the the date from the registry file", ex); //NON-NLS
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error updating TSK_OS_ACCOUNT artifacts to include newly parsed data.", ex); //NON-NLS
logger.log(Level.SEVERE, "Error updating TSK_OS_ACCOUNT artifacts to include newly parsed data.", ex); //NON-NLS
}
return false;
}
@ -953,8 +953,7 @@ class ExtractRegistry extends Extract {
if (line.contains(userNameLabel)) {
String userNameAndIdString = line.replace(userNameLabel, "");
userName = userNameAndIdString.substring(0, userNameAndIdString.lastIndexOf('[')).trim();
}
else if (line.contains(sidLabel) && !userName.isEmpty()){
} else if (line.contains(sidLabel) && !userName.isEmpty()) {
String sid = line.replace(sidLabel, "").trim();
UserInfo userInfo = new UserInfo(userName, sid);
//continue reading this users information until end of file or a blank line between users
@ -980,12 +979,21 @@ class ExtractRegistry extends Extract {
public void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
this.dataSource = dataSource;
this.context = context;
progressBar.progress(Bundle.Progress_Message_Analyze_Registry());
analyzeRegistryFiles();
}
/**
* Private wrapper class for Registry output files
*/
private class RegOutputFiles {
public String autopsyPlugins = "";
public String fullPlugins = "";
}
/**
* Class for organizing information associated with a TSK_OS_ACCOUNT before
* the artifact is created.
@ -1001,7 +1009,7 @@ class ExtractRegistry extends Extract {
/**
* Create a UserInfo object
*
* @param name - the os user account name
* @param name - the os user account name
* @param userSidString - the SID for the user account
*/
private UserInfo(String name, String userSidString) {

View File

@ -1,5 +1,5 @@
#Updated by build script
#Tue, 26 Feb 2019 14:37:44 -0500
#Wed, 08 May 2019 21:37:02 -0400
LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=314
SPLASH_WIDTH=538
@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18
SplashRunningTextColor=0x0
SplashRunningTextFontSize=19
currentVersion=Autopsy 4.10.0
currentVersion=Autopsy 4.11.0

View File

@ -1,4 +1,4 @@
#Updated by build script
#Tue, 26 Feb 2019 14:37:44 -0500
CTL_MainWindow_Title=Autopsy 4.10.0
CTL_MainWindow_Title_No_Project=Autopsy 4.10.0
#Wed, 08 May 2019 21:37:02 -0400
CTL_MainWindow_Title=Autopsy 4.11.0
CTL_MainWindow_Title_No_Project=Autopsy 4.11.0

View File

@ -193,7 +193,7 @@ final class VcardParser {
}
}
}
ThunderbirdMboxFileIngestModule.addArtifactAttribute(name, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME_PERSON, attributes);
ThunderbirdMboxFileIngestModule.addArtifactAttribute(name, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, attributes);
for (Telephone telephone : vcard.getTelephoneNumbers()) {
addPhoneAttributes(telephone, abstractFile, attributes);
@ -412,7 +412,7 @@ final class VcardParser {
type.getValue().toUpperCase().replaceAll("\\s+","").split(","));
for (String splitType : splitTelephoneTypes) {
String attributeTypeName = "TSK_PHONE_" + splitType;
String attributeTypeName = "TSK_PHONE_NUMBER_" + splitType;
try {
BlackboardAttribute.Type attributeType = tskCase.getAttributeType(attributeTypeName);
if (attributeType == null) {