mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-13 08:26:15 +00:00
Merge branch 'develop' of github.com:sleuthkit/autopsy into 5014_known_slack_filtering
This commit is contained in:
commit
698b464bc4
@ -110,11 +110,11 @@
|
|||||||
<target name="getTestDataFiles">
|
<target name="getTestDataFiles">
|
||||||
<mkdir dir="${basedir}/test/qa-functional/data"/>
|
<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=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=1zPlIn1xmOeC1VYKmV3fJHl5qE6E_M7K-" 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=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=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=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=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=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"/>
|
<get src="https://drive.google.com/uc?id=1-vmbmAAb2HBLbf58GpAA97ozGUFiYHbN" dest="${test-input}/CommonFiles_img2_v1.vhd" skipexisting="true"/>
|
||||||
|
@ -181,7 +181,7 @@ final class AddImageWizardSelectDspVisual extends JPanel {
|
|||||||
/**
|
/**
|
||||||
* Create a list of the DataSourceProcessors which should exist as options
|
* Create a list of the DataSourceProcessors which should exist as options
|
||||||
* on this panel. The default Autopsy DataSourceProcessors will appear at
|
* 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
|
* @return dspList a list of DataSourceProcessors which can be chose in this
|
||||||
* panel
|
* panel
|
||||||
@ -200,6 +200,7 @@ final class AddImageWizardSelectDspVisual extends JPanel {
|
|||||||
dspList.add(LocalDiskDSProcessor.getType());
|
dspList.add(LocalDiskDSProcessor.getType());
|
||||||
dspList.add(LocalFilesDSProcessor.getType());
|
dspList.add(LocalFilesDSProcessor.getType());
|
||||||
dspList.add(RawDSProcessor.getType());
|
dspList.add(RawDSProcessor.getType());
|
||||||
|
dspList.add(LogicalImagerDSProcessor.getType());
|
||||||
// now add any addtional DSPs that haven't already been added
|
// now add any addtional DSPs that haven't already been added
|
||||||
for (String dspType : datasourceProcessorsMap.keySet()) {
|
for (String dspType : datasourceProcessorsMap.keySet()) {
|
||||||
if (!dspList.contains(dspType)) {
|
if (!dspList.contains(dspType)) {
|
||||||
|
@ -238,6 +238,13 @@ OpenMultiUserCasePanel.cancelButton.text=Cancel
|
|||||||
OpenMultiUserCasePanel.openSingleUserCaseButton.text=Open Single-User Case...
|
OpenMultiUserCasePanel.openSingleUserCaseButton.text=Open Single-User Case...
|
||||||
OpenMultiUserCasePanel.openSelectedCaseButton.text=Open Selected Case
|
OpenMultiUserCasePanel.openSelectedCaseButton.text=Open Selected Case
|
||||||
OpenMultiUserCasePanel.searchLabel.text=Select any case and start typing to search by case name
|
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.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.desc1Label.text=Unpackage a portable case so it can be opened in Autopsy. Portable cases are created through the
|
||||||
UnpackagePortableCaseDialog.exitButton.text=Exit
|
UnpackagePortableCaseDialog.exitButton.text=Exit
|
||||||
|
@ -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.
|
LogicalEvidenceFilePanel.validatePanel.nonL01Error.text=Only files with the .l01 file extension are supported here.
|
||||||
LogicalFilesDspPanel.subTypeComboBox.l01FileOption.text=Logical evidence file (L01)
|
LogicalFilesDspPanel.subTypeComboBox.l01FileOption.text=Logical evidence file (L01)
|
||||||
LogicalFilesDspPanel.subTypeComboBox.localFilesOption.text=Local files and folders
|
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
|
Menu/Case/OpenRecentCase=Open Recent Case
|
||||||
CTL_CaseDeleteAction=Delete Case
|
CTL_CaseDeleteAction=Delete Case
|
||||||
OpenIDE-Module-Name=Case
|
OpenIDE-Module-Name=Case
|
||||||
@ -440,6 +452,13 @@ OpenMultiUserCasePanel.cancelButton.text=Cancel
|
|||||||
OpenMultiUserCasePanel.openSingleUserCaseButton.text=Open Single-User Case...
|
OpenMultiUserCasePanel.openSingleUserCaseButton.text=Open Single-User Case...
|
||||||
OpenMultiUserCasePanel.openSelectedCaseButton.text=Open Selected Case
|
OpenMultiUserCasePanel.openSelectedCaseButton.text=Open Selected Case
|
||||||
OpenMultiUserCasePanel.searchLabel.text=Select any case and start typing to search by case name
|
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.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.desc1Label.text=Unpackage a portable case so it can be opened in Autopsy. Portable cases are created through the
|
||||||
UnpackagePortableCaseDialog.exitButton.text=Exit
|
UnpackagePortableCaseDialog.exitButton.text=Exit
|
||||||
|
@ -116,7 +116,7 @@
|
|||||||
<Component id="hashValuesNoteLabel" min="-2" max="-2" attributes="0"/>
|
<Component id="hashValuesNoteLabel" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||||
<Component id="errorLabel" min="-2" 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>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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="<String>"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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>
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.communications;
|
|||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.ListSelectionModel;
|
import javax.swing.ListSelectionModel;
|
||||||
@ -31,11 +33,16 @@ import org.openide.explorer.ExplorerManager;
|
|||||||
import org.openide.explorer.ExplorerUtils;
|
import org.openide.explorer.ExplorerUtils;
|
||||||
import org.openide.nodes.AbstractNode;
|
import org.openide.nodes.AbstractNode;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.nodes.Node;
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.openide.util.lookup.ProxyLookup;
|
import org.openide.util.lookup.ProxyLookup;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
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.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||||
|
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
@ -56,9 +63,10 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro
|
|||||||
|
|
||||||
private final Outline outline;
|
private final Outline outline;
|
||||||
|
|
||||||
private final ExplorerManager messageBrowserEM = new ExplorerManager();
|
|
||||||
private final ExplorerManager accountsTableEM = new ExplorerManager();
|
private final ExplorerManager accountsTableEM = new ExplorerManager();
|
||||||
|
|
||||||
|
final RelationshipBrowser relationshipBrowser;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This lookup proxies the selection lookup of both he accounts table and
|
* This lookup proxies the selection lookup of both he accounts table and
|
||||||
* the messages table.
|
* the messages table.
|
||||||
@ -79,19 +87,28 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro
|
|||||||
outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||||
outline.setColumnSorted(3, false, 1); //it would be nice if the column index wasn't hardcoded
|
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 -> {
|
accountsTableEM.addPropertyChangeListener(evt -> {
|
||||||
if (ExplorerManager.PROP_ROOT_CONTEXT.equals(evt.getPropertyName())) {
|
if (ExplorerManager.PROP_ROOT_CONTEXT.equals(evt.getPropertyName())) {
|
||||||
SwingUtilities.invokeLater(this::setColumnWidths);
|
SwingUtilities.invokeLater(this::setColumnWidths);
|
||||||
} else if (ExplorerManager.PROP_EXPLORED_CONTEXT.equals(evt.getPropertyName())) {
|
} else if (ExplorerManager.PROP_EXPLORED_CONTEXT.equals(evt.getPropertyName())) {
|
||||||
SwingUtilities.invokeLater(this::setColumnWidths);
|
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(relationshipBrowser.getLookup(),
|
||||||
|
|
||||||
proxyLookup = new ProxyLookup(
|
|
||||||
messageBrowser.getLookup(),
|
|
||||||
ExplorerUtils.createLookup(accountsTableEM, getActionMap()));
|
ExplorerUtils.createLookup(accountsTableEM, getActionMap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,21 +32,16 @@ VisualizationPanel.zoomInButton.toolTipText=Zoom in
|
|||||||
VisualizationPanel.zoomInButton.text=
|
VisualizationPanel.zoomInButton.text=
|
||||||
VisualizationPanel.zoomOutButton.toolTipText=Zoom out
|
VisualizationPanel.zoomOutButton.toolTipText=Zoom out
|
||||||
VisualizationPanel.zoomOutButton.text=
|
VisualizationPanel.zoomOutButton.text=
|
||||||
<<<<<<< HEAD
|
VisualizationPanel.fastOrganicLayoutButton.text=
|
||||||
VisualizationPanel.fastOrganicLayoutButton.text=Redraw
|
|
||||||
VisualizationPanel.clearVizButton.text_1=Clear
|
|
||||||
VisualizationPanel.backButton.text_1=
|
VisualizationPanel.backButton.text_1=
|
||||||
VisualizationPanel.forwardButton.text=
|
|
||||||
=======
|
|
||||||
VisualizationPanel.circleLayoutButton.text=Circle
|
VisualizationPanel.circleLayoutButton.text=Circle
|
||||||
VisualizationPanel.organicLayoutButton.text=Organic
|
VisualizationPanel.organicLayoutButton.text=Organic
|
||||||
VisualizationPanel.fastOrganicLayoutButton.text=
|
|
||||||
VisualizationPanel.hierarchyLayoutButton.text=Hierarchical
|
VisualizationPanel.hierarchyLayoutButton.text=Hierarchical
|
||||||
VisualizationPanel.clearVizButton.text_1=
|
VisualizationPanel.clearVizButton.text_1=
|
||||||
VisualizationPanel.snapshotButton.text_1=Snapshot Report
|
VisualizationPanel.snapshotButton.text_1=Snapshot Report
|
||||||
>>>>>>> develop
|
|
||||||
VisualizationPanel.clearVizButton.actionCommand=
|
VisualizationPanel.clearVizButton.actionCommand=
|
||||||
VisualizationPanel.backButton.toolTipText=Click to go back
|
VisualizationPanel.backButton.toolTipText=Click to go back
|
||||||
VisualizationPanel.forwardButton.toolTipText=Click to go forward
|
VisualizationPanel.forwardButton.toolTipText=Click to go forward
|
||||||
VisualizationPanel.fastOrganicLayoutButton.toolTipText=Click to redraw the chart
|
VisualizationPanel.fastOrganicLayoutButton.toolTipText=Click to redraw the chart
|
||||||
VisualizationPanel.clearVizButton.toolTipText=Click to clear the chart
|
VisualizationPanel.clearVizButton.toolTipText=Click to clear the chart
|
||||||
|
VisualizationPanel.forwardButton.text=
|
||||||
|
@ -22,7 +22,6 @@ FiltersPanel.refreshButton.text=Refresh
|
|||||||
FiltersPanel.deviceRequiredLabel.text=Select at least one.
|
FiltersPanel.deviceRequiredLabel.text=Select at least one.
|
||||||
FiltersPanel.accountTypeRequiredLabel.text=Select at least one.
|
FiltersPanel.accountTypeRequiredLabel.text=Select at least one.
|
||||||
FiltersPanel.needsRefreshLabel.text=Displayed data is out of date. Press Refresh.
|
FiltersPanel.needsRefreshLabel.text=Displayed data is out of date. Press Refresh.
|
||||||
MessageBrowser.DataResultViewerTable.title=Messages
|
|
||||||
OpenCVTAction.displayName=Communications
|
OpenCVTAction.displayName=Communications
|
||||||
PinAccountsAction.pluralText=Add Selected Accounts to Visualization
|
PinAccountsAction.pluralText=Add Selected Accounts to Visualization
|
||||||
PinAccountsAction.singularText=Add Selected Account to Visualization
|
PinAccountsAction.singularText=Add Selected Account to Visualization
|
||||||
@ -76,24 +75,19 @@ VisualizationPanel.zoomInButton.toolTipText=Zoom in
|
|||||||
VisualizationPanel.zoomInButton.text=
|
VisualizationPanel.zoomInButton.text=
|
||||||
VisualizationPanel.zoomOutButton.toolTipText=Zoom out
|
VisualizationPanel.zoomOutButton.toolTipText=Zoom out
|
||||||
VisualizationPanel.zoomOutButton.text=
|
VisualizationPanel.zoomOutButton.text=
|
||||||
<<<<<<< HEAD
|
VisualizationPanel.fastOrganicLayoutButton.text=
|
||||||
VisualizationPanel.fastOrganicLayoutButton.text=Redraw
|
|
||||||
VisualizationPanel.clearVizButton.text_1=Clear
|
|
||||||
VisualizationPanel.backButton.text_1=
|
VisualizationPanel.backButton.text_1=
|
||||||
VisualizationPanel.forwardButton.text=
|
|
||||||
=======
|
|
||||||
VisualizationPanel.circleLayoutButton.text=Circle
|
VisualizationPanel.circleLayoutButton.text=Circle
|
||||||
VisualizationPanel.organicLayoutButton.text=Organic
|
VisualizationPanel.organicLayoutButton.text=Organic
|
||||||
VisualizationPanel.fastOrganicLayoutButton.text=
|
|
||||||
VisualizationPanel.hierarchyLayoutButton.text=Hierarchical
|
VisualizationPanel.hierarchyLayoutButton.text=Hierarchical
|
||||||
VisualizationPanel.clearVizButton.text_1=
|
VisualizationPanel.clearVizButton.text_1=
|
||||||
VisualizationPanel.snapshotButton.text_1=Snapshot Report
|
VisualizationPanel.snapshotButton.text_1=Snapshot Report
|
||||||
>>>>>>> develop
|
|
||||||
VisualizationPanel.clearVizButton.actionCommand=
|
VisualizationPanel.clearVizButton.actionCommand=
|
||||||
VisualizationPanel.backButton.toolTipText=Click to go back
|
VisualizationPanel.backButton.toolTipText=Click to go back
|
||||||
VisualizationPanel.forwardButton.toolTipText=Click to go forward
|
VisualizationPanel.forwardButton.toolTipText=Click to go forward
|
||||||
VisualizationPanel.fastOrganicLayoutButton.toolTipText=Click to redraw the chart
|
VisualizationPanel.fastOrganicLayoutButton.toolTipText=Click to redraw the chart
|
||||||
VisualizationPanel.clearVizButton.toolTipText=Click to clear the chart
|
VisualizationPanel.clearVizButton.toolTipText=Click to clear the chart
|
||||||
|
VisualizationPanel.forwardButton.text=
|
||||||
VisualizationPanel_action_dialogs_title=Communications
|
VisualizationPanel_action_dialogs_title=Communications
|
||||||
VisualizationPanel_action_name_text=Snapshot Report
|
VisualizationPanel_action_name_text=Snapshot Report
|
||||||
VisualizationPanel_module_name=Communications
|
VisualizationPanel_module_name=Communications
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
package org.sleuthkit.autopsy.communications;
|
package org.sleuthkit.autopsy.communications;
|
||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -61,8 +62,11 @@ public final class CVTTopComponent extends TopComponent {
|
|||||||
associateLookup(proxyLookup);
|
associateLookup(proxyLookup);
|
||||||
// Make sure the Global Actions Context is proxying the selection of the active tab.
|
// Make sure the Global Actions Context is proxying the selection of the active tab.
|
||||||
browseVisualizeTabPane.addChangeListener(changeEvent -> {
|
browseVisualizeTabPane.addChangeListener(changeEvent -> {
|
||||||
Lookup.Provider selectedComponent = (Lookup.Provider) browseVisualizeTabPane.getSelectedComponent();
|
Component selectedComponent = browseVisualizeTabPane.getSelectedComponent();
|
||||||
proxyLookup.setNewLookups(selectedComponent.getLookup());
|
if(selectedComponent instanceof Lookup.Provider) {
|
||||||
|
Lookup lookup = ((Lookup.Provider)selectedComponent).getLookup();
|
||||||
|
proxyLookup.setNewLookups(lookup);
|
||||||
|
}
|
||||||
filtersPane.setDeviceAccountTypeEnabled(browseVisualizeTabPane.getSelectedIndex() != 0);
|
filtersPane.setDeviceAccountTypeEnabled(browseVisualizeTabPane.getSelectedIndex() != 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -52,6 +52,7 @@ import org.sleuthkit.datamodel.CommunicationsFilter.DateRangeFilter;
|
|||||||
import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter;
|
import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter;
|
||||||
import org.sleuthkit.datamodel.DataSource;
|
import org.sleuthkit.datamodel.DataSource;
|
||||||
import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG;
|
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 static org.sleuthkit.datamodel.Relationship.Type.MESSAGE;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
@ -598,7 +599,7 @@ final public class FiltersPanel extends JPanel {
|
|||||||
commsFilter.addAndFilter(getAccountTypeFilter());
|
commsFilter.addAndFilter(getAccountTypeFilter());
|
||||||
commsFilter.addAndFilter(getDateRangeFilter());
|
commsFilter.addAndFilter(getDateRangeFilter());
|
||||||
commsFilter.addAndFilter(new CommunicationsFilter.RelationshipTypeFilter(
|
commsFilter.addAndFilter(new CommunicationsFilter.RelationshipTypeFilter(
|
||||||
ImmutableSet.of(CALL_LOG, MESSAGE)));
|
ImmutableSet.of(CALL_LOG, MESSAGE, CONTACT)));
|
||||||
return commsFilter;
|
return commsFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
|
|
||||||
}
|
|
@ -26,9 +26,9 @@ import org.openide.util.lookup.ProxyLookup;
|
|||||||
* delegated to.
|
* delegated to.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
final class ModifiableProxyLookup extends ProxyLookup {
|
final public class ModifiableProxyLookup extends ProxyLookup {
|
||||||
|
|
||||||
ModifiableProxyLookup(final Lookup... lookups) {
|
public ModifiableProxyLookup(final Lookup... lookups) {
|
||||||
super(lookups);
|
super(lookups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,12 +28,12 @@ import org.sleuthkit.datamodel.Account;
|
|||||||
/**
|
/**
|
||||||
* Utility class with helpers for dealing with accounts.
|
* Utility class with helpers for dealing with accounts.
|
||||||
*/
|
*/
|
||||||
class Utils {
|
public final class Utils {
|
||||||
|
|
||||||
private Utils() {
|
private Utils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static ZoneId getUserPreferredZoneId() {
|
static public ZoneId getUserPreferredZoneId() {
|
||||||
ZoneId zone = UserPreferences.displayTimesInLocalTime() ?
|
ZoneId zone = UserPreferences.displayTimesInLocalTime() ?
|
||||||
ZoneOffset.systemDefault() : TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()).toZoneId();
|
ZoneOffset.systemDefault() : TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()).toZoneId();
|
||||||
return zone;
|
return zone;
|
||||||
@ -44,7 +44,7 @@ class Utils {
|
|||||||
*
|
*
|
||||||
* @return The path of the icon for the given Account Type.
|
* @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);
|
return Accounts.getIconFilePath(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,6 @@ import java.awt.event.MouseEvent;
|
|||||||
import java.awt.event.MouseWheelEvent;
|
import java.awt.event.MouseWheelEvent;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyVetoException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@ -62,11 +61,11 @@ import java.nio.file.Paths;
|
|||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
@ -98,23 +97,20 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import org.controlsfx.control.Notifications;
|
import org.controlsfx.control.Notifications;
|
||||||
import org.jdesktop.layout.GroupLayout;
|
import org.jdesktop.layout.GroupLayout;
|
||||||
import org.jdesktop.layout.LayoutStyle;
|
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.NbBundle;
|
||||||
import org.openide.util.lookup.ProxyLookup;
|
|
||||||
import org.openide.windows.WindowManager;
|
import org.openide.windows.WindowManager;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
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.communications.snapshot.CommSnapShotReportWriter;
|
||||||
import org.sleuthkit.autopsy.coreutils.FileUtil;
|
import org.sleuthkit.autopsy.coreutils.FileUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||||
import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator;
|
import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator;
|
||||||
|
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
/**
|
/**
|
||||||
* A panel that goes in the Visualize tab of the Communications Visualization
|
* 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.
|
* actions to work correctly.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
@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 long serialVersionUID = 1L;
|
||||||
private static final Logger logger = Logger.getLogger(VisualizationPanel.class.getName());
|
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")
|
@NbBundle.Messages("VisualizationPanel.cancelButton.text=Cancel")
|
||||||
private static final String CANCEL = Bundle.VisualizationPanel_cancelButton_text();
|
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 Frame windowAncestor;
|
||||||
|
|
||||||
private CommunicationsManager commsManager;
|
private CommunicationsManager commsManager;
|
||||||
@ -162,6 +155,8 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
|||||||
private final Map<NamedGraphLayout, JButton> layoutButtons = new HashMap<>();
|
private final Map<NamedGraphLayout, JButton> layoutButtons = new HashMap<>();
|
||||||
private NamedGraphLayout currentLayout;
|
private NamedGraphLayout currentLayout;
|
||||||
|
|
||||||
|
private final RelationshipBrowser relationshipBrowser;
|
||||||
|
|
||||||
private final StateManager stateManager;
|
private final StateManager stateManager;
|
||||||
|
|
||||||
@NbBundle.Messages("VisalizationPanel.paintingError=Problem painting visualization.")
|
@NbBundle.Messages("VisalizationPanel.paintingError=Problem painting visualization.")
|
||||||
@ -226,12 +221,8 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
|||||||
graphComponent.getGraphControl().addMouseWheelListener(graphMouseListener);
|
graphComponent.getGraphControl().addMouseWheelListener(graphMouseListener);
|
||||||
graphComponent.getGraphControl().addMouseListener(graphMouseListener);
|
graphComponent.getGraphControl().addMouseListener(graphMouseListener);
|
||||||
|
|
||||||
final MessageBrowser messageBrowser = new MessageBrowser(vizEM, gacEM);
|
relationshipBrowser = new RelationshipBrowser();
|
||||||
splitPane.setRightComponent(messageBrowser);
|
splitPane.setRightComponent(relationshipBrowser);
|
||||||
proxyLookup = new ProxyLookup(
|
|
||||||
ExplorerUtils.createLookup(vizEM, getActionMap()),
|
|
||||||
messageBrowser.getLookup()
|
|
||||||
);
|
|
||||||
|
|
||||||
//feed selection to explorermanager
|
//feed selection to explorermanager
|
||||||
graph.getSelectionModel().addListener(mxEvent.CHANGE, new SelectionListener());
|
graph.getSelectionModel().addListener(mxEvent.CHANGE, new SelectionListener());
|
||||||
@ -258,11 +249,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
|||||||
setStateButtonsEnabled();
|
setStateButtonsEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Lookup getLookup() {
|
|
||||||
return proxyLookup;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
void handle(LockedVertexModel.VertexLockEvent event) {
|
void handle(LockedVertexModel.VertexLockEvent event) {
|
||||||
final Set<mxCell> vertices = event.getVertices();
|
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
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
|
||||||
splitPane = new JSplitPane();
|
splitPane = new javax.swing.JSplitPane();
|
||||||
borderLayoutPanel = new JPanel();
|
borderLayoutPanel = new javax.swing.JPanel();
|
||||||
placeHolderPanel = new JPanel();
|
placeHolderPanel = new javax.swing.JPanel();
|
||||||
jTextArea1 = new JTextArea();
|
jTextArea1 = new javax.swing.JTextArea();
|
||||||
toolbar = new JPanel();
|
toolbar = new javax.swing.JPanel();
|
||||||
fastOrganicLayoutButton = new JButton();
|
fastOrganicLayoutButton = new javax.swing.JButton();
|
||||||
zoomOutButton = new JButton();
|
zoomOutButton = new javax.swing.JButton();
|
||||||
zoomInButton = new JButton();
|
zoomInButton = new javax.swing.JButton();
|
||||||
zoomActualButton = new JButton();
|
zoomActualButton = new javax.swing.JButton();
|
||||||
fitZoomButton = new JButton();
|
fitZoomButton = new javax.swing.JButton();
|
||||||
jLabel2 = new JLabel();
|
jLabel2 = new javax.swing.JLabel();
|
||||||
zoomLabel = new JLabel();
|
zoomLabel = new javax.swing.JLabel();
|
||||||
clearVizButton = new JButton();
|
clearVizButton = new javax.swing.JButton();
|
||||||
jSeparator2 = new JToolBar.Separator();
|
jSeparator2 = new javax.swing.JToolBar.Separator();
|
||||||
backButton = new JButton();
|
backButton = new javax.swing.JButton();
|
||||||
forwardButton = new JButton();
|
forwardButton = new javax.swing.JButton();
|
||||||
snapshotButton = new JButton();
|
snapshotButton = new javax.swing.JButton();
|
||||||
jSeparator3 = new JToolBar.Separator();
|
jSeparator3 = new javax.swing.JToolBar.Separator();
|
||||||
jSeparator4 = new JToolBar.Separator();
|
jSeparator4 = new javax.swing.JToolBar.Separator();
|
||||||
notificationsJFXPanel = new JFXPanel();
|
notificationsJFXPanel = new javafx.embed.swing.JFXPanel();
|
||||||
|
|
||||||
setLayout(new BorderLayout());
|
setLayout(new java.awt.BorderLayout());
|
||||||
|
|
||||||
splitPane.setDividerLocation(800);
|
splitPane.setDividerLocation(800);
|
||||||
splitPane.setResizeWeight(0.5);
|
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.setColumns(20);
|
||||||
jTextArea1.setLineWrap(true);
|
jTextArea1.setLineWrap(true);
|
||||||
jTextArea1.setRows(5);
|
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);
|
placeHolderPanel.setLayout(placeHolderPanelLayout);
|
||||||
placeHolderPanelLayout.setHorizontalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING)
|
placeHolderPanelLayout.setHorizontalGroup(
|
||||||
|
placeHolderPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
|
||||||
.add(placeHolderPanelLayout.createSequentialGroup()
|
.add(placeHolderPanelLayout.createSequentialGroup()
|
||||||
.addContainerGap(250, Short.MAX_VALUE)
|
.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))
|
.addContainerGap(423, Short.MAX_VALUE))
|
||||||
);
|
);
|
||||||
placeHolderPanelLayout.setVerticalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING)
|
placeHolderPanelLayout.setVerticalGroup(
|
||||||
|
placeHolderPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
|
||||||
.add(placeHolderPanelLayout.createSequentialGroup()
|
.add(placeHolderPanelLayout.createSequentialGroup()
|
||||||
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
.add(jTextArea1, GroupLayout.PREFERRED_SIZE, 47, GroupLayout.PREFERRED_SIZE)
|
.add(jTextArea1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 47, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||||
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
.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.setIcon(new javax.swing.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.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.text")); // NOI18N
|
||||||
fastOrganicLayoutButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.toolTipText")); // NOI18N
|
fastOrganicLayoutButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.toolTipText")); // NOI18N
|
||||||
fastOrganicLayoutButton.setFocusable(false);
|
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.setIcon(new javax.swing.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.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.text")); // NOI18N
|
||||||
zoomOutButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.toolTipText")); // NOI18N
|
zoomOutButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.toolTipText")); // NOI18N
|
||||||
zoomOutButton.setFocusable(false);
|
zoomOutButton.setFocusable(false);
|
||||||
zoomOutButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
zoomOutButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||||
zoomOutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
zoomOutButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
||||||
zoomOutButton.addActionListener(new ActionListener() {
|
zoomOutButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
zoomOutButtonActionPerformed(evt);
|
zoomOutButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
zoomInButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png"))); // NOI18N
|
zoomInButton.setIcon(new javax.swing.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.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.text")); // NOI18N
|
||||||
zoomInButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.toolTipText")); // NOI18N
|
zoomInButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.toolTipText")); // NOI18N
|
||||||
zoomInButton.setFocusable(false);
|
zoomInButton.setFocusable(false);
|
||||||
zoomInButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
zoomInButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||||
zoomInButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
zoomInButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
||||||
zoomInButton.addActionListener(new ActionListener() {
|
zoomInButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
zoomInButtonActionPerformed(evt);
|
zoomInButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
zoomActualButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png"))); // NOI18N
|
zoomActualButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png"))); // NOI18N
|
||||||
zoomActualButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.text")); // NOI18N
|
zoomActualButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.text")); // NOI18N
|
||||||
zoomActualButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.toolTipText")); // NOI18N
|
zoomActualButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.toolTipText")); // NOI18N
|
||||||
zoomActualButton.setFocusable(false);
|
zoomActualButton.setFocusable(false);
|
||||||
zoomActualButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
zoomActualButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||||
zoomActualButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
zoomActualButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
||||||
zoomActualButton.addActionListener(new ActionListener() {
|
zoomActualButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
zoomActualButtonActionPerformed(evt);
|
zoomActualButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
fitZoomButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png"))); // NOI18N
|
fitZoomButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png"))); // NOI18N
|
||||||
fitZoomButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.text")); // NOI18N
|
fitZoomButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.text")); // NOI18N
|
||||||
fitZoomButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.toolTipText")); // NOI18N
|
fitZoomButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.toolTipText")); // NOI18N
|
||||||
fitZoomButton.setFocusable(false);
|
fitZoomButton.setFocusable(false);
|
||||||
fitZoomButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
fitZoomButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||||
fitZoomButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
fitZoomButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
||||||
fitZoomButton.addActionListener(new ActionListener() {
|
fitZoomButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
fitZoomButtonActionPerformed(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.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/broom.png"))); // NOI18N
|
||||||
clearVizButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.text_1")); // NOI18N
|
clearVizButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.text_1")); // NOI18N
|
||||||
clearVizButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.toolTipText")); // NOI18N
|
clearVizButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.toolTipText")); // NOI18N
|
||||||
clearVizButton.setActionCommand(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.actionCommand")); // NOI18N
|
clearVizButton.setActionCommand(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.actionCommand")); // NOI18N
|
||||||
clearVizButton.addActionListener(new ActionListener() {
|
clearVizButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
clearVizButtonActionPerformed(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.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_previous.png"))); // NOI18N
|
||||||
backButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.text_1")); // NOI18N
|
backButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.text_1")); // NOI18N
|
||||||
backButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.toolTipText")); // NOI18N
|
backButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.toolTipText")); // NOI18N
|
||||||
backButton.addActionListener(new ActionListener() {
|
backButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
backButtonActionPerformed(evt);
|
backButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
forwardButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_next.png"))); // NOI18N
|
forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_next.png"))); // NOI18N
|
||||||
forwardButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.text")); // NOI18N
|
forwardButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.text")); // NOI18N
|
||||||
forwardButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.toolTipText")); // NOI18N
|
forwardButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.toolTipText")); // NOI18N
|
||||||
forwardButton.setHorizontalTextPosition(SwingConstants.LEADING);
|
forwardButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
|
||||||
forwardButton.addActionListener(new ActionListener() {
|
forwardButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
forwardButtonActionPerformed(evt);
|
forwardButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
snapshotButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/report/images/image.png"))); // NOI18N
|
snapshotButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/report/images/image.png"))); // NOI18N
|
||||||
snapshotButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.snapshotButton.text_1")); // NOI18N
|
snapshotButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.snapshotButton.text_1")); // NOI18N
|
||||||
snapshotButton.addActionListener(new ActionListener() {
|
snapshotButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
snapshotButtonActionPerformed(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);
|
toolbar.setLayout(toolbarLayout);
|
||||||
toolbarLayout.setHorizontalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING)
|
toolbarLayout.setHorizontalGroup(
|
||||||
|
toolbarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
|
||||||
.add(toolbarLayout.createSequentialGroup()
|
.add(toolbarLayout.createSequentialGroup()
|
||||||
.addContainerGap()
|
.addContainerGap()
|
||||||
.add(backButton)
|
.add(backButton)
|
||||||
.addPreferredGap(LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(forwardButton)
|
.add(forwardButton)
|
||||||
.addPreferredGap(LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(jSeparator4, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
|
.add(jSeparator4, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 10, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(fastOrganicLayoutButton)
|
.add(fastOrganicLayoutButton)
|
||||||
.addPreferredGap(LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(clearVizButton)
|
.add(clearVizButton)
|
||||||
.addPreferredGap(LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(jSeparator2, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
|
.add(jSeparator2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 10, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(jLabel2)
|
.add(jLabel2)
|
||||||
.addPreferredGap(LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(zoomLabel)
|
.add(zoomLabel)
|
||||||
.addPreferredGap(LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(zoomOutButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
|
.add(zoomOutButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 32, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(zoomInButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
|
.add(zoomInButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 32, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(zoomActualButton, GroupLayout.PREFERRED_SIZE, 33, GroupLayout.PREFERRED_SIZE)
|
.add(zoomActualButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 33, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(fitZoomButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
|
.add(fitZoomButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 32, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(jSeparator3, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
|
.add(jSeparator3, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 10, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(snapshotButton)
|
.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(toolbarLayout.createSequentialGroup()
|
||||||
.add(3, 3, 3)
|
.add(3, 3, 3)
|
||||||
.add(toolbarLayout.createParallelGroup(GroupLayout.CENTER)
|
.add(toolbarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.CENTER)
|
||||||
.add(fastOrganicLayoutButton)
|
.add(fastOrganicLayoutButton)
|
||||||
.add(zoomOutButton)
|
.add(zoomOutButton)
|
||||||
.add(zoomInButton, 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, GroupLayout.DEFAULT_SIZE, 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, GroupLayout.DEFAULT_SIZE, 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(jLabel2)
|
||||||
.add(zoomLabel)
|
.add(zoomLabel)
|
||||||
.add(clearVizButton)
|
.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(backButton)
|
||||||
.add(forwardButton)
|
.add(forwardButton)
|
||||||
.add(snapshotButton)
|
.add(snapshotButton)
|
||||||
.add(jSeparator3, 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, GroupLayout.DEFAULT_SIZE, 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))
|
.add(3, 3, 3))
|
||||||
);
|
);
|
||||||
|
|
||||||
borderLayoutPanel.add(toolbar, BorderLayout.PAGE_START);
|
borderLayoutPanel.add(toolbar, java.awt.BorderLayout.PAGE_START);
|
||||||
borderLayoutPanel.add(notificationsJFXPanel, BorderLayout.PAGE_END);
|
borderLayoutPanel.add(notificationsJFXPanel, java.awt.BorderLayout.PAGE_END);
|
||||||
|
|
||||||
splitPane.setLeftComponent(borderLayoutPanel);
|
splitPane.setLeftComponent(borderLayoutPanel);
|
||||||
|
|
||||||
add(splitPane, BorderLayout.CENTER);
|
add(splitPane, java.awt.BorderLayout.CENTER);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
private void fitZoomButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_fitZoomButtonActionPerformed
|
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
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private JButton backButton;
|
private javax.swing.JButton backButton;
|
||||||
private JPanel borderLayoutPanel;
|
private javax.swing.JPanel borderLayoutPanel;
|
||||||
private JButton clearVizButton;
|
private javax.swing.JButton clearVizButton;
|
||||||
private JButton fastOrganicLayoutButton;
|
private javax.swing.JButton fastOrganicLayoutButton;
|
||||||
private JButton fitZoomButton;
|
private javax.swing.JButton fitZoomButton;
|
||||||
private JButton forwardButton;
|
private javax.swing.JButton forwardButton;
|
||||||
private JLabel jLabel2;
|
private javax.swing.JLabel jLabel2;
|
||||||
private JToolBar.Separator jSeparator2;
|
private javax.swing.JToolBar.Separator jSeparator2;
|
||||||
private JToolBar.Separator jSeparator3;
|
private javax.swing.JToolBar.Separator jSeparator3;
|
||||||
private JToolBar.Separator jSeparator4;
|
private javax.swing.JToolBar.Separator jSeparator4;
|
||||||
private JTextArea jTextArea1;
|
private javax.swing.JTextArea jTextArea1;
|
||||||
private JFXPanel notificationsJFXPanel;
|
private javafx.embed.swing.JFXPanel notificationsJFXPanel;
|
||||||
private JPanel placeHolderPanel;
|
private javax.swing.JPanel placeHolderPanel;
|
||||||
private JButton snapshotButton;
|
private javax.swing.JButton snapshotButton;
|
||||||
private JSplitPane splitPane;
|
private javax.swing.JSplitPane splitPane;
|
||||||
private JPanel toolbar;
|
private javax.swing.JPanel toolbar;
|
||||||
private JButton zoomActualButton;
|
private javax.swing.JButton zoomActualButton;
|
||||||
private JButton zoomInButton;
|
private javax.swing.JButton zoomInButton;
|
||||||
private JLabel zoomLabel;
|
private javax.swing.JLabel zoomLabel;
|
||||||
private JButton zoomOutButton;
|
private javax.swing.JButton zoomOutButton;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -922,40 +912,25 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
|||||||
@Override
|
@Override
|
||||||
public void invoke(Object sender, mxEventObject evt) {
|
public void invoke(Object sender, mxEventObject evt) {
|
||||||
Object[] selectionCells = graph.getSelectionCells();
|
Object[] selectionCells = graph.getSelectionCells();
|
||||||
Node rootNode = Node.EMPTY;
|
|
||||||
Node[] selectedNodes = new Node[0];
|
|
||||||
if (selectionCells.length > 0) {
|
if (selectionCells.length > 0) {
|
||||||
mxICell[] selectedCells = Arrays.asList(selectionCells).toArray(new mxCell[selectionCells.length]);
|
mxICell[] selectedCells = Arrays.asList(selectionCells).toArray(new mxCell[selectionCells.length]);
|
||||||
HashSet<Content> relationshipSources = new HashSet<>();
|
HashSet<AccountDeviceInstance> deviceInstances = new HashSet<>();
|
||||||
HashSet<AccountDeviceInstanceKey> adis = new HashSet<>();
|
|
||||||
for (mxICell cell : selectedCells) {
|
for (mxICell cell : selectedCells) {
|
||||||
if (cell.isEdge()) {
|
if (cell.isEdge()) {
|
||||||
mxICell source = (mxICell) graph.getModel().getTerminal(cell, true);
|
mxICell source = (mxICell) graph.getModel().getTerminal(cell, true);
|
||||||
AccountDeviceInstanceKey account1 = (AccountDeviceInstanceKey) source.getValue();
|
|
||||||
mxICell target = (mxICell) graph.getModel().getTerminal(cell, false);
|
mxICell target = (mxICell) graph.getModel().getTerminal(cell, false);
|
||||||
AccountDeviceInstanceKey account2 = (AccountDeviceInstanceKey) target.getValue();
|
|
||||||
try {
|
deviceInstances.add(((AccountDeviceInstanceKey) source.getValue()).getAccountDeviceInstance());
|
||||||
final List<Content> relationshipSources1 = commsManager.getRelationshipSources(
|
deviceInstances.add(((AccountDeviceInstanceKey) target.getValue()).getAccountDeviceInstance());
|
||||||
account1.getAccountDeviceInstance(),
|
|
||||||
account2.getAccountDeviceInstance(),
|
|
||||||
currentFilter);
|
|
||||||
relationshipSources.addAll(relationshipSources1);
|
|
||||||
} catch (TskCoreException tskCoreException) {
|
|
||||||
logger.log(Level.SEVERE, " Error getting relationsips....", tskCoreException);
|
|
||||||
}
|
|
||||||
} else if (cell.isVertex()) {
|
} else if (cell.isVertex()) {
|
||||||
adis.add((AccountDeviceInstanceKey) cell.getValue());
|
deviceInstances.add(((AccountDeviceInstanceKey) cell.getValue()).getAccountDeviceInstance());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rootNode = SelectionNode.createFromAccountsAndRelationships(relationshipSources, adis, currentFilter, commsManager);
|
relationshipBrowser.setSelectionInfo(new SelectionInfo(deviceInstances, currentFilter));
|
||||||
selectedNodes = new Node[]{rootNode};
|
} else {
|
||||||
}
|
relationshipBrowser.setSelectionInfo(new SelectionInfo(Collections.EMPTY_SET, currentFilter));
|
||||||
vizEM.setRootContext(rootNode);
|
|
||||||
try {
|
|
||||||
vizEM.setSelectedNodes(selectedNodes);
|
|
||||||
} catch (PropertyVetoException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Selection vetoed.", ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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:
|
@ -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
|
@ -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, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="org.openide.explorer.propertysheet.PropertySheet" name="propertySheet">
|
||||||
|
<Properties>
|
||||||
|
<Property name="descriptionAreaVisible" type="boolean" value="false"/>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
@ -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
|
||||||
|
}
|
161
Core/src/org/sleuthkit/autopsy/communications/relationships/ContactNode.java
Executable file
161
Core/src/org/sleuthkit/autopsy/communications/relationships/ContactNode.java
Executable 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();
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
186
Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java
Executable file
186
Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java
Executable 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
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
68
Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.form
Executable file
68
Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.form
Executable 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>
|
233
Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java
Executable file
233
Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java
Executable 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
|
||||||
|
|
||||||
|
}
|
@ -16,7 +16,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.communications;
|
package org.sleuthkit.autopsy.communications.relationships;
|
||||||
|
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import org.openide.explorer.ExplorerManager;
|
import org.openide.explorer.ExplorerManager;
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2017-2018 Basis Technology Corp.
|
* Copyright 2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -16,7 +16,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.communications;
|
package org.sleuthkit.autopsy.communications.relationships;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
@ -25,12 +25,12 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
|
||||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME;
|
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_SENT;
|
||||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START;
|
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.Tag;
|
||||||
import org.sleuthkit.datamodel.TimeUtilities;
|
import org.sleuthkit.datamodel.TimeUtilities;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
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);
|
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);
|
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
|
@Override
|
||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
Sheet sheet = new Sheet();
|
Sheet sheet = super.createSheet();
|
||||||
List<Tag> tags = getAllTagsFromDatabase();
|
List<Tag> tags = getAllTagsFromDatabase();
|
||||||
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
||||||
if (sheetSet == null) {
|
if (sheetSet == null) {
|
||||||
@ -68,62 +79,63 @@ final class RelationshipNode extends BlackboardArtifactNode {
|
|||||||
sheet.put(sheetSet);
|
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);
|
addScoreProperty(sheetSet, tags);
|
||||||
|
|
||||||
CorrelationAttributeInstance correlationAttribute = null;
|
CorrelationAttributeInstance correlationAttribute = null;
|
||||||
if (UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
|
if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
|
||||||
correlationAttribute = getCorrelationAttributeInstance();
|
correlationAttribute = getCorrelationAttributeInstance();
|
||||||
}
|
}
|
||||||
addCommentProperty(sheetSet, tags, correlationAttribute);
|
addCommentProperty(sheetSet, tags, correlationAttribute);
|
||||||
|
|
||||||
if (UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
|
if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
|
||||||
addCountProperty(sheetSet, correlationAttribute);
|
addCountProperty(sheetSet, correlationAttribute);
|
||||||
}
|
}
|
||||||
final BlackboardArtifact artifact = getArtifact();
|
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) {
|
if (null != fromID) {
|
||||||
//Consider refactoring this to reduce boilerplate
|
//Consider refactoring this to reduce boilerplate
|
||||||
switch (fromID) {
|
switch (fromID) {
|
||||||
case TSK_EMAIL_MSG:
|
case TSK_EMAIL_MSG:
|
||||||
sheetSet.put(new NodeProperty<>("From", "From", "From",
|
sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "",
|
||||||
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_FROM), " \t\n;")));
|
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_FROM), " \t\n;"))); //NON-NLS
|
||||||
sheetSet.put(new NodeProperty<>("To", "To", "To",
|
sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "",
|
||||||
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_TO), " \t\n;")));
|
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_TO), " \t\n;"))); //NON-NLS
|
||||||
sheetSet.put(new NodeProperty<>("Date", "Date", "Date",
|
sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "",
|
||||||
getAttributeDisplayString(artifact, TSK_DATETIME_SENT)));
|
getAttributeDisplayString(artifact, TSK_DATETIME_SENT))); //NON-NLS
|
||||||
sheetSet.put(new NodeProperty<>("Subject", "Subject", "Subject",
|
sheetSet.put(new NodeProperty<>("Subject", Bundle.MessageNode_Node_Property_Subject(), "",
|
||||||
getAttributeDisplayString(artifact, TSK_SUBJECT)));
|
getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS
|
||||||
try {
|
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) {
|
} 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;
|
break;
|
||||||
case TSK_MESSAGE:
|
case TSK_MESSAGE:
|
||||||
sheetSet.put(new NodeProperty<>("From", "From", "From",
|
sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "",
|
||||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM)));
|
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM))); //NON-NLS
|
||||||
sheetSet.put(new NodeProperty<>("To", "To", "To",
|
sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "",
|
||||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO)));
|
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO))); //NON-NLS
|
||||||
sheetSet.put(new NodeProperty<>("Date", "Date", "Date",
|
sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "",
|
||||||
getAttributeDisplayString(artifact, TSK_DATETIME)));
|
getAttributeDisplayString(artifact, TSK_DATETIME))); //NON-NLS
|
||||||
sheetSet.put(new NodeProperty<>("Subject", "Subject", "Subject",
|
sheetSet.put(new NodeProperty<>("Subject", Bundle.MessageNode_Node_Property_Subject(), "",
|
||||||
getAttributeDisplayString(artifact, TSK_SUBJECT)));
|
getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS
|
||||||
try {
|
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) {
|
} 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;
|
break;
|
||||||
case TSK_CALLLOG:
|
case TSK_CALLLOG:
|
||||||
sheetSet.put(new NodeProperty<>("From", "From", "From",
|
sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "",
|
||||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM)));
|
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM))); //NON-NLS
|
||||||
sheetSet.put(new NodeProperty<>("To", "To", "To",
|
sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "",
|
||||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO)));
|
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO))); //NON-NLS
|
||||||
sheetSet.put(new NodeProperty<>("Date", "Date", "Date",
|
sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "",
|
||||||
getAttributeDisplayString(artifact, TSK_DATETIME_START)));
|
getAttributeDisplayString(artifact, TSK_DATETIME_START))); //NON-NLS
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -144,7 +156,7 @@ final class RelationshipNode extends BlackboardArtifactNode {
|
|||||||
* @return The display string, or an empty string if there is no such
|
* @return The display string, or an empty string if there is no such
|
||||||
* attribute or an an error.
|
* 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 {
|
try {
|
||||||
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(attributeType.getTypeID())));
|
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(attributeType.getTypeID())));
|
||||||
if (attribute == null) {
|
if (attribute == null) {
|
||||||
@ -156,7 +168,7 @@ final class RelationshipNode extends BlackboardArtifactNode {
|
|||||||
return attribute.getDisplayString();
|
return attribute.getDisplayString();
|
||||||
}
|
}
|
||||||
} catch (TskCoreException tskCoreException) {
|
} catch (TskCoreException tskCoreException) {
|
||||||
logger.log(Level.WARNING, "Error getting attribute value.", tskCoreException);
|
logger.log(Level.WARNING, "Error getting attribute value.", tskCoreException); //NON-NLS
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
194
Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java
Executable file
194
Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java
Executable 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
|
||||||
|
}
|
@ -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, "{key}")"/>
|
||||||
|
</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>
|
@ -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
|
||||||
|
|
||||||
|
}
|
@ -5,7 +5,7 @@
|
|||||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
<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_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
@ -16,40 +16,36 @@
|
|||||||
<Layout>
|
<Layout>
|
||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="1" attributes="0">
|
<EmptySpace min="0" pref="400" max="32767" attributes="0"/>
|
||||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||||
<Component id="splitPane" max="32767" attributes="0"/>
|
<Component id="scrollPane" alignment="1" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<EmptySpace min="0" pref="300" max="32767" attributes="0"/>
|
||||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||||
<Component id="splitPane" pref="1083" max="32767" attributes="0"/>
|
<Component id="scrollPane" alignment="0" max="32767" attributes="0"/>
|
||||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
</Layout>
|
</Layout>
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Container class="javax.swing.JSplitPane" name="splitPane">
|
<Container class="javax.swing.JScrollPane" name="scrollPane">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="dividerLocation" type="int" value="400"/>
|
<Property name="verticalScrollBarPolicy" type="int" value="21"/>
|
||||||
<Property name="dividerSize" type="int" value="10"/>
|
|
||||||
<Property name="orientation" type="int" value="0"/>
|
|
||||||
<Property name="resizeWeight" type="double" value="0.5"/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="org.sleuthkit.autopsy.communications.MessageDataContent" name="messageDataContent">
|
<Container class="javax.swing.JTabbedPane" name="tabPane">
|
||||||
<Constraints>
|
<Events>
|
||||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="tabPaneStateChanged"/>
|
||||||
<JSplitPaneConstraints position="bottom"/>
|
</Events>
|
||||||
</Constraint>
|
|
||||||
</Constraints>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
|
||||||
</Component>
|
</Container>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Container>
|
</Container>
|
||||||
</SubComponents>
|
</SubComponents>
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
185
Core/src/org/sleuthkit/autopsy/communications/relationships/SelectionInfo.java
Executable file
185
Core/src/org/sleuthkit/autopsy/communications/relationships/SelectionInfo.java
Executable 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
215
Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.form
Executable file
215
Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.form
Executable 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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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>
|
313
Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.java
Executable file
313
Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.java
Executable 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
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*s
|
*s
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* 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 {
|
class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(MediaFileViewer.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(MediaFileViewer.class.getName());
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
private AbstractFile lastFile;
|
private AbstractFile lastFile;
|
||||||
//UI
|
//UI
|
||||||
private MediaPlayerPanel mediaPlayerPanel;
|
private MediaPlayerPanel mediaPlayerPanel;
|
||||||
@ -48,7 +49,7 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
|||||||
/**
|
/**
|
||||||
* Creates a new MediaFileViewer.
|
* Creates a new MediaFileViewer.
|
||||||
*/
|
*/
|
||||||
public MediaFileViewer() {
|
MediaFileViewer() {
|
||||||
|
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
@ -70,7 +71,7 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
|||||||
private void customizeComponents() {
|
private void customizeComponents() {
|
||||||
add(imagePanel, IMAGE_VIEWER_LAYER);
|
add(imagePanel, IMAGE_VIEWER_LAYER);
|
||||||
|
|
||||||
if(mediaPlayerPanel != null) {
|
if (mediaPlayerPanel != null) {
|
||||||
add(mediaPlayerPanel, MEDIA_PLAYER_LAYER);
|
add(mediaPlayerPanel, MEDIA_PLAYER_LAYER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +104,7 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
|||||||
List<String> mimeTypes = new ArrayList<>();
|
List<String> mimeTypes = new ArrayList<>();
|
||||||
|
|
||||||
mimeTypes.addAll(this.imagePanel.getSupportedMimeTypes());
|
mimeTypes.addAll(this.imagePanel.getSupportedMimeTypes());
|
||||||
if(mediaPlayerPanel != null) {
|
if (mediaPlayerPanel != null) {
|
||||||
mimeTypes.addAll(this.mediaPlayerPanel.getSupportedMimeTypes());
|
mimeTypes.addAll(this.mediaPlayerPanel.getSupportedMimeTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,10 @@ import javax.swing.JPanel;
|
|||||||
import org.controlsfx.control.MaskerPane;
|
import org.controlsfx.control.MaskerPane;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.python.google.common.collect.Lists;
|
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.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
||||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
import org.sleuthkit.autopsy.datamodel.FileNode;
|
||||||
@ -70,6 +74,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
private final boolean fxInited;
|
private final boolean fxInited;
|
||||||
|
|
||||||
private JFXPanel fxPanel;
|
private JFXPanel fxPanel;
|
||||||
|
private Group imageGroup;
|
||||||
|
private ImageTaggingTool tagger;
|
||||||
private ImageView fxImageView;
|
private ImageView fxImageView;
|
||||||
private ScrollPane scrollPane;
|
private ScrollPane scrollPane;
|
||||||
private final ProgressBar progressBar = new ProgressBar();
|
private final ProgressBar progressBar = new ProgressBar();
|
||||||
@ -115,7 +121,9 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
|
|
||||||
// build jfx ui (we could do this in FXML?)
|
// build jfx ui (we could do this in FXML?)
|
||||||
fxImageView = new ImageView(); // will hold image
|
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.getStyleClass().add("bg"); //NOI18N
|
||||||
scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
|
scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
|
||||||
scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
|
scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
|
||||||
@ -146,9 +154,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
fxImageView.setViewport(new Rectangle2D(0, 0, 0, 0));
|
fxImageView.setViewport(new Rectangle2D(0, 0, 0, 0));
|
||||||
fxImageView.setImage(null);
|
fxImageView.setImage(null);
|
||||||
|
tagger.defaultSettings();
|
||||||
|
|
||||||
scrollPane.setContent(null);
|
scrollPane.setContent(null);
|
||||||
scrollPane.setContent(fxImageView);
|
scrollPane.setContent(imageGroup);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,8 +208,11 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
if (nonNull(fxImage)) {
|
if (nonNull(fxImage)) {
|
||||||
// We have a non-null image, so let's show it.
|
// We have a non-null image, so let's show it.
|
||||||
fxImageView.setImage(fxImage);
|
fxImageView.setImage(fxImage);
|
||||||
|
imageGroup.getChildren().remove(tagger);
|
||||||
|
tagger = new ImageTaggingTool(fxImageView, Color.RED);
|
||||||
|
imageGroup.getChildren().add(tagger);
|
||||||
resetView();
|
resetView();
|
||||||
scrollPane.setContent(fxImageView);
|
scrollPane.setContent(imageGroup);
|
||||||
} else {
|
} else {
|
||||||
showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
|
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
|
private void zoomInButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomInButtonActionPerformed
|
||||||
// Find the next zoom step.
|
// 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]) {
|
if (zoomRatio < ZOOM_STEPS[i]) {
|
||||||
zoomRatio = ZOOM_STEPS[i];
|
zoomRatio = ZOOM_STEPS[i];
|
||||||
break;
|
break;
|
||||||
@ -421,7 +433,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
|
|
||||||
private void zoomOutButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomOutButtonActionPerformed
|
private void zoomOutButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomOutButtonActionPerformed
|
||||||
// Find the next zoom step.
|
// 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]) {
|
if (zoomRatio > ZOOM_STEPS[i]) {
|
||||||
zoomRatio = ZOOM_STEPS[i];
|
zoomRatio = ZOOM_STEPS[i];
|
||||||
break;
|
break;
|
||||||
@ -589,8 +601,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
// Add the transforms in reverse order of intended execution.
|
// Add the transforms in reverse order of intended execution.
|
||||||
// Note: They MUST be added in this order to ensure translate is
|
// Note: They MUST be added in this order to ensure translate is
|
||||||
// executed last.
|
// executed last.
|
||||||
fxImageView.getTransforms().clear();
|
imageGroup.getTransforms().clear();
|
||||||
fxImageView.getTransforms().addAll(translate, rotate, scale);
|
imageGroup.getTransforms().addAll(translate, rotate, scale);
|
||||||
|
|
||||||
// Adjust scroll bar positions for view changes.
|
// Adjust scroll bar positions for view changes.
|
||||||
if (viewportWidth > fxPanel.getWidth()) {
|
if (viewportWidth > fxPanel.getWidth()) {
|
||||||
@ -606,4 +618,107 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
rotationTextField.setText((int) rotation + "°");
|
rotationTextField.setText((int) rotation + "°");
|
||||||
zoomTextField.setText((Math.round(zoomRatio * 100.0)) + "%");
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -467,6 +467,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
htmlPanel.reset();
|
htmlPanel.reset();
|
||||||
textbodyTextArea.setText("");
|
textbodyTextArea.setText("");
|
||||||
msgbodyTabbedPane.setEnabled(false);
|
msgbodyTabbedPane.setEnabled(false);
|
||||||
|
drp.setNode(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -561,7 +562,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, numberOfAttachments > 0);
|
msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, numberOfAttachments > 0);
|
||||||
msgbodyTabbedPane.setTitleAt(ATTM_TAB_INDEX, "Attachments (" + numberOfAttachments + ")");
|
msgbodyTabbedPane.setTitleAt(ATTM_TAB_INDEX, "Attachments (" + numberOfAttachments + ")");
|
||||||
drp.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(
|
drp.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(
|
||||||
new AttachmentsChildren(attachments)), null), true));
|
new AttachmentsChildren(attachments))), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String wrapInHtmlBody(String htmlText) {
|
private static String wrapInHtmlBody(String htmlText) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2018 Basis Technology Corp.
|
* Copyright 2018-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -79,7 +79,7 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
|
|||||||
/**
|
/**
|
||||||
* Creates new form PListViewer
|
* Creates new form PListViewer
|
||||||
*/
|
*/
|
||||||
public PListViewer() {
|
PListViewer() {
|
||||||
|
|
||||||
// Create an Outlineview and add to the panel
|
// Create an Outlineview and add to the panel
|
||||||
outlineView = new org.openide.explorer.view.OutlineView();
|
outlineView = new org.openide.explorer.view.OutlineView();
|
||||||
@ -431,16 +431,16 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
|
|||||||
* else is unexpected and will be ignored.
|
* else is unexpected and will be ignored.
|
||||||
*/
|
*/
|
||||||
if (rootDict instanceof NSArray) {
|
if (rootDict instanceof NSArray) {
|
||||||
for (int i=0; i < ((NSArray)rootDict).count(); i++) {
|
for (int i = 0; i < ((NSArray) rootDict).count(); i++) {
|
||||||
final PropKeyValue pkv = parseProperty("", ((NSArray)rootDict).objectAtIndex(i));
|
final PropKeyValue pkv = parseProperty("", ((NSArray) rootDict).objectAtIndex(i));
|
||||||
if (null != pkv) {
|
if (null != pkv) {
|
||||||
plist.add(pkv);
|
plist.add(pkv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (rootDict instanceof NSDictionary) {
|
} else if (rootDict instanceof NSDictionary) {
|
||||||
final String[] keys = ((NSDictionary)rootDict).allKeys();
|
final String[] keys = ((NSDictionary) rootDict).allKeys();
|
||||||
for (final String key : keys) {
|
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) {
|
if (null != pkv) {
|
||||||
plist.add(pkv);
|
plist.add(pkv);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2018 Basis Technology Corp.
|
* Copyright 2018-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -74,7 +74,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
|||||||
/**
|
/**
|
||||||
* Constructs a file content viewer for SQLite database files.
|
* Constructs a file content viewer for SQLite database files.
|
||||||
*/
|
*/
|
||||||
public SQLiteViewer() {
|
SQLiteViewer() {
|
||||||
initComponents();
|
initComponents();
|
||||||
jTableDataPanel.add(selectedTableView, BorderLayout.CENTER);
|
jTableDataPanel.add(selectedTableView, BorderLayout.CENTER);
|
||||||
}
|
}
|
||||||
@ -544,19 +544,19 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
|||||||
@Override
|
@Override
|
||||||
public void accept(String columnName) {
|
public void accept(String columnName) {
|
||||||
columnIndex++;
|
columnIndex++;
|
||||||
|
String csvString = columnName;
|
||||||
//Format the value to adhere to the format of a CSV file
|
//Format the value to adhere to the format of a CSV file
|
||||||
if (columnIndex == 1) {
|
if (columnIndex == 1) {
|
||||||
columnName = "\"" + columnName + "\"";
|
csvString = "\"" + csvString + "\"";
|
||||||
} else {
|
} else {
|
||||||
columnName = ",\"" + columnName + "\"";
|
csvString = ",\"" + csvString + "\"";
|
||||||
}
|
}
|
||||||
if (columnIndex == totalColumnCount) {
|
if (columnIndex == totalColumnCount) {
|
||||||
columnName += "\n";
|
csvString += "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
out.write(columnName.getBytes());
|
out.write(csvString.getBytes());
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
/*
|
/*
|
||||||
* If we can no longer write to the output stream, toss a
|
* 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);
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
rowIndex = rowIndex % totalColumnCount;
|
rowIndex %= totalColumnCount;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@ public final class UserPreferences {
|
|||||||
private static final String MESSAGE_SERVICE_USER = "MessageServiceUser"; //NON-NLS
|
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_HOST = "MessageServiceHost"; //NON-NLS
|
||||||
private static final String MESSAGE_SERVICE_PORT = "MessageServicePort"; //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_ENABLED = "ProcessTimeOutEnabled"; //NON-NLS
|
||||||
public static final String PROCESS_TIME_OUT_HOURS = "ProcessTimeOutHours"; //NON-NLS
|
public static final String PROCESS_TIME_OUT_HOURS = "ProcessTimeOutHours"; //NON-NLS
|
||||||
private static final int DEFAULT_PROCESS_TIMEOUT_HR = 60;
|
private static final int DEFAULT_PROCESS_TIMEOUT_HR = 60;
|
||||||
@ -336,6 +337,14 @@ public final class UserPreferences {
|
|||||||
preferences.putInt(INDEXING_SERVER_PORT, 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.
|
* Persists message service connection info.
|
||||||
*
|
*
|
||||||
|
@ -386,7 +386,13 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
|||||||
rootNodeChildren.cancelLoadingThumbnails();
|
rootNodeChildren.cancelLoadingThumbnails();
|
||||||
}
|
}
|
||||||
try {
|
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;
|
rootNode = (TableFilterNode) givenNode;
|
||||||
/*
|
/*
|
||||||
* Wrap the given node in a ThumbnailViewChildren that will
|
* Wrap the given node in a ThumbnailViewChildren that will
|
||||||
|
@ -29,6 +29,7 @@ import java.io.BufferedInputStream;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -798,7 +799,12 @@ public class ImageUtils {
|
|||||||
imageSaver.execute(() -> {
|
imageSaver.execute(() -> {
|
||||||
try {
|
try {
|
||||||
synchronized (cacheFile) {
|
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()) {
|
if (cacheFile.exists()) {
|
||||||
cacheFile.delete();
|
cacheFile.delete();
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,8 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
static private final DisplayableItemNodeVisitor<List<Action>> getActionsDIV = new GetPopupActionsDisplayableItemNodeVisitor();
|
static private final DisplayableItemNodeVisitor<List<Action>> getActionsDIV = new GetPopupActionsDisplayableItemNodeVisitor();
|
||||||
private final DisplayableItemNodeVisitor<AbstractAction> getPreferredActionsDIV = new GetPreferredActionsDisplayableItemNodeVisitor();
|
private final DisplayableItemNodeVisitor<AbstractAction> getPreferredActionsDIV = new GetPreferredActionsDisplayableItemNodeVisitor();
|
||||||
|
|
||||||
|
// Assumptions are made in GetPreferredActionsDisplayableItemNodeVisitor that
|
||||||
|
// sourceEm is the directory tree explorer manager.
|
||||||
private final ExplorerManager sourceEm;
|
private final ExplorerManager sourceEm;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,6 +105,17 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
* wrapped node and may filter out some of its children.
|
* wrapped node and may filter out some of its children.
|
||||||
*
|
*
|
||||||
* @param node The node to wrap.
|
* @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
|
||||||
|
* 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.
|
||||||
* @param em The ExplorerManager for the component that is creating the
|
* @param em The ExplorerManager for the component that is creating the
|
||||||
* node.
|
* node.
|
||||||
*/
|
*/
|
||||||
@ -549,6 +562,9 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
// is a DirectoryTreeFilterNode that wraps the dataModelNode. We need
|
// is a DirectoryTreeFilterNode that wraps the dataModelNode. We need
|
||||||
// to set that wrapped node as the selection and root context of the
|
// to set that wrapped node as the selection and root context of the
|
||||||
// directory tree explorer manager (sourceEm)
|
// directory tree explorer manager (sourceEm)
|
||||||
|
if(sourceEm == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
final Node currentSelectionInDirectoryTree = sourceEm.getSelectedNodes()[0];
|
final Node currentSelectionInDirectoryTree = sourceEm.getSelectedNodes()[0];
|
||||||
|
|
||||||
return new AbstractAction() {
|
return new AbstractAction() {
|
||||||
@ -589,6 +605,9 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private AbstractAction openParent(AbstractNode node) {
|
private AbstractAction openParent(AbstractNode node) {
|
||||||
|
if(sourceEm == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
// @@@ Why do we ignore node?
|
// @@@ Why do we ignore node?
|
||||||
Node[] selectedFilterNodes = sourceEm.getSelectedNodes();
|
Node[] selectedFilterNodes = sourceEm.getSelectedNodes();
|
||||||
Node selectedFilterNode = selectedFilterNodes[0];
|
Node selectedFilterNode = selectedFilterNodes[0];
|
||||||
|
BIN
Core/src/org/sleuthkit/autopsy/images/translate32.png
Normal file
BIN
Core/src/org/sleuthkit/autopsy/images/translate32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
@ -163,6 +163,8 @@ final class ContactAnalyzer {
|
|||||||
data1 = resultSet.getString("data1"); //NON-NLS
|
data1 = resultSet.getString("data1"); //NON-NLS
|
||||||
mimetype = resultSet.getString("mimetype"); //NON-NLS
|
mimetype = resultSet.getString("mimetype"); //NON-NLS
|
||||||
if (name.equals(oldName) == false) {
|
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));
|
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, moduleName, name));
|
||||||
}
|
}
|
||||||
if (mimetype.equals("vnd.android.cursor.item/phone_v2")) { //NON-NLS
|
if (mimetype.equals("vnd.android.cursor.item/phone_v2")) { //NON-NLS
|
||||||
@ -170,6 +172,12 @@ final class ContactAnalyzer {
|
|||||||
} else {
|
} else {
|
||||||
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, moduleName, data1));
|
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;
|
oldName = name;
|
||||||
|
|
||||||
bba.addAttributes(attributes);
|
bba.addAttributes(attributes);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013-2018 Basis Technology Corp.
|
* Copyright 2013-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,12 +18,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.modules.stix;
|
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.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -31,10 +34,8 @@ import java.io.UnsupportedEncodingException;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
import org.mitre.cybox.objects.WindowsRegistryKey;
|
import org.mitre.cybox.objects.WindowsRegistryKey;
|
||||||
import org.mitre.cybox.common_2.ConditionTypeEnum;
|
import org.mitre.cybox.common_2.ConditionTypeEnum;
|
||||||
import com.williballenthin.rejistry.*;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,9 +44,9 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
|||||||
class EvalRegistryObj extends EvaluatableObject {
|
class EvalRegistryObj extends EvaluatableObject {
|
||||||
|
|
||||||
private final WindowsRegistryKey obj;
|
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;
|
obj = a_obj;
|
||||||
id = a_id;
|
id = a_id;
|
||||||
spacing = a_spacing;
|
spacing = a_spacing;
|
||||||
@ -80,7 +81,7 @@ class EvalRegistryObj extends EvaluatableObject {
|
|||||||
setUnsupportedFieldWarnings();
|
setUnsupportedFieldWarnings();
|
||||||
|
|
||||||
// Make a list of hives to test
|
// Make a list of hives to test
|
||||||
List<RegistryFileInfo> hiveList = new ArrayList<RegistryFileInfo>();
|
List<RegistryFileInfo> hiveList = new ArrayList<>();
|
||||||
if (obj.getHive() == null) {
|
if (obj.getHive() == null) {
|
||||||
// If the hive field is missing, add everything
|
// If the hive field is missing, add everything
|
||||||
hiveList.addAll(regFiles);
|
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.
|
// If the hive name is HKEY_LOCAL_MACHINE, add the ones from the config directory.
|
||||||
// Otherwise, add the others
|
// Otherwise, add the others
|
||||||
for (RegistryFileInfo regFile : regFiles) {
|
for (RegistryFileInfo regFile : regFiles) {
|
||||||
if (regFile.abstractFile.getParentPath() != null) {
|
if (regFile.getAbstractFile().getParentPath() != null) {
|
||||||
Pattern pattern = Pattern.compile("system32", Pattern.CASE_INSENSITIVE);
|
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()) {
|
if (matcher.find()) {
|
||||||
// Looking for system files and found one, so add it to the list
|
// Looking for system files and found one, so add it to the list
|
||||||
if (obj.getHive().getValue().toString().equalsIgnoreCase("HKEY_LOCAL_MACHINE")) { //NON-NLS
|
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);
|
Pattern pattern = Pattern.compile("Temp.STIX." + stixHiveName, Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
for (RegistryFileInfo hive : regFiles) {
|
for (RegistryFileInfo hive : regFiles) {
|
||||||
Matcher matcher = pattern.matcher(hive.tempFileName);
|
Matcher matcher = pattern.matcher(hive.getTempFileName());
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
hiveList.add(hive);
|
hiveList.add(hive);
|
||||||
}
|
}
|
||||||
@ -163,7 +164,7 @@ class EvalRegistryObj extends EvaluatableObject {
|
|||||||
*/
|
*/
|
||||||
private ObservableResult testRegistryFile(RegistryFileInfo a_regInfo) {
|
private ObservableResult testRegistryFile(RegistryFileInfo a_regInfo) {
|
||||||
try {
|
try {
|
||||||
RegistryKey root = openRegistry(a_regInfo.tempFileName);
|
RegistryKey root = openRegistry(a_regInfo.getTempFileName());
|
||||||
RegistryKey result = findKey(root, obj.getKey().getValue().toString());
|
RegistryKey result = findKey(root, obj.getKey().getValue().toString());
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
@ -192,8 +193,8 @@ class EvalRegistryObj extends EvaluatableObject {
|
|||||||
|
|
||||||
if ((obj.getValues() == null) || (obj.getValues().getValues().isEmpty())) {
|
if ((obj.getValues() == null) || (obj.getValues().getValues().isEmpty())) {
|
||||||
// No values to test
|
// No values to test
|
||||||
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
|
List<StixArtifactData> artData = new ArrayList<>();
|
||||||
artData.add(new StixArtifactData(a_regInfo.abstractFile.getId(), id, "Registry")); //NON-NLS
|
artData.add(new StixArtifactData(a_regInfo.getAbstractFile().getId(), id, "Registry")); //NON-NLS
|
||||||
return new ObservableResult(id, "RegistryObject: Found key " + obj.getKey().getValue(), //NON-NLS
|
return new ObservableResult(id, "RegistryObject: Found key " + obj.getKey().getValue(), //NON-NLS
|
||||||
spacing, ObservableResult.ObservableState.TRUE, artData);
|
spacing, ObservableResult.ObservableState.TRUE, artData);
|
||||||
}
|
}
|
||||||
@ -262,8 +263,8 @@ class EvalRegistryObj extends EvaluatableObject {
|
|||||||
|
|
||||||
if (nameSuccess && valueSuccess) {
|
if (nameSuccess && valueSuccess) {
|
||||||
// Found a match for all values
|
// Found a match for all values
|
||||||
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
|
List<StixArtifactData> artData = new ArrayList<>();
|
||||||
artData.add(new StixArtifactData(a_regInfo.abstractFile.getId(), id, "Registry")); //NON-NLS
|
artData.add(new StixArtifactData(a_regInfo.getAbstractFile().getId(), id, "Registry")); //NON-NLS
|
||||||
return new ObservableResult(id, "RegistryObject: Found key " + obj.getKey().getValue() //NON-NLS
|
return new ObservableResult(id, "RegistryObject: Found key " + obj.getKey().getValue() //NON-NLS
|
||||||
+ " and value " + stixRegValue.getName().getValue().toString() //NON-NLS
|
+ " and value " + stixRegValue.getName().getValue().toString() //NON-NLS
|
||||||
+ " = " + stixRegValue.getData().getValue().toString(),
|
+ " = " + stixRegValue.getData().getValue().toString(),
|
||||||
@ -343,7 +344,7 @@ class EvalRegistryObj extends EvaluatableObject {
|
|||||||
List<AbstractFile> regFilesAbstract = findRegistryFiles();
|
List<AbstractFile> regFilesAbstract = findRegistryFiles();
|
||||||
|
|
||||||
// List to hold all the extracted file names plus their abstract file
|
// 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
|
// Make the temp directory
|
||||||
String tmpDir;
|
String tmpDir;
|
||||||
@ -382,7 +383,7 @@ class EvalRegistryObj extends EvaluatableObject {
|
|||||||
* RecentActivity
|
* RecentActivity
|
||||||
*/
|
*/
|
||||||
private static List<AbstractFile> findRegistryFiles() throws TskCoreException {
|
private static List<AbstractFile> findRegistryFiles() throws TskCoreException {
|
||||||
List<AbstractFile> registryFiles = new ArrayList<AbstractFile>();
|
List<AbstractFile> registryFiles = new ArrayList<>();
|
||||||
Case openCase;
|
Case openCase;
|
||||||
try {
|
try {
|
||||||
openCase = Case.getCurrentCaseThrows();
|
openCase = Case.getCurrentCaseThrows();
|
||||||
@ -413,7 +414,7 @@ class EvalRegistryObj extends EvaluatableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setUnsupportedFieldWarnings() {
|
private void setUnsupportedFieldWarnings() {
|
||||||
List<String> fieldNames = new ArrayList<String>();
|
List<String> fieldNames = new ArrayList<>();
|
||||||
|
|
||||||
if (obj.getNumberValues() != null) {
|
if (obj.getNumberValues() != null) {
|
||||||
fieldNames.add("Number_Values"); //NON-NLS
|
fieldNames.add("Number_Values"); //NON-NLS
|
||||||
@ -462,5 +463,23 @@ class EvalRegistryObj extends EvaluatableObject {
|
|||||||
tempFileName = a_tempFileName;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -22,7 +22,9 @@ import java.io.IOException;
|
|||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import net.htmlparser.jericho.Attributes;
|
import net.htmlparser.jericho.Attributes;
|
||||||
import net.htmlparser.jericho.Config;
|
import net.htmlparser.jericho.Config;
|
||||||
@ -84,27 +86,21 @@ final class HtmlTextExtractor implements TextExtractor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a reader that will iterate over the text of an HTML document.
|
* Get the metadata as a key -> value map. HTML metadata will include
|
||||||
|
* scripts, links, images, comments, and misc attributes.
|
||||||
*
|
*
|
||||||
* @param content Html document source
|
* @return Map containing metadata key -> value pairs.
|
||||||
*
|
|
||||||
* @return A reader instance containing the document source text
|
|
||||||
*
|
|
||||||
* @throws TextExtractorException
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Reader getReader() throws InitReaderException {
|
public Map<String, String> getMetadata() {
|
||||||
//TODO JIRA-4467, there is only harm in excluding HTML documents greater
|
Map<String, String> metadataMap = new HashMap<>();
|
||||||
//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 {
|
try {
|
||||||
StringBuilder scripts = new StringBuilder();
|
ReadContentInputStream stream = new ReadContentInputStream(file);
|
||||||
StringBuilder links = new StringBuilder();
|
StringBuilder scripts = new StringBuilder("\n");
|
||||||
StringBuilder images = new StringBuilder();
|
StringBuilder links = new StringBuilder("\n");
|
||||||
StringBuilder comments = new StringBuilder();
|
StringBuilder images = new StringBuilder("\n");
|
||||||
StringBuilder others = new StringBuilder();
|
StringBuilder comments = new StringBuilder("\n");
|
||||||
|
StringBuilder others = new StringBuilder("\n");
|
||||||
int numScripts = 0;
|
int numScripts = 0;
|
||||||
int numLinks = 0;
|
int numLinks = 0;
|
||||||
int numImages = 0;
|
int numImages = 0;
|
||||||
@ -113,17 +109,8 @@ final class HtmlTextExtractor implements TextExtractor {
|
|||||||
|
|
||||||
Source source = new Source(stream);
|
Source source = new Source(stream);
|
||||||
source.fullSequentialParse();
|
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();
|
List<StartTag> tags = source.getAllStartTags();
|
||||||
|
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
|
||||||
for (StartTag tag : tags) {
|
for (StartTag tag : tags) {
|
||||||
if (tag.getName().equals("script")) { //NON-NLS
|
if (tag.getName().equals("script")) { //NON-NLS
|
||||||
// If the <script> tag has attributes
|
// 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) {
|
if (numScripts > 0) {
|
||||||
stringBuilder.append("---Scripts---\n"); //NON-NLS
|
metadataMap.put("Scripts", scripts.toString());
|
||||||
stringBuilder.append(scripts).append("\n");
|
|
||||||
}
|
}
|
||||||
if (numLinks > 0) {
|
if (numLinks > 0) {
|
||||||
stringBuilder.append("---Links---\n"); //NON-NLS
|
metadataMap.put("Links", links.toString());
|
||||||
stringBuilder.append(links).append("\n");
|
|
||||||
}
|
}
|
||||||
if (numImages > 0) {
|
if (numImages > 0) {
|
||||||
stringBuilder.append("---Images---\n"); //NON-NLS
|
metadataMap.put("Images", images.toString());
|
||||||
stringBuilder.append(images).append("\n");
|
|
||||||
}
|
}
|
||||||
if (numComments > 0) {
|
if (numComments > 0) {
|
||||||
stringBuilder.append("---Comments---\n"); //NON-NLS
|
metadataMap.put("Comments", comments.toString());
|
||||||
stringBuilder.append(comments).append("\n");
|
|
||||||
}
|
}
|
||||||
if (numOthers > 0) {
|
if (numOthers > 0) {
|
||||||
stringBuilder.append("---Others---\n"); //NON-NLS
|
metadataMap.put("Others", others.toString());
|
||||||
stringBuilder.append(others).append("\n");
|
|
||||||
}
|
}
|
||||||
// All done, now make it a reader
|
} catch (IOException ex) {
|
||||||
return new StringReader(stringBuilder.toString());
|
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) {
|
} catch (IOException ex) {
|
||||||
logger.log(Level.WARNING, "Error extracting HTML from content.", ex);
|
logger.log(Level.WARNING, "Error extracting HTML from content.", ex);
|
||||||
throw new InitReaderException("Error extracting HTML from content.", ex);
|
throw new InitReaderException("Error extracting HTML from content.", ex);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-18 Basis Technology Corp.
|
* Copyright 2011-19 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -19,6 +19,8 @@
|
|||||||
package org.sleuthkit.autopsy.textextractors;
|
package org.sleuthkit.autopsy.textextractors;
|
||||||
|
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,6 +64,15 @@ public interface TextExtractor {
|
|||||||
//no-op by default
|
//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.
|
* System level exception for reader initialization.
|
||||||
*/
|
*/
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -29,8 +29,10 @@ import java.io.InputStream;
|
|||||||
import java.io.PushbackReader;
|
import java.io.PushbackReader;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@ -40,8 +42,8 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
|
||||||
import org.apache.tika.Tika;
|
import org.apache.tika.Tika;
|
||||||
|
import org.apache.tika.exception.TikaException;
|
||||||
import org.apache.tika.metadata.Metadata;
|
import org.apache.tika.metadata.Metadata;
|
||||||
import org.apache.tika.parser.AutoDetectParser;
|
import org.apache.tika.parser.AutoDetectParser;
|
||||||
import org.apache.tika.parser.ParseContext;
|
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.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
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
|
* Extracts text from Tika supported content. Protects against Tika parser hangs
|
||||||
@ -136,6 +142,7 @@ final class TikaTextExtractor implements TextExtractor {
|
|||||||
private static final File TESSERACT_PATH = locateTesseractExecutable();
|
private static final File TESSERACT_PATH = locateTesseractExecutable();
|
||||||
private String languagePacks = formatLanguagePacks(PlatformUtil.getOcrLanguagePacks());
|
private String languagePacks = formatLanguagePacks(PlatformUtil.getOcrLanguagePacks());
|
||||||
private static final String TESSERACT_OUTPUT_FILE_NAME = "tess_output"; //NON-NLS
|
private static final String TESSERACT_OUTPUT_FILE_NAME = "tess_output"; //NON-NLS
|
||||||
|
private Map<String, String> metadataMap;
|
||||||
|
|
||||||
private ProcessTerminator processTerminator;
|
private ProcessTerminator processTerminator;
|
||||||
|
|
||||||
@ -151,8 +158,8 @@ final class TikaTextExtractor implements TextExtractor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* If Tesseract has been installed and is set to be used through
|
* If Tesseract has been installed and is set to be used through
|
||||||
* configuration, then ocr is enabled. OCR can only currently be run on
|
* configuration, then ocr is enabled. OCR can only currently be run on 64
|
||||||
* 64 bit Windows OS.
|
* bit Windows OS.
|
||||||
*
|
*
|
||||||
* @return Flag indicating if OCR is set to be used.
|
* @return Flag indicating if OCR is set to be used.
|
||||||
*/
|
*/
|
||||||
@ -233,9 +240,16 @@ final class TikaTextExtractor implements TextExtractor {
|
|||||||
+ "Tika returned empty reader for " + content);
|
+ "Tika returned empty reader for " + content);
|
||||||
}
|
}
|
||||||
pushbackReader.unread(read);
|
pushbackReader.unread(read);
|
||||||
//concatenate parsed content and meta data into a single reader.
|
|
||||||
CharSource metaDataCharSource = getMetaDataCharSource(metadata);
|
//Save the metadata if it has not been fetched already.
|
||||||
return CharSource.concat(new ReaderCharSource(pushbackReader), metaDataCharSource).openStream();
|
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) {
|
} catch (TimeoutException te) {
|
||||||
final String msg = NbBundle.getMessage(this.getClass(),
|
final String msg = NbBundle.getMessage(this.getClass(),
|
||||||
"AbstractFileTikaTextExtract.index.tikaParseTimeout.text",
|
"AbstractFileTikaTextExtract.index.tikaParseTimeout.text",
|
||||||
@ -403,20 +417,33 @@ final class TikaTextExtractor implements TextExtractor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a CharSource that wraps a formated representation of the given
|
* Get the content metadata, if any.
|
||||||
* Metadata.
|
|
||||||
*
|
*
|
||||||
* @param metadata The Metadata to wrap as a CharSource
|
* @return Metadata as a name -> value map
|
||||||
*
|
|
||||||
* @return A CharSource for the given MetaData
|
|
||||||
*/
|
*/
|
||||||
static private CharSource getMetaDataCharSource(Metadata metadata) {
|
@Override
|
||||||
return CharSource.wrap(
|
public Map<String, String> getMetadata() {
|
||||||
new StringBuilder("\n\n------------------------------METADATA------------------------------\n\n")
|
if (metadataMap != null) {
|
||||||
.append(Stream.of(metadata.names()).sorted()
|
return ImmutableMap.copyOf(metadataMap);
|
||||||
.map(key -> key + ": " + metadata.get(key))
|
}
|
||||||
.collect(Collectors.joining("\n"))
|
|
||||||
));
|
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
|
@Override
|
||||||
public boolean isSupported() {
|
public boolean isSupported() {
|
||||||
if(!(content instanceof AbstractFile)) {
|
if (!(content instanceof AbstractFile)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String detectedType = ((AbstractFile)content).getMIMEType();
|
String detectedType = ((AbstractFile) content).getMIMEType();
|
||||||
if (detectedType == null
|
if (detectedType == null
|
||||||
|| BINARY_MIME_TYPES.contains(detectedType) //any binary unstructured blobs (string extraction will be used)
|
|| BINARY_MIME_TYPES.contains(detectedType) //any binary unstructured blobs (string extraction will be used)
|
||||||
|| ARCHIVE_MIME_TYPES.contains(detectedType)
|
|| ARCHIVE_MIME_TYPES.contains(detectedType)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2018-2018 Basis Technology Corp.
|
* Copyright 2018-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,25 +18,28 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.texttranslation;
|
package org.sleuthkit.autopsy.texttranslation;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a lookup for a TextTranslator service provider and if present,
|
* Performs a lookup for a TextTranslator service provider and if present, will
|
||||||
* will use this provider to run translation on the input.
|
* use this provider to run translation on the input.
|
||||||
*/
|
*/
|
||||||
public final class TextTranslationService {
|
public final class TextTranslationService {
|
||||||
|
|
||||||
private final static TextTranslationService tts = new TextTranslationService();
|
private final static TextTranslationService tts = new TextTranslationService();
|
||||||
|
|
||||||
private final Optional<TextTranslator> translator;
|
private final Collection<? extends TextTranslator> translators;
|
||||||
|
private Optional<TextTranslator> selectedTranslator;
|
||||||
|
|
||||||
private TextTranslationService(){
|
private TextTranslationService() {
|
||||||
//Perform look up for Text Translation implementations ONLY ONCE during
|
//Perform look up for Text Translation implementations ONLY ONCE during
|
||||||
//class loading.
|
//class loading.
|
||||||
translator = Optional.ofNullable(Lookup.getDefault()
|
translators = Lookup.getDefault().lookupAll(TextTranslator.class);
|
||||||
.lookup(TextTranslator.class));
|
updateSelectedTranslator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextTranslationService getInstance() {
|
public static TextTranslationService getInstance() {
|
||||||
@ -44,8 +47,23 @@ public final class TextTranslationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translates the input string using whichever TextTranslator Service Provider
|
* Update the translator currently in use to match the one saved to the user
|
||||||
* was found during lookup.
|
* 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
|
* @param input Input string to be translated
|
||||||
*
|
*
|
||||||
@ -58,13 +76,41 @@ public final class TextTranslationService {
|
|||||||
* implementations fail
|
* implementations fail
|
||||||
*/
|
*/
|
||||||
public String translate(String input) throws NoServiceProviderException, TranslationException {
|
public String translate(String input) throws NoServiceProviderException, TranslationException {
|
||||||
if (translator.isPresent()) {
|
if (hasProvider()) {
|
||||||
return translator.get().translate(input);
|
return selectedTranslator.get().translate(input);
|
||||||
}
|
}
|
||||||
throw new NoServiceProviderException(
|
throw new NoServiceProviderException(
|
||||||
"Could not find a TextTranslator service provider");
|
"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
|
* Returns if a TextTranslator lookup successfully found an implementing
|
||||||
* class.
|
* class.
|
||||||
@ -72,6 +118,6 @@ public final class TextTranslationService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean hasProvider() {
|
public boolean hasProvider() {
|
||||||
return translator.isPresent();
|
return selectedTranslator.isPresent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2018-2018 Basis Technology Corp.
|
* Copyright 2018-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,12 +18,42 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.texttranslation;
|
package org.sleuthkit.autopsy.texttranslation;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for creating text translators. Implementing classes will be picked
|
* Interface for creating text translators. Implementing classes will be picked
|
||||||
* up and run by the Text Translation Service.
|
* up and run by the Text Translation Service.
|
||||||
*/
|
*/
|
||||||
public interface TextTranslator {
|
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;
|
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();
|
||||||
}
|
}
|
||||||
|
@ -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.
|
@ -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.originalText=Original Text
|
||||||
TranslatedContentPanel.comboBoxOption.translatedText=Translated Text
|
TranslatedContentPanel.comboBoxOption.translatedText=Translated Text
|
||||||
TranslatedContentViewer.emptyTranslation=The resulting translation was empty.
|
TranslatedContentViewer.emptyTranslation=The resulting translation was empty.
|
||||||
@ -13,6 +15,13 @@ TranslatedContentViewer.translationException=Error encountered while attempting
|
|||||||
TranslatedTextViewer.title=Translation
|
TranslatedTextViewer.title=Translation
|
||||||
TranslatedTextViewer.toolTip=Displays translated file text.
|
TranslatedTextViewer.toolTip=Displays translated file text.
|
||||||
TranslationContentPanel.autoDetectOCR=Autodetect language
|
TranslationContentPanel.autoDetectOCR=Autodetect language
|
||||||
TranslationContentPanel.warningLabel2MB.text=Only the first 1MB of text will be displayed
|
|
||||||
TranslationContentPanel.ShowLabel.text=Show:
|
TranslationContentPanel.ShowLabel.text=Show:
|
||||||
|
TranslationContentPanel.warningLabel2MB.text=Only the first 1MB of text will be displayed
|
||||||
TranslationContentPanel.ocrLabel.text=OCR:
|
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.
|
@ -16,7 +16,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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.collect.Lists;
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
@ -53,7 +53,7 @@ import org.sleuthkit.autopsy.texttranslation.TranslationException;
|
|||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
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.
|
* A TextViewer that displays machine translation of text.
|
||||||
@ -294,12 +294,15 @@ public final class TranslatedTextViewer implements TextViewer {
|
|||||||
/**
|
/**
|
||||||
* Fetches text from a file.
|
* 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
|
* @return Extracted Text
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
|
* @throws
|
||||||
|
* org.sleuthkit.autopsy.textextractors.TextExtractor.InitReaderException
|
||||||
*/
|
*/
|
||||||
private String extractText(AbstractFile source, boolean ocrEnabled) throws IOException, InterruptedException, TextExtractor.InitReaderException {
|
private String extractText(AbstractFile source, boolean ocrEnabled) throws IOException, InterruptedException, TextExtractor.InitReaderException {
|
||||||
Reader textExtractor = getTextExtractor(source, ocrEnabled);
|
Reader textExtractor = getTextExtractor(source, ocrEnabled);
|
@ -102,7 +102,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="ShowLabel">
|
<Component class="javax.swing.JLabel" name="ShowLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties" key="TranslationContentPanel.ShowLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
@ -148,7 +148,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="ocrLabel">
|
<Component class="javax.swing.JLabel" name="ocrLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties" key="TranslationContentPanel.ocrLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="enabled" type="boolean" value="false"/>
|
<Property name="enabled" type="boolean" value="false"/>
|
||||||
</Properties>
|
</Properties>
|
||||||
@ -159,7 +159,7 @@
|
|||||||
<Image iconType="3" name="/org/sleuthkit/autopsy/images/warning16.png"/>
|
<Image iconType="3" name="/org/sleuthkit/autopsy/images/warning16.png"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties" key="TranslationContentPanel.warningLabel2MB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
@ -16,7 +16,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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.base.Strings;
|
||||||
import com.google.common.collect.ImmutableBiMap;
|
import com.google.common.collect.ImmutableBiMap;
|
||||||
@ -362,7 +362,7 @@ public class TranslationContentPanel extends javax.swing.JPanel {
|
|||||||
this.setLayout(layout);
|
this.setLayout(layout);
|
||||||
layout.setHorizontalGroup(
|
layout.setHorizontalGroup(
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
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)
|
.addComponent(jScrollPane1)
|
||||||
);
|
);
|
||||||
layout.setVerticalGroup(
|
layout.setVerticalGroup(
|
@ -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="<String>"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Container class="javax.swing.JPanel" name="translationServicePanel">
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
@ -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
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
/*
|
/*=
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013-15 Basis Technology Corp.
|
* Copyright 2013-15 Basis Technology Corp.
|
||||||
@ -14,8 +14,8 @@
|
|||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* 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.
|
AbstractTimelineChart.defaultTooltip.text=Drag the mouse to select a time interval to zoom into.\nRight-click for more actions.
|
||||||
HistoryToolBar.historyLabel.text=History
|
HistoryToolBar.historyLabel.text=History
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
TranslationContentPanel.warningLabel2MB.text=Only the first 1MB of text will be displayed
|
|
||||||
TranslationContentPanel.ShowLabel.text=Show:
|
|
||||||
TranslationContentPanel.ocrLabel.text=OCR:
|
|
@ -141,6 +141,7 @@ class ContactAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
name = resultSet.getString("display_name")
|
name = resultSet.getString("display_name")
|
||||||
data1 = resultSet.getString("data1") # the phone number or email
|
data1 = resultSet.getString("data1") # the phone number or email
|
||||||
mimetype = resultSet.getString("mimetype") # either phone or email
|
mimetype = resultSet.getString("mimetype") # either phone or email
|
||||||
|
attributes = ArrayList()
|
||||||
if name != oldName:
|
if name != oldName:
|
||||||
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT)
|
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT)
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))
|
||||||
|
@ -24,6 +24,7 @@ KeywordSearchIngestModule.init.badInitMsg=Keyword search server was not properly
|
|||||||
KeywordSearchIngestModule.init.exception.errConnToSolr.msg=Error connecting to SOLR server: {0}.
|
KeywordSearchIngestModule.init.exception.errConnToSolr.msg=Error connecting to SOLR server: {0}.
|
||||||
# {0} - Reason for not starting Solr
|
# {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.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.noOpenCase.errMsg=No open case available.
|
||||||
KeywordSearchIngestModule.startUp.noOpenCore.msg=The index could not be opened or does not exist.
|
KeywordSearchIngestModule.startUp.noOpenCore.msg=The index could not be opened or does not exist.
|
||||||
# {0} - schema version number
|
# {0} - schema version number
|
||||||
@ -35,7 +36,7 @@ KeywordSearchResultFactory.createNodeForKey.noResultsFound.text=No results found
|
|||||||
KeywordSearchResultFactory.query.exception.msg=Could not perform the query
|
KeywordSearchResultFactory.query.exception.msg=Could not perform the query
|
||||||
OpenIDE-Module-Display-Category=Ingest Module
|
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
|
OpenIDE-Module-Name=KeywordSearch
|
||||||
OptionsCategory_Name_KeywordSearchOptions=Keyword Search
|
OptionsCategory_Name_KeywordSearchOptions=Keyword Search
|
||||||
OptionsCategory_Keywords_KeywordSearchOptions=Keyword Search
|
OptionsCategory_Keywords_KeywordSearchOptions=Keyword Search
|
||||||
|
@ -123,15 +123,13 @@ class Ingester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use the given TextExtractor to extract text from the given source. The
|
* Read and chunk the source text for indexing in Solr.
|
||||||
* text will be chunked and each chunk passed to Solr to add to the index.
|
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param <A> The type of the Appendix provider that provides
|
* @param <A> The type of the Appendix provider that provides
|
||||||
* additional text to append to the final chunk.
|
* additional text to append to the final chunk.
|
||||||
* @param <T> A subclass of SleuthkitVisibleItem.
|
* @param <T> A subclass of SleuthkitVisibleItem.
|
||||||
* @param extractor The TextExtractor that will be used to extract text from
|
* @param Reader The reader containing extracted text.
|
||||||
* the given source.
|
|
||||||
* @param source The source from which text will be extracted, chunked,
|
* @param source The source from which text will be extracted, chunked,
|
||||||
* and indexed.
|
* and indexed.
|
||||||
* @param context The ingest job context that can be used to cancel this
|
* @param context The ingest job context that can be used to cancel this
|
||||||
|
@ -19,12 +19,15 @@
|
|||||||
package org.sleuthkit.autopsy.keywordsearch;
|
package org.sleuthkit.autopsy.keywordsearch;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.io.CharSource;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
@ -469,15 +472,14 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
|||||||
* streaming) from the file Divide the file into chunks and index the
|
* streaming) from the file Divide the file into chunks and index the
|
||||||
* chunks
|
* chunks
|
||||||
*
|
*
|
||||||
* @param aFile file to extract strings from, divide into
|
* @param aFile file to extract strings from, divide into chunks and
|
||||||
* chunks and index
|
* index
|
||||||
* @param detectedFormat mime-type detected, or null if none detected
|
|
||||||
*
|
*
|
||||||
* @return true if the file was text_ingested, false otherwise
|
* @return true if the file was text_ingested, false otherwise
|
||||||
*
|
*
|
||||||
* @throws IngesterException exception thrown if indexing failed
|
* @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 imageConfig = new ImageConfig();
|
||||||
imageConfig.setOCREnabled(KeywordSearchSettings.getOcrOption());
|
imageConfig.setOCREnabled(KeywordSearchSettings.getOcrOption());
|
||||||
ProcessTerminator terminator = () -> context.fileIngestIsCancelled();
|
ProcessTerminator terminator = () -> context.fileIngestIsCancelled();
|
||||||
@ -485,15 +487,54 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
TextExtractor extractor = TextExtractorFactory.getExtractor(aFile, extractionContext);
|
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
|
//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) {
|
} catch (TextExtractorFactory.NoTextExtractorFound | TextExtractor.InitReaderException ex) {
|
||||||
//No text extractor found... run the default instead
|
//No text extractor found... run the default instead
|
||||||
return false;
|
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.
|
* Extract strings using heuristics from the file and add to index.
|
||||||
*
|
*
|
||||||
@ -595,7 +636,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
|||||||
extractStringsAndIndex(aFile);
|
extractStringsAndIndex(aFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!extractTextAndIndex(aFile, fileType)) {
|
if (!extractTextAndIndex(aFile)) {
|
||||||
// Text extractor not found for file. Extract string only.
|
// Text extractor not found for file. Extract string only.
|
||||||
putIngestStatus(jobId, aFile.getId(), IngestStatus.SKIPPED_ERROR_TEXTEXTRACT);
|
putIngestStatus(jobId, aFile.getId(), IngestStatus.SKIPPED_ERROR_TEXTEXTRACT);
|
||||||
} else {
|
} else {
|
||||||
|
@ -64,7 +64,7 @@ ExtractZone_progress_Msg=Extracting :Zone.Identifer files
|
|||||||
ExtractZone_Restricted=Restricted Sites Zone
|
ExtractZone_Restricted=Restricted Sites Zone
|
||||||
ExtractZone_Trusted=Trusted Sites Zone
|
ExtractZone_Trusted=Trusted Sites Zone
|
||||||
OpenIDE-Module-Display-Category=Ingest Module
|
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-Name=RecentActivity
|
||||||
OpenIDE-Module-Short-Description=Recent Activity finder ingest module
|
OpenIDE-Module-Short-Description=Recent Activity finder ingest module
|
||||||
Chrome.moduleName=Chrome
|
Chrome.moduleName=Chrome
|
||||||
|
@ -22,11 +22,16 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.recentactivity;
|
package org.sleuthkit.autopsy.recentactivity;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
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.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
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.DataSourceIngestModuleProcessTerminator;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||||
import org.sleuthkit.autopsy.recentactivity.UsbDeviceIdMapper.USBInfo;
|
import org.sleuthkit.autopsy.recentactivity.UsbDeviceIdMapper.USBInfo;
|
||||||
import org.sleuthkit.datamodel.*;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
@ -50,6 +54,14 @@ import org.w3c.dom.NodeList;
|
|||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import java.nio.file.Path;
|
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 static java.util.TimeZone.getTimeZone;
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
|
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.IngestServices;
|
||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||||
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
|
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.ReadContentInputStream.ReadContentInputStreamException;
|
||||||
|
import org.sleuthkit.datamodel.Report;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract windows registry data using regripper. Runs two versions of
|
* Extract windows registry data using regripper. Runs two versions of
|
||||||
@ -72,21 +90,19 @@ import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamExce
|
|||||||
})
|
})
|
||||||
class ExtractRegistry extends Extract {
|
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 UsbDeviceIdMapper USB_MAPPER = new UsbDeviceIdMapper();
|
||||||
final private static String RIP_EXE = "rip.exe";
|
final private static String RIP_EXE = "rip.exe";
|
||||||
final private static String RIP_PL = "rip.pl";
|
final private static String RIP_PL = "rip.pl";
|
||||||
final private static int MS_IN_SEC = 1000;
|
final private static int MS_IN_SEC = 1000;
|
||||||
final private static String NEVER_DATE = "Never";
|
final private static String NEVER_DATE = "Never";
|
||||||
final private static String SECTION_DIVIDER = "-------------------------";
|
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> rrCmd = new ArrayList<>();
|
||||||
private final List<String> rrFullCmd = 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 {
|
ExtractRegistry() throws IngestModuleException {
|
||||||
moduleName = NbBundle.getMessage(ExtractIE.class, "ExtractRegistry.moduleName.text");
|
moduleName = NbBundle.getMessage(ExtractIE.class, "ExtractRegistry.moduleName.text");
|
||||||
@ -106,19 +122,19 @@ class ExtractRegistry extends Extract {
|
|||||||
executableToRun = RIP_PL;
|
executableToRun = RIP_PL;
|
||||||
}
|
}
|
||||||
rrHome = rrRoot.toPath();
|
rrHome = rrRoot.toPath();
|
||||||
RR_PATH = rrHome.resolve(executableToRun).toString();
|
String rrPath = rrHome.resolve(executableToRun).toString();
|
||||||
rrFullHome = rrFullRoot.toPath();
|
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());
|
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());
|
throw new IngestModuleException(Bundle.RegRipperFullNotFound());
|
||||||
}
|
}
|
||||||
if (PlatformUtil.isWindowsOS()) {
|
if (PlatformUtil.isWindowsOS()) {
|
||||||
rrCmd.add(RR_PATH);
|
rrCmd.add(rrPath);
|
||||||
rrFullCmd.add(RR_FULL_PATH);
|
rrFullCmd.add(rrFullPath);
|
||||||
} else {
|
} else {
|
||||||
String perl;
|
String perl;
|
||||||
File usrBin = new File("/usr/bin/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");
|
throw new IngestModuleException("perl not found in your system");
|
||||||
}
|
}
|
||||||
rrCmd.add(perl);
|
rrCmd.add(perl);
|
||||||
rrCmd.add(RR_PATH);
|
rrCmd.add(rrPath);
|
||||||
rrFullCmd.add(perl);
|
rrFullCmd.add(perl);
|
||||||
rrFullCmd.add(RR_FULL_PATH);
|
rrFullCmd.add(rrFullPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,24 +240,20 @@ class ExtractRegistry extends Extract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse the autopsy-specific output
|
// parse the autopsy-specific output
|
||||||
if (regOutputFiles.autopsyPlugins.isEmpty() == false) {
|
if (regOutputFiles.autopsyPlugins.isEmpty() == false && parseAutopsyPluginOutput(regOutputFiles.autopsyPlugins, regFile) == false) {
|
||||||
if (parseAutopsyPluginOutput(regOutputFiles.autopsyPlugins, regFile) == false) {
|
|
||||||
this.addErrorMessage(
|
this.addErrorMessage(
|
||||||
NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
|
NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
|
||||||
this.getName(), regFileName));
|
this.getName(), regFileName));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// create a report for the full output
|
// create a report for the full output
|
||||||
if (!regOutputFiles.fullPlugins.isEmpty()) {
|
if (!regOutputFiles.fullPlugins.isEmpty()) {
|
||||||
//parse the full regripper output from SAM hive files
|
//parse the full regripper output from SAM hive files
|
||||||
if (regFileNameLocal.toLowerCase().contains("sam")) {
|
if (regFileNameLocal.toLowerCase().contains("sam") && parseSamPluginOutput(regOutputFiles.fullPlugins, regFile) == false) {
|
||||||
if (parseSamPluginOutput(regOutputFiles.fullPlugins, regFile) == false) {
|
|
||||||
this.addErrorMessage(
|
this.addErrorMessage(
|
||||||
NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
|
NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
|
||||||
this.getName(), regFileName));
|
this.getName(), regFileName));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
Report report = currentCase.addReport(regOutputFiles.fullPlugins,
|
Report report = currentCase.addReport(regOutputFiles.fullPlugins,
|
||||||
NbBundle.getMessage(this.getClass(), "ExtractRegistry.parentModuleName.noSpace"),
|
NbBundle.getMessage(this.getClass(), "ExtractRegistry.parentModuleName.noSpace"),
|
||||||
@ -259,7 +271,6 @@ class ExtractRegistry extends Extract {
|
|||||||
this.addErrorMessage("Error adding regripper output as Autopsy report: " + e.getLocalizedMessage()); //NON-NLS
|
this.addErrorMessage("Error adding regripper output as Autopsy report: " + e.getLocalizedMessage()); //NON-NLS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete the hive
|
// delete the hive
|
||||||
regFileNameLocalFile.delete();
|
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.
|
* Execute regripper on the given registry.
|
||||||
*
|
*
|
||||||
@ -406,12 +411,11 @@ class ExtractRegistry extends Extract {
|
|||||||
Element timenode = (Element) timenodes.item(0);
|
Element timenode = (Element) timenodes.item(0);
|
||||||
String etime = timenode.getTextContent();
|
String etime = timenode.getTextContent();
|
||||||
try {
|
try {
|
||||||
Long epochtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy").parse(etime).getTime();
|
mtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy").parse(etime).getTime();
|
||||||
mtime = epochtime;
|
|
||||||
String Tempdate = mtime.toString();
|
String Tempdate = mtime.toString();
|
||||||
mtime = Long.valueOf(Tempdate) / MS_IN_SEC;
|
mtime = Long.valueOf(Tempdate) / MS_IN_SEC;
|
||||||
} catch (ParseException ex) {
|
} 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);
|
Element artroot = (Element) artroots.item(0);
|
||||||
NodeList myartlist = artroot.getChildNodes();
|
NodeList myartlist = artroot.getChildNodes();
|
||||||
String parentModuleName = RecentActivityExtracterModuleFactory.getModuleName();
|
String parentModuleName = RecentActivityExtracterModuleFactory.getModuleName();
|
||||||
String winver = "";
|
|
||||||
|
|
||||||
// If all artifact nodes should really go under one Blackboard artifact, need to process it differently
|
// If all artifact nodes should really go under one Blackboard artifact, need to process it differently
|
||||||
switch (dataType) {
|
switch (dataType) {
|
||||||
@ -508,7 +511,6 @@ class ExtractRegistry extends Extract {
|
|||||||
case "Profiler": // NON-NLS
|
case "Profiler": // NON-NLS
|
||||||
String os = "";
|
String os = "";
|
||||||
String procArch = "";
|
String procArch = "";
|
||||||
String procId = "";
|
|
||||||
String tempDir = "";
|
String tempDir = "";
|
||||||
for (int j = 0; j < myartlist.getLength(); j++) {
|
for (int j = 0; j < myartlist.getLength(); j++) {
|
||||||
Node artchild = myartlist.item(j);
|
Node artchild = myartlist.item(j);
|
||||||
@ -526,7 +528,6 @@ class ExtractRegistry extends Extract {
|
|||||||
procArch = value;
|
procArch = value;
|
||||||
break;
|
break;
|
||||||
case "PROCESSOR_IDENTIFIER": //NON-NLS
|
case "PROCESSOR_IDENTIFIER": //NON-NLS
|
||||||
procId = value;
|
|
||||||
break;
|
break;
|
||||||
case "TEMP": //NON-NLS
|
case "TEMP": //NON-NLS
|
||||||
tempDir = value;
|
tempDir = value;
|
||||||
@ -652,7 +653,7 @@ class ExtractRegistry extends Extract {
|
|||||||
try {
|
try {
|
||||||
Long epochtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy").parse(artnode.getAttribute("mtime")).getTime(); //NON-NLS
|
Long epochtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy").parse(artnode.getAttribute("mtime")).getTime(); //NON-NLS
|
||||||
itemMtime = epochtime;
|
itemMtime = epochtime;
|
||||||
itemMtime = itemMtime / MS_IN_SEC;
|
itemMtime /= MS_IN_SEC;
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
logger.log(Level.WARNING, "Failed to parse epoch time for installed program artifact."); //NON-NLS
|
logger.log(Level.WARNING, "Failed to parse epoch time for installed program artifact."); //NON-NLS
|
||||||
}
|
}
|
||||||
@ -852,10 +853,9 @@ class ExtractRegistry extends Extract {
|
|||||||
String line = bufferedReader.readLine();
|
String line = bufferedReader.readLine();
|
||||||
Set<UserInfo> userSet = new HashSet<>();
|
Set<UserInfo> userSet = new HashSet<>();
|
||||||
while (line != null) {
|
while (line != null) {
|
||||||
if (line.contains(SECTION_DIVIDER) && previousLine != null) {
|
if (line.contains(SECTION_DIVIDER) && previousLine != null && previousLine.contains(userInfoSection)) {
|
||||||
if (previousLine.contains(userInfoSection)) {
|
|
||||||
readUsers(bufferedReader, userSet);
|
readUsers(bufferedReader, userSet);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
previousLine = line;
|
previousLine = line;
|
||||||
line = bufferedReader.readLine();
|
line = bufferedReader.readLine();
|
||||||
@ -953,8 +953,7 @@ class ExtractRegistry extends Extract {
|
|||||||
if (line.contains(userNameLabel)) {
|
if (line.contains(userNameLabel)) {
|
||||||
String userNameAndIdString = line.replace(userNameLabel, "");
|
String userNameAndIdString = line.replace(userNameLabel, "");
|
||||||
userName = userNameAndIdString.substring(0, userNameAndIdString.lastIndexOf('[')).trim();
|
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();
|
String sid = line.replace(sidLabel, "").trim();
|
||||||
UserInfo userInfo = new UserInfo(userName, sid);
|
UserInfo userInfo = new UserInfo(userName, sid);
|
||||||
//continue reading this users information until end of file or a blank line between users
|
//continue reading this users information until end of file or a blank line between users
|
||||||
@ -986,6 +985,15 @@ class ExtractRegistry extends Extract {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Class for organizing information associated with a TSK_OS_ACCOUNT before
|
||||||
* the artifact is created.
|
* the artifact is created.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#Updated by build script
|
#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
|
LBL_splash_window_title=Starting Autopsy
|
||||||
SPLASH_HEIGHT=314
|
SPLASH_HEIGHT=314
|
||||||
SPLASH_WIDTH=538
|
SPLASH_WIDTH=538
|
||||||
@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18
|
|||||||
SplashRunningTextColor=0x0
|
SplashRunningTextColor=0x0
|
||||||
SplashRunningTextFontSize=19
|
SplashRunningTextFontSize=19
|
||||||
|
|
||||||
currentVersion=Autopsy 4.10.0
|
currentVersion=Autopsy 4.11.0
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#Updated by build script
|
#Updated by build script
|
||||||
#Tue, 26 Feb 2019 14:37:44 -0500
|
#Wed, 08 May 2019 21:37:02 -0400
|
||||||
CTL_MainWindow_Title=Autopsy 4.10.0
|
CTL_MainWindow_Title=Autopsy 4.11.0
|
||||||
CTL_MainWindow_Title_No_Project=Autopsy 4.10.0
|
CTL_MainWindow_Title_No_Project=Autopsy 4.11.0
|
||||||
|
@ -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()) {
|
for (Telephone telephone : vcard.getTelephoneNumbers()) {
|
||||||
addPhoneAttributes(telephone, abstractFile, attributes);
|
addPhoneAttributes(telephone, abstractFile, attributes);
|
||||||
@ -412,7 +412,7 @@ final class VcardParser {
|
|||||||
type.getValue().toUpperCase().replaceAll("\\s+","").split(","));
|
type.getValue().toUpperCase().replaceAll("\\s+","").split(","));
|
||||||
|
|
||||||
for (String splitType : splitTelephoneTypes) {
|
for (String splitType : splitTelephoneTypes) {
|
||||||
String attributeTypeName = "TSK_PHONE_" + splitType;
|
String attributeTypeName = "TSK_PHONE_NUMBER_" + splitType;
|
||||||
try {
|
try {
|
||||||
BlackboardAttribute.Type attributeType = tskCase.getAttributeType(attributeTypeName);
|
BlackboardAttribute.Type attributeType = tskCase.getAttributeType(attributeTypeName);
|
||||||
if (attributeType == null) {
|
if (attributeType == null) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user