3562 merge changes from develop
@ -6,6 +6,13 @@
|
||||
|
||||
</configurations>
|
||||
<dependencies >
|
||||
|
||||
|
||||
<dependency conf="core->default" org="com.github.jgraph" name="jgraphx" rev="v3.8.0"/>
|
||||
|
||||
|
||||
|
||||
|
||||
<dependency conf="core->default" org="org.apache.activemq" name="activemq-all" rev="5.11.1"/>
|
||||
<dependency conf="core->default" org="org.apache.curator" name="curator-client" rev="2.8.0"/>
|
||||
<dependency conf="core->default" org="org.apache.curator" name="curator-framework" rev="2.8.0"/>
|
||||
|
@ -4,6 +4,7 @@
|
||||
<chain name="main">
|
||||
<ibiblio name="central" m2compatible="true"/>
|
||||
<ibiblio name="maven.restlet.org" root="http://maven.restlet.com" m2compatible="true" />
|
||||
<ibiblio name="jitpack.io" root="https://jitpack.io" m2compatible="true" />
|
||||
</chain>
|
||||
</resolvers>
|
||||
</ivysettings>
|
||||
|
@ -6,6 +6,7 @@ file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.
|
||||
file.reference.dd-plist-1.20.jar=release\\modules\\ext\\dd-plist-1.20.jar
|
||||
file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
|
||||
file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar
|
||||
file.reference.jgraphx-v3.8.0.jar=release/modules/ext/jgraphx-v3.8.0.jar
|
||||
file.reference.jsoup-1.10.3.jar=release/modules/ext/jsoup-1.10.3.jar
|
||||
file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar
|
||||
file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar
|
||||
|
@ -15,6 +15,15 @@
|
||||
<specification-version>1.27.1.121</specification-version>
|
||||
</run-dependency>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<code-name-base>org.jdesktop.layout</code-name-base>
|
||||
<build-prerequisite/>
|
||||
<compile-dependency/>
|
||||
<run-dependency>
|
||||
<release-version>1</release-version>
|
||||
<specification-version>1.33.1</specification-version>
|
||||
</run-dependency>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<code-name-base>org.netbeans.api.progress</code-name-base>
|
||||
<build-prerequisite/>
|
||||
@ -349,6 +358,14 @@
|
||||
<runtime-relative-path>ext/curator-framework-2.8.0.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/curator-framework-2.8.0.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/commons-dbcp2-2.1.1.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/commons-dbcp2-2.1.1.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jgraphx-v3.8.0.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jgraphx-v3.8.0.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/commons-compress-1.14.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/commons-compress-1.14.jar</binary-origin>
|
||||
|
@ -36,10 +36,10 @@ GetTagNameDialog.tagNameExistsTskCore.msg=The {0} tag name already exists in the
|
||||
OpenLogFolder.error1=Log File Not Found: {0}
|
||||
OpenLogFolder.CouldNotOpenLogFolder=Could not open log folder
|
||||
CTL_OpenLogFolder=Open Log Folder
|
||||
CTL_OpenOutputFolder=Open Case Folder
|
||||
OpenOutputFolder.error1=Case Output Folder Not Found\: {0}
|
||||
OpenOutputFolder.noCaseOpen=No open case, therefore no current case output folder available.
|
||||
OpenOutputFolder.CouldNotOpenOutputFolder=Could not open case output folder
|
||||
CTL_OpenOutputFolder=Open Output Folder
|
||||
OpenOutputFolder.error1=Output Folder Not Found\: {0}
|
||||
OpenOutputFolder.noCaseOpen=No open case, therefore no current output folder available.
|
||||
OpenOutputFolder.CouldNotOpenOutputFolder=Could not open output folder
|
||||
ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot
|
||||
OpenPythonModulesFolderAction.actionName.text=Python Plugins
|
||||
OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python plugins folder not found: {0}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
/**
|
||||
* The action associated with the Tools/Open Case Folder menu item. It opens a
|
||||
* The action associated with the Tools/Open Output Folder menu item. It opens a
|
||||
* file explorer window for the root output directory for the currently open
|
||||
* case. If the case is a single-user case, this is the case directory. If the
|
||||
* case is a multi-user case, this is a subdirectory of the case directory
|
||||
@ -46,7 +46,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
* This action should only be invoked in the event dispatch thread (EDT).
|
||||
*/
|
||||
@ActionRegistration(displayName = "#CTL_OpenOutputFolder", iconInMenu = true, lazy = false)
|
||||
@ActionReference(path = "Menu/Case", position = 302)
|
||||
@ActionReference(path = "Menu/Tools", position = 1850, separatorBefore = 1849)
|
||||
@ActionID(id = "org.sleuthkit.autopsy.actions.OpenOutputFolderAction", category = "Help")
|
||||
public final class OpenOutputFolderAction extends CallableSystemAction {
|
||||
|
||||
@ -63,7 +63,7 @@ public final class OpenOutputFolderAction extends CallableSystemAction {
|
||||
try {
|
||||
Desktop.getDesktop().open(outputDir);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Failed to open case output folder %s", outputDir), ex); //NON-NLS
|
||||
logger.log(Level.SEVERE, String.format("Failed to open output folder %s", outputDir), ex); //NON-NLS
|
||||
NotifyDescriptor descriptor = new NotifyDescriptor.Message(
|
||||
NbBundle.getMessage(this.getClass(), "OpenOutputFolder.CouldNotOpenOutputFolder", outputDir.getAbsolutePath()), NotifyDescriptor.ERROR_MESSAGE);
|
||||
DialogDisplayer.getDefault().notify(descriptor);
|
||||
|
@ -107,9 +107,15 @@ class AddImageTask implements Runnable {
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
Case currentCase;
|
||||
try {
|
||||
currentCase = Case.getOpenCase();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Exception while getting open case.", ex);
|
||||
return;
|
||||
}
|
||||
progressMonitor.setIndeterminate(true);
|
||||
progressMonitor.setProgress(0);
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
String imageWriterPath = "";
|
||||
if (imageWriterSettings != null) {
|
||||
imageWriterPath = imageWriterSettings.getPath();
|
||||
|
@ -29,6 +29,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
@ -46,6 +47,7 @@ import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescriptorPanel;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
/**
|
||||
* The final panel of the add image wizard. It displays a progress bar and
|
||||
@ -331,7 +333,11 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel {
|
||||
cleanupTask.enable();
|
||||
|
||||
new Thread(() -> {
|
||||
Case.getCurrentCase().notifyAddingDataSource(dataSourceId);
|
||||
try {
|
||||
Case.getOpenCase().notifyAddingDataSource(dataSourceId);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
Logger.getLogger(AddImageWizardAddingProgressVisual.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
|
||||
}
|
||||
}).start();
|
||||
DataSourceProcessorCallback cbObj = new DataSourceProcessorCallback() {
|
||||
@Override
|
||||
@ -398,10 +404,14 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel {
|
||||
|
||||
//notify the UI of the new content added to the case
|
||||
new Thread(() -> {
|
||||
try {
|
||||
if (!contents.isEmpty()) {
|
||||
Case.getCurrentCase().notifyDataSourceAdded(contents.get(0), dataSourceId);
|
||||
Case.getOpenCase().notifyDataSourceAdded(contents.get(0), dataSourceId);
|
||||
} else {
|
||||
Case.getCurrentCase().notifyFailedAddingDataSource(dataSourceId);
|
||||
Case.getOpenCase().notifyFailedAddingDataSource(dataSourceId);
|
||||
}
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
Logger.getLogger(AddImageWizardAddingProgressVisual.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
|
||||
}
|
||||
}).start();
|
||||
|
||||
|
@ -583,6 +583,8 @@ public class Case {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated. Use getOpenCase() instead.
|
||||
*
|
||||
* Gets the current case, if there is one, at the time of the call.
|
||||
*
|
||||
* @return The current case.
|
||||
|
@ -66,7 +66,7 @@ final class CaseDeleteAction extends CallableSystemAction {
|
||||
"# {0} - exception message", "Case.deleteCaseFailureMessageBox.message=Error deleting case: {0}",})
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
Case currentCase = Case.getOpenCase();
|
||||
String caseName = currentCase.getName();
|
||||
String caseDirectory = currentCase.getCaseDirectory();
|
||||
|
||||
@ -110,7 +110,7 @@ final class CaseDeleteAction extends CallableSystemAction {
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
} catch (IllegalStateException ex) {
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Case delete action called with no current case", ex);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -20,9 +20,11 @@ package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.windows.WindowManager;
|
||||
|
||||
@ -51,7 +53,11 @@ class CaseInformationPanel extends javax.swing.JPanel {
|
||||
"CaseInformationPanel.editDetailsDialog.title=Edit Case Details"
|
||||
})
|
||||
private void customizeComponents() {
|
||||
propertiesPanel = new CasePropertiesPanel(Case.getCurrentCase());
|
||||
try {
|
||||
propertiesPanel = new CasePropertiesPanel(Case.getOpenCase());
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
Logger.getLogger(CaseInformationPanel.class.getName()).log(Level.INFO, "Exception while getting open case.", ex);
|
||||
}
|
||||
propertiesPanel.setSize(propertiesPanel.getPreferredSize());
|
||||
this.tabbedPane.addTab(Bundle.CaseInformationPanel_caseDetails_header(), propertiesPanel);
|
||||
this.tabbedPane.addTab(Bundle.CaseInformationPanel_ingestJobInfo_header(), new IngestJobInfoPanel());
|
||||
@ -59,11 +65,6 @@ class CaseInformationPanel extends javax.swing.JPanel {
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
tabbedPane.getSelectedComponent().setSize(tabbedPane.getSelectedComponent().getPreferredSize());
|
||||
if (tabbedPane.getSelectedComponent() instanceof CasePropertiesPanel) {
|
||||
editDetailsButton.setVisible(true);
|
||||
} else {
|
||||
editDetailsButton.setVisible(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -49,7 +49,12 @@ final class CasePropertiesPanel extends javax.swing.JPanel {
|
||||
}
|
||||
|
||||
void updateCaseInfo() {
|
||||
theCase = Case.getCurrentCase();
|
||||
try {
|
||||
theCase = Case.getOpenCase();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
|
||||
return;
|
||||
}
|
||||
lbCaseNameText.setText(theCase.getDisplayName());
|
||||
lbCaseNumberText.setText(theCase.getNumber());
|
||||
lbExaminerNameText.setText(theCase.getExaminer());
|
||||
@ -78,9 +83,9 @@ final class CasePropertiesPanel extends javax.swing.JPanel {
|
||||
try {
|
||||
EamDb dbManager = EamDb.getInstance();
|
||||
if (dbManager != null) {
|
||||
CorrelationCase correlationCase = dbManager.getCase(Case.getCurrentCase());
|
||||
CorrelationCase correlationCase = dbManager.getCase(theCase);
|
||||
if (null == correlationCase) {
|
||||
correlationCase = dbManager.newCase(Case.getCurrentCase());
|
||||
correlationCase = dbManager.newCase(theCase);
|
||||
}
|
||||
currentOrg = correlationCase.getOrg();
|
||||
}
|
||||
|
@ -122,8 +122,8 @@ final class CollaborationMonitor {
|
||||
* 2. Check for stale remote tasks.<br>
|
||||
*/
|
||||
periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build());
|
||||
periodicTasksExecutor.scheduleAtFixedRate(new HeartbeatTask(), HEARTBEAT_INTERVAL_MINUTES, HEARTBEAT_INTERVAL_MINUTES, TimeUnit.MINUTES);
|
||||
periodicTasksExecutor.scheduleAtFixedRate(new StaleTaskDetectionTask(), STALE_TASKS_DETECT_INTERVAL_MINS, STALE_TASKS_DETECT_INTERVAL_MINS, TimeUnit.MINUTES);
|
||||
periodicTasksExecutor.scheduleWithFixedDelay(new HeartbeatTask(), HEARTBEAT_INTERVAL_MINUTES, HEARTBEAT_INTERVAL_MINUTES, TimeUnit.MINUTES);
|
||||
periodicTasksExecutor.scheduleWithFixedDelay(new StaleTaskDetectionTask(), STALE_TASKS_DETECT_INTERVAL_MINS, STALE_TASKS_DETECT_INTERVAL_MINS, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -31,6 +31,7 @@ import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.NbBundle;
|
||||
import static org.sleuthkit.autopsy.casemodule.Bundle.*;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
@ -306,7 +307,9 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
|
||||
*
|
||||
* @return true if a proper image has been selected, false otherwise
|
||||
*/
|
||||
@NbBundle.Messages("ImageFilePanel.pathValidation.dataSourceOnCDriveError=Warning: Path to multi-user data source is on \"C:\" drive")
|
||||
@NbBundle.Messages({"ImageFilePanel.pathValidation.dataSourceOnCDriveError=Warning: Path to multi-user data source is on \"C:\" drive",
|
||||
"ImageFilePanel.pathValidation.getOpenCase.Error=Warning: Exception while getting open case."
|
||||
})
|
||||
public boolean validatePanel() {
|
||||
pathErrorLabel.setVisible(false);
|
||||
String path = getContentPaths();
|
||||
@ -315,10 +318,15 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
|
||||
}
|
||||
|
||||
// Display warning if there is one (but don't disable "next" button)
|
||||
if (false == PathValidator.isValid(path, Case.getCurrentCase().getCaseType())) {
|
||||
try {
|
||||
if (false == PathValidator.isValid(path, Case.getOpenCase().getCaseType())) {
|
||||
pathErrorLabel.setVisible(true);
|
||||
pathErrorLabel.setText(Bundle.ImageFilePanel_pathValidation_dataSourceOnCDriveError());
|
||||
}
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
pathErrorLabel.setVisible(true);
|
||||
pathErrorLabel.setText(Bundle.ImageFilePanel_pathValidation_getOpenCase_Error());
|
||||
}
|
||||
|
||||
return new File(path).isFile()
|
||||
|| DriveUtils.isPhysicalDrive(path)
|
||||
|
@ -75,12 +75,12 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
|
||||
try {
|
||||
SleuthkitCase skCase = Case.getOpenCase().getSleuthkitCase();
|
||||
List<IngestJobInfo> ingestJobs = skCase.getIngestJobs();
|
||||
this.ingestJobs = ingestJobs;
|
||||
this.repaint();
|
||||
} catch (TskCoreException ex) {
|
||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to load ingest jobs.", ex);
|
||||
JOptionPane.showMessageDialog(this, Bundle.IngestJobInfoPanel_loadIngestJob_error_text(), Bundle.IngestJobInfoPanel_loadIngestJob_error_title(), JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
@ -114,11 +114,11 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
IngestJobInfo currIngestJob = ingestJobs.get(rowIndex);
|
||||
SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
|
||||
if (columnIndex == 0) {
|
||||
try {
|
||||
SleuthkitCase skCase = Case.getOpenCase().getSleuthkitCase();
|
||||
return skCase.getContentById(currIngestJob.getObjectId()).getName();
|
||||
} catch (TskCoreException ex) {
|
||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to get content from db", ex);
|
||||
return "";
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import javax.swing.JPanel;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.openide.modules.InstalledFileLocator;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
|
@ -275,10 +275,12 @@ final class LocalFilesPanel extends javax.swing.JPanel {
|
||||
*
|
||||
* @param paths Absolute paths to the selected data source
|
||||
*/
|
||||
@NbBundle.Messages("LocalFilesPanel.pathValidation.error=WARNING: Exception while gettting opon case.")
|
||||
private void warnIfPathIsInvalid(final List<String> pathsList) {
|
||||
errorLabel.setVisible(false);
|
||||
|
||||
final Case.CaseType currentCaseType = Case.getCurrentCase().getCaseType();
|
||||
try {
|
||||
final Case.CaseType currentCaseType = Case.getOpenCase().getCaseType();
|
||||
|
||||
for (String currentPath : pathsList) {
|
||||
if (!PathValidator.isValid(currentPath, currentCaseType)) {
|
||||
@ -287,6 +289,10 @@ final class LocalFilesPanel extends javax.swing.JPanel {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
errorLabel.setVisible(true);
|
||||
errorLabel.setText(Bundle.LocalFilesPanel_pathValidation_error());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,6 +32,7 @@ import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.PathValidator;
|
||||
@ -178,7 +179,8 @@ final class LogicalEvidenceFilePanel extends javax.swing.JPanel implements Docum
|
||||
*/
|
||||
@Messages({
|
||||
"LogicalEvidenceFilePanel.validatePanel.nonL01Error.text=Only files with the .l01 file extension are supported here.",
|
||||
"LogicalEvidenceFilePanel.pathValidation.dataSourceOnCDriveError=Warning: Path to multi-user data source is on \"C:\" drive"
|
||||
"LogicalEvidenceFilePanel.pathValidation.dataSourceOnCDriveError=Warning: Path to multi-user data source is on \"C:\" drive",
|
||||
"LogicalEvidenceFilePanel.pathValidation.getOpenCase.Error=Warning: Exception while getting open case."
|
||||
})
|
||||
boolean validatePanel() {
|
||||
errorLabel.setVisible(false);
|
||||
@ -188,11 +190,17 @@ final class LogicalEvidenceFilePanel extends javax.swing.JPanel implements Docum
|
||||
return false;
|
||||
}
|
||||
// display warning if there is one (but don't disable "next" button)
|
||||
if (!PathValidator.isValid(path, Case.getCurrentCase().getCaseType())) {
|
||||
try {
|
||||
if (!PathValidator.isValid(path, Case.getOpenCase().getCaseType())) {
|
||||
errorLabel.setVisible(true);
|
||||
errorLabel.setText(Bundle.LogicalEvidenceFilePanel_pathValidation_dataSourceOnCDriveError());
|
||||
return false;
|
||||
}
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
errorLabel.setVisible(true);
|
||||
errorLabel.setText(Bundle.LogicalEvidenceFilePanel_pathValidation_getOpenCase_Error());
|
||||
return false;
|
||||
}
|
||||
//check the extension incase the path was manually entered
|
||||
if (!LocalFilesDSProcessor.getLogicalEvidenceFilter().accept(new File(path))) {
|
||||
errorLabel.setVisible(true);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -62,12 +62,19 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
|
||||
OptionalCasePropertiesPanel(boolean editCurrentCase) {
|
||||
initComponents();
|
||||
if (editCurrentCase) {
|
||||
caseDisplayNameTextField.setText(Case.getCurrentCase().getDisplayName());
|
||||
caseNumberTextField.setText(Case.getCurrentCase().getNumber());
|
||||
examinerTextField.setText(Case.getCurrentCase().getExaminer());
|
||||
tfExaminerEmailText.setText(Case.getCurrentCase().getExaminerEmail());
|
||||
tfExaminerPhoneText.setText(Case.getCurrentCase().getExaminerPhone());
|
||||
taNotesText.setText(Case.getCurrentCase().getCaseNotes());
|
||||
Case openCase;
|
||||
try {
|
||||
openCase = Case.getOpenCase();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
|
||||
return;
|
||||
}
|
||||
caseDisplayNameTextField.setText(openCase.getDisplayName());
|
||||
caseNumberTextField.setText(openCase.getNumber());
|
||||
examinerTextField.setText(openCase.getExaminer());
|
||||
tfExaminerEmailText.setText(openCase.getExaminerEmail());
|
||||
tfExaminerPhoneText.setText(openCase.getExaminerPhone());
|
||||
taNotesText.setText(openCase.getCaseNotes());
|
||||
setUpCaseDetailsFields();
|
||||
setUpOrganizationData();
|
||||
} else {
|
||||
@ -86,15 +93,18 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
|
||||
|
||||
private void setUpOrganizationData() {
|
||||
if (EamDb.isEnabled()) {
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
if (currentCase != null) {
|
||||
try {
|
||||
Case currentCase = Case.getOpenCase();
|
||||
if (currentCase != null) {
|
||||
EamDb dbManager = EamDb.getInstance();
|
||||
selectedOrg = dbManager.getCase(currentCase).getOrg();
|
||||
}
|
||||
} catch (EamDbException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to get Organization associated with the case from Central Repo", ex);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedOrg != null) {
|
||||
setCurrentlySelectedOrganization(selectedOrg.getName());
|
||||
}
|
||||
@ -533,7 +543,8 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
|
||||
|
||||
@Messages({
|
||||
"OptionalCasePropertiesPanel.errorDialog.emptyCaseNameMessage=No case name entered.",
|
||||
"OptionalCasePropertiesPanel.errorDialog.invalidCaseNameMessage=Case names cannot include the following symbols: \\, /, :, *, ?, \", <, >, |"
|
||||
"OptionalCasePropertiesPanel.errorDialog.invalidCaseNameMessage=Case names cannot include the following symbols: \\, /, :, *, ?, \", <, >, |",
|
||||
"OptionalCasePropertiesPanel.errorDialog.noOpenCase.errMsg=Exception while getting open case."
|
||||
})
|
||||
void saveUpdatedCaseDetails() {
|
||||
if (caseDisplayNameTextField.getText().trim().isEmpty()) {
|
||||
@ -544,14 +555,19 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
|
||||
MessageNotifyUtil.Message.error(Bundle.OptionalCasePropertiesPanel_errorDialog_invalidCaseNameMessage());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
updateCaseDetails();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
MessageNotifyUtil.Message.error(Bundle.OptionalCasePropertiesPanel_errorDialog_noOpenCase_errMsg());
|
||||
return;
|
||||
}
|
||||
updateCorrelationCase();
|
||||
}
|
||||
|
||||
private void updateCaseDetails() {
|
||||
private void updateCaseDetails() throws NoCurrentCaseException {
|
||||
if (caseDisplayNameTextField.isVisible()) {
|
||||
try {
|
||||
Case.getCurrentCase().updateCaseDetails(new CaseDetails(
|
||||
Case.getOpenCase().updateCaseDetails(new CaseDetails(
|
||||
caseDisplayNameTextField.getText(), caseNumberTextField.getText(),
|
||||
examinerTextField.getText(), tfExaminerPhoneText.getText(),
|
||||
tfExaminerEmailText.getText(), taNotesText.getText()));
|
||||
@ -570,7 +586,7 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
|
||||
if (EamDb.isEnabled()) {
|
||||
try {
|
||||
EamDb dbManager = EamDb.getInstance();
|
||||
CorrelationCase correlationCase = dbManager.getCase(Case.getCurrentCase());
|
||||
CorrelationCase correlationCase = dbManager.getCase(Case.getOpenCase());
|
||||
if (caseDisplayNameTextField.isVisible()) {
|
||||
correlationCase.setDisplayName(caseDisplayNameTextField.getText());
|
||||
}
|
||||
@ -583,6 +599,8 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
|
||||
dbManager.updateCase(correlationCase);
|
||||
} catch (EamDbException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error connecting to central repository database", ex); // NON-NLS
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
|
||||
} finally {
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2015 Basis Technology Corp.
|
||||
* Copyright 2015-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule.events;
|
||||
import java.io.Serializable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
@ -41,11 +42,11 @@ public class BlackBoardArtifactTagAddedEvent extends TagAddedEvent<BlackboardArt
|
||||
*
|
||||
* @return BlackboardArtifactTag that was added
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* @throws NoCurrentCaseException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
@Override
|
||||
BlackboardArtifactTag getTagByID() throws IllegalStateException, TskCoreException {
|
||||
return Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagByTagID(getTagID());
|
||||
BlackboardArtifactTag getTagByID() throws NoCurrentCaseException, TskCoreException {
|
||||
return Case.getOpenCase().getServices().getTagsManager().getBlackboardArtifactTagByTagID(getTagID());
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2015 Basis Technology Corp.
|
||||
* Copyright 2015-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule.events;
|
||||
import java.io.Serializable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
@ -41,10 +42,10 @@ public class ContentTagAddedEvent extends TagAddedEvent<ContentTag> implements S
|
||||
*
|
||||
* @return ContentTag that was added
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* @throws NoCurrentCaseException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
ContentTag getTagByID() throws IllegalStateException, TskCoreException {
|
||||
return Case.getCurrentCase().getServices().getTagsManager().getContentTagByTagID(getTagID());
|
||||
ContentTag getTagByID() throws NoCurrentCaseException, TskCoreException {
|
||||
return Case.getOpenCase().getServices().getTagsManager().getContentTagByTagID(getTagID());
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2015 Basis Technology Corp.
|
||||
* Copyright 2015-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -22,6 +22,7 @@ import java.io.Serializable;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
@ -78,9 +79,9 @@ public final class DataSourceAddedEvent extends AutopsyEvent implements Serializ
|
||||
}
|
||||
try {
|
||||
long id = (Long) super.getNewValue();
|
||||
dataSource = Case.getCurrentCase().getSleuthkitCase().getContentById(id);
|
||||
dataSource = Case.getOpenCase().getSleuthkitCase().getContentById(id);
|
||||
return dataSource;
|
||||
} catch (IllegalStateException | TskCoreException ex) {
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS
|
||||
return null;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2015 Basis Technology Corp.
|
||||
* Copyright 2015-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -22,6 +22,7 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
import org.sleuthkit.datamodel.Report;
|
||||
@ -69,7 +70,7 @@ public final class ReportAddedEvent extends AutopsyEvent implements Serializable
|
||||
}
|
||||
try {
|
||||
long id = (Long) super.getNewValue();
|
||||
List<Report> reports = Case.getCurrentCase().getSleuthkitCase().getAllReports();
|
||||
List<Report> reports = Case.getOpenCase().getSleuthkitCase().getAllReports();
|
||||
for (Report thisReport : reports) {
|
||||
if (thisReport.getId() == id) {
|
||||
report = thisReport;
|
||||
@ -77,7 +78,7 @@ public final class ReportAddedEvent extends AutopsyEvent implements Serializable
|
||||
}
|
||||
}
|
||||
return report;
|
||||
} catch (IllegalStateException | TskCoreException ex) {
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS
|
||||
return null;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2015 Basis Technology Corp.
|
||||
* Copyright 2015-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.casemodule.events;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
import org.sleuthkit.datamodel.Tag;
|
||||
@ -84,7 +85,7 @@ abstract class TagAddedEvent<T extends Tag> extends AutopsyEvent implements Seri
|
||||
try {
|
||||
tag = getTagByID();
|
||||
return tag;
|
||||
} catch (IllegalStateException | TskCoreException ex) {
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
Logger.getLogger(TagAddedEvent.class.getName()).log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS
|
||||
return null;
|
||||
}
|
||||
@ -98,8 +99,8 @@ abstract class TagAddedEvent<T extends Tag> extends AutopsyEvent implements Seri
|
||||
*
|
||||
* @return the Tag based on the saved tag id
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* @throws NoCurrentCaseException
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
abstract T getTagByID() throws IllegalStateException, TskCoreException;
|
||||
abstract T getTagByID() throws NoCurrentCaseException, TskCoreException;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -28,6 +28,7 @@ import java.util.logging.Level;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
@ -295,9 +296,11 @@ final class TagNameDefinition implements Comparable<TagNameDefinition> {
|
||||
setting.append(";");
|
||||
}
|
||||
setting.append(tagName.toSettingsFormat());
|
||||
if (Case.isCaseOpen()) {
|
||||
SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase();
|
||||
try {
|
||||
SleuthkitCase caseDb = Case.getOpenCase().getSleuthkitCase();
|
||||
tagName.saveToCase(caseDb);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
|
||||
}
|
||||
}
|
||||
ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString());
|
||||
|
@ -24,6 +24,7 @@ import java.beans.PropertyChangeListener;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
@ -32,10 +33,12 @@ import org.netbeans.spi.options.OptionsPanelController;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
/**
|
||||
* A panel to allow the user to create and delete custom tag types.
|
||||
@ -421,8 +424,10 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
|
||||
private void sendStatusChangedEvents() {
|
||||
for (String modifiedTagDisplayName : updatedStatusTags) {
|
||||
//if user closes their case after options have been changed but before application of them is complete don't notify
|
||||
if (Case.isCaseOpen()) {
|
||||
Case.getCurrentCase().notifyTagDefinitionChanged(modifiedTagDisplayName);
|
||||
try {
|
||||
Case.getOpenCase().notifyTagDefinitionChanged(modifiedTagDisplayName);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
Logger.getLogger(TagOptionsPanel.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
updatedStatusTags.clear();
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -29,6 +29,7 @@ import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.NbBundle;
|
||||
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.BlackboardArtifactTag;
|
||||
@ -98,11 +99,11 @@ public class TagsManager implements Closeable {
|
||||
tagDisplayNames.add(tagType.getDisplayName());
|
||||
});
|
||||
try {
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
TagsManager tagsManager = Case.getOpenCase().getServices().getTagsManager();
|
||||
for (TagName tagName : tagsManager.getAllTagNames()) {
|
||||
tagDisplayNames.add(tagName.getDisplayName());
|
||||
}
|
||||
} catch (IllegalStateException ignored) {
|
||||
} catch (NoCurrentCaseException ignored) {
|
||||
/*
|
||||
* No current case, nothing more to add to the set.
|
||||
*/
|
||||
@ -339,8 +340,8 @@ public class TagsManager implements Closeable {
|
||||
ContentTag tag;
|
||||
tag = caseDb.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset);
|
||||
try {
|
||||
Case.getCurrentCase().notifyContentTagAdded(tag);
|
||||
} catch (IllegalStateException ex) {
|
||||
Case.getOpenCase().notifyContentTagAdded(tag);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
throw new TskCoreException("Added a tag to a closed case", ex);
|
||||
}
|
||||
return tag;
|
||||
@ -357,8 +358,8 @@ public class TagsManager implements Closeable {
|
||||
public void deleteContentTag(ContentTag tag) throws TskCoreException {
|
||||
caseDb.deleteContentTag(tag);
|
||||
try {
|
||||
Case.getCurrentCase().notifyContentTagDeleted(tag);
|
||||
} catch (IllegalStateException ex) {
|
||||
Case.getOpenCase().notifyContentTagDeleted(tag);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
throw new TskCoreException("Deleted a tag from a closed case", ex);
|
||||
}
|
||||
}
|
||||
@ -469,8 +470,8 @@ public class TagsManager implements Closeable {
|
||||
public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
|
||||
BlackboardArtifactTag tag = caseDb.addBlackboardArtifactTag(artifact, tagName, comment);
|
||||
try {
|
||||
Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(tag);
|
||||
} catch (IllegalStateException ex) {
|
||||
Case.getOpenCase().notifyBlackBoardArtifactTagAdded(tag);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
throw new TskCoreException("Added a tag to a closed case", ex);
|
||||
}
|
||||
return tag;
|
||||
@ -487,8 +488,8 @@ public class TagsManager implements Closeable {
|
||||
public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
|
||||
caseDb.deleteBlackboardArtifactTag(tag);
|
||||
try {
|
||||
Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag);
|
||||
} catch (IllegalStateException ex) {
|
||||
Case.getOpenCase().notifyBlackBoardArtifactTagDeleted(tag);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
throw new TskCoreException("Deleted a tag from a closed case", ex);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2015-2017 Basis Technology Corp.
|
||||
* Copyright 2015-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -46,6 +46,7 @@ import org.openide.nodes.Node;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||
@ -97,7 +98,11 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D
|
||||
} else if (jmi.equals(showCaseDetailsMenuItem)) {
|
||||
showCaseDetails(otherCasesTable.getSelectedRow());
|
||||
} else if (jmi.equals(exportToCSVMenuItem)) {
|
||||
try {
|
||||
saveToCSV();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
|
||||
}
|
||||
} else if (jmi.equals(showCommonalityMenuItem)) {
|
||||
showCommonalityDetails();
|
||||
}
|
||||
@ -159,8 +164,19 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D
|
||||
@Messages({"DataContentViewerOtherCases.caseDetailsDialog.notSelected=No Row Selected",
|
||||
"DataContentViewerOtherCases.caseDetailsDialog.noDetails=No details for this case.",
|
||||
"DataContentViewerOtherCases.caseDetailsDialog.noDetailsReference=No case details for Global reference properties.",
|
||||
"DataContentViewerOtherCases.caseDetailsDialog.noCaseNameError=Error"})
|
||||
"DataContentViewerOtherCases.caseDetailsDialog.noCaseNameError=Error",
|
||||
"DataContentViewerOtherCases.noOpenCase.errMsg=No open case available."})
|
||||
private void showCaseDetails(int selectedRowViewIdx) {
|
||||
Case openCase;
|
||||
try {
|
||||
openCase = Case.getOpenCase();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
|
||||
Bundle.DataContentViewerOtherCases_noOpenCase_errMsg(),
|
||||
Bundle.DataContentViewerOtherCases_noOpenCase_errMsg(),
|
||||
DEFAULT_OPTION, PLAIN_MESSAGE);
|
||||
return;
|
||||
}
|
||||
String caseDisplayName = Bundle.DataContentViewerOtherCases_caseDetailsDialog_noCaseNameError();
|
||||
try {
|
||||
if (-1 != selectedRowViewIdx) {
|
||||
@ -177,7 +193,7 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D
|
||||
}
|
||||
caseDisplayName = eamCasePartial.getDisplayName();
|
||||
// query case details
|
||||
CorrelationCase eamCase = dbManager.getCase(Case.getCurrentCase());
|
||||
CorrelationCase eamCase = dbManager.getCase(openCase);
|
||||
if (eamCase == null) {
|
||||
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
|
||||
Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
|
||||
@ -205,11 +221,11 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D
|
||||
}
|
||||
}
|
||||
|
||||
private void saveToCSV() {
|
||||
private void saveToCSV() throws NoCurrentCaseException {
|
||||
if (0 != otherCasesTable.getSelectedRowCount()) {
|
||||
Calendar now = Calendar.getInstance();
|
||||
String fileName = String.format("%1$tY%1$tm%1$te%1$tI%1$tM%1$tS_other_data_sources.csv", now);
|
||||
CSVFileChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory()));
|
||||
CSVFileChooser.setCurrentDirectory(new File(Case.getOpenCase().getExportDirectory()));
|
||||
CSVFileChooser.setSelectedFile(new File(fileName));
|
||||
CSVFileChooser.setFileFilter(new FileNameExtensionFilter("csv file", "csv"));
|
||||
|
||||
@ -417,8 +433,8 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D
|
||||
*/
|
||||
private Collection<CorrelationAttributeInstance> getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) {
|
||||
// @@@ Check exception
|
||||
String caseUUID = Case.getCurrentCase().getName();
|
||||
try {
|
||||
String caseUUID = Case.getOpenCase().getName();
|
||||
EamDb dbManager = EamDb.getInstance();
|
||||
Collection<CorrelationAttributeInstance> artifactInstances = dbManager.getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).stream()
|
||||
.filter(artifactInstance -> !artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
|
||||
@ -428,6 +444,8 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D
|
||||
return artifactInstances;
|
||||
} catch (EamDbException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
@ -473,9 +491,9 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D
|
||||
if (af != null) {
|
||||
Content dataSource = af.getDataSource();
|
||||
dataSourceName = dataSource.getName();
|
||||
deviceId = Case.getCurrentCase().getSleuthkitCase().getDataSource(dataSource.getId()).getDeviceId();
|
||||
deviceId = Case.getOpenCase().getSleuthkitCase().getDataSource(dataSource.getId()).getDeviceId();
|
||||
}
|
||||
} catch (TskException ex) {
|
||||
} catch (TskException | NoCurrentCaseException ex) {
|
||||
// do nothing.
|
||||
// @@@ Review this behavior
|
||||
}
|
||||
|
@ -2334,7 +2334,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
|
||||
}
|
||||
CorrelationAttributeInstance eamArtifactInstance = new CorrelationAttributeInstance(
|
||||
new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), resultSet.getString("case_name")),
|
||||
new CorrelationDataSource(resultSet.getInt("case_id"), -1, resultSet.getString("device_id"), resultSet.getString("name")),
|
||||
new CorrelationDataSource(-1, resultSet.getInt("case_id"), resultSet.getString("device_id"), resultSet.getString("name")),
|
||||
resultSet.getString("file_path"),
|
||||
resultSet.getString("comment"),
|
||||
TskData.FileKnown.valueOf(resultSet.getByte("known_status"))
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2015-2017 Basis Technology Corp.
|
||||
* Copyright 2015-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.centralrepository.datamodel;
|
||||
|
||||
import java.io.Serializable;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskDataException;
|
||||
@ -73,8 +74,8 @@ public class CorrelationDataSource implements Serializable {
|
||||
public static CorrelationDataSource fromTSKDataSource(CorrelationCase correlationCase, Content dataSource) throws EamDbException {
|
||||
Case curCase;
|
||||
try {
|
||||
curCase = Case.getCurrentCase();
|
||||
} catch (IllegalStateException ex) {
|
||||
curCase = Case.getOpenCase();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
throw new EamDbException("Autopsy case is closed");
|
||||
}
|
||||
String deviceId;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2015-2017 Basis Technology Corp.
|
||||
* Copyright 2015-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -23,6 +23,7 @@ import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
@ -89,7 +90,7 @@ public class EamArtifactUtil {
|
||||
// if they asked for it, add the instance details associated with this occurance.
|
||||
if (!eamArtifacts.isEmpty() && addInstanceDetails) {
|
||||
try {
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
Case currentCase = Case.getOpenCase();
|
||||
AbstractFile bbSourceFile = currentCase.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID());
|
||||
if (null == bbSourceFile) {
|
||||
//@@@ Log this
|
||||
@ -97,9 +98,9 @@ public class EamArtifactUtil {
|
||||
}
|
||||
|
||||
// make an instance for the BB source file
|
||||
CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getCurrentCase());
|
||||
CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getOpenCase());
|
||||
if (null == correlationCase) {
|
||||
correlationCase = EamDb.getInstance().newCase(Case.getCurrentCase());
|
||||
correlationCase = EamDb.getInstance().newCase(Case.getOpenCase());
|
||||
}
|
||||
CorrelationAttributeInstance eamInstance = new CorrelationAttributeInstance(
|
||||
correlationCase,
|
||||
@ -116,7 +117,7 @@ public class EamArtifactUtil {
|
||||
} catch (TskCoreException | EamDbException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error creating artifact instance.", ex); // NON-NLS
|
||||
return eamArtifacts;
|
||||
} catch (IllegalStateException ex) {
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Case is closed.", ex); // NON-NLS
|
||||
return eamArtifacts;
|
||||
}
|
||||
@ -145,7 +146,7 @@ public class EamArtifactUtil {
|
||||
// Get the associated artifact
|
||||
BlackboardAttribute attribute = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
|
||||
if (attribute != null) {
|
||||
BlackboardArtifact associatedArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
|
||||
BlackboardArtifact associatedArtifact = Case.getOpenCase().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
|
||||
return EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(correlationType, associatedArtifact);
|
||||
}
|
||||
|
||||
@ -203,6 +204,9 @@ public class EamArtifactUtil {
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS
|
||||
return null;
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
|
||||
return null;
|
||||
}
|
||||
|
||||
if (null != value) {
|
||||
@ -250,9 +254,9 @@ public class EamArtifactUtil {
|
||||
try {
|
||||
CorrelationAttribute.Type filesType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID);
|
||||
eamArtifact = new CorrelationAttribute(filesType, af.getMd5Hash());
|
||||
CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getCurrentCase());
|
||||
CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getOpenCase());
|
||||
if (null == correlationCase) {
|
||||
correlationCase = EamDb.getInstance().newCase(Case.getCurrentCase());
|
||||
correlationCase = EamDb.getInstance().newCase(Case.getOpenCase());
|
||||
}
|
||||
CorrelationAttributeInstance cei = new CorrelationAttributeInstance(
|
||||
correlationCase,
|
||||
@ -263,7 +267,7 @@ public class EamArtifactUtil {
|
||||
);
|
||||
eamArtifact.addInstance(cei);
|
||||
return eamArtifact;
|
||||
} catch (TskCoreException | EamDbException ex) {
|
||||
} catch (TskCoreException | EamDbException | NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error making correlation attribute.", ex);
|
||||
return null;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2015-2017 Basis Technology Corp.
|
||||
* Copyright 2015-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -28,6 +28,7 @@ import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
||||
@ -162,8 +163,8 @@ final class CaseEventListener implements PropertyChangeListener {
|
||||
|
||||
try {
|
||||
// Get the remaining tags on the content object
|
||||
Content content = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID);
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
Content content = Case.getOpenCase().getSleuthkitCase().getContentById(contentID);
|
||||
TagsManager tagsManager = Case.getOpenCase().getServices().getTagsManager();
|
||||
List<ContentTag> tags = tagsManager.getContentTagsByContent(content);
|
||||
|
||||
if (tags.stream()
|
||||
@ -185,7 +186,7 @@ final class CaseEventListener implements PropertyChangeListener {
|
||||
// There's still at least one bad tag, so leave the known status as is
|
||||
return;
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to find content", ex);
|
||||
return;
|
||||
}
|
||||
@ -241,6 +242,13 @@ final class CaseEventListener implements PropertyChangeListener {
|
||||
return;
|
||||
}
|
||||
} else { //BLACKBOARD_ARTIFACT_TAG_DELETED
|
||||
Case openCase;
|
||||
try {
|
||||
openCase = Case.getOpenCase();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
|
||||
return;
|
||||
}
|
||||
// For deleted tags, we want to set the file status to UNKNOWN if:
|
||||
// - The tag that was just removed is notable in central repo
|
||||
// - There are no remaining tags that are notable
|
||||
@ -256,9 +264,9 @@ final class CaseEventListener implements PropertyChangeListener {
|
||||
|
||||
try {
|
||||
// Get the remaining tags on the artifact
|
||||
content = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID);
|
||||
bbArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(artifactID);
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
content = openCase.getSleuthkitCase().getContentById(contentID);
|
||||
bbArtifact = openCase.getSleuthkitCase().getBlackboardArtifact(artifactID);
|
||||
TagsManager tagsManager = openCase.getServices().getTagsManager();
|
||||
List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
|
||||
|
||||
if (tags.stream()
|
||||
@ -319,10 +327,10 @@ final class CaseEventListener implements PropertyChangeListener {
|
||||
* that are tagged with the given tag name.
|
||||
*/
|
||||
try {
|
||||
TagName tagName = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(modifiedTagName);
|
||||
TagName tagName = Case.getOpenCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(modifiedTagName);
|
||||
//First update the artifacts
|
||||
//Get all BlackboardArtifactTags with this tag name
|
||||
List<BlackboardArtifactTag> artifactTags = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTagsByTagName(tagName);
|
||||
List<BlackboardArtifactTag> artifactTags = Case.getOpenCase().getSleuthkitCase().getBlackboardArtifactTagsByTagName(tagName);
|
||||
for (BlackboardArtifactTag bbTag : artifactTags) {
|
||||
//start with assumption that none of the other tags applied to this Correlation Attribute will prevent it's status from being changed
|
||||
boolean hasTagWithConflictingKnownStatus = false;
|
||||
@ -338,7 +346,7 @@ final class CaseEventListener implements PropertyChangeListener {
|
||||
}
|
||||
//Get the BlackboardArtifact which this BlackboardArtifactTag has been applied to.
|
||||
BlackboardArtifact bbArtifact = bbTag.getArtifact();
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
TagsManager tagsManager = Case.getOpenCase().getServices().getTagsManager();
|
||||
List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
|
||||
//get all tags which are on this blackboard artifact
|
||||
for (BlackboardArtifactTag t : tags) {
|
||||
@ -366,7 +374,7 @@ final class CaseEventListener implements PropertyChangeListener {
|
||||
}
|
||||
// Next update the files
|
||||
|
||||
List<ContentTag> fileTags = Case.getCurrentCase().getSleuthkitCase().getContentTagsByTagName(tagName);
|
||||
List<ContentTag> fileTags = Case.getOpenCase().getSleuthkitCase().getContentTagsByTagName(tagName);
|
||||
//Get all ContentTags with this tag name
|
||||
for (ContentTag contentTag : fileTags) {
|
||||
//start with assumption that none of the other tags applied to this ContentTag will prevent it's status from being changed
|
||||
@ -376,7 +384,7 @@ final class CaseEventListener implements PropertyChangeListener {
|
||||
// the status of the file in the central repository
|
||||
if (tagName.getKnownStatus() == TskData.FileKnown.UNKNOWN) {
|
||||
Content content = contentTag.getContent();
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
TagsManager tagsManager = Case.getOpenCase().getServices().getTagsManager();
|
||||
List<ContentTag> tags = tagsManager.getContentTagsByContent(content);
|
||||
//get all tags which are on this file
|
||||
for (ContentTag t : tags) {
|
||||
@ -405,6 +413,8 @@ final class CaseEventListener implements PropertyChangeListener {
|
||||
LOGGER.log(Level.SEVERE, "Cannot update known status in central repository for tag: " + modifiedTagName, ex); //NON-NLS
|
||||
} catch (EamDbException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Cannot get central repository for tag: " + modifiedTagName, ex); //NON-NLS
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
|
||||
}
|
||||
} //TAG_STATUS_CHANGED
|
||||
}
|
||||
@ -424,15 +434,22 @@ final class CaseEventListener implements PropertyChangeListener {
|
||||
if (!EamDb.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
Case openCase;
|
||||
try {
|
||||
openCase = Case.getOpenCase();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
final DataSourceAddedEvent dataSourceAddedEvent = (DataSourceAddedEvent) event;
|
||||
Content newDataSource = dataSourceAddedEvent.getDataSource();
|
||||
|
||||
try {
|
||||
String deviceId = Case.getCurrentCase().getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId();
|
||||
CorrelationCase correlationCase = dbManager.getCase(Case.getCurrentCase());
|
||||
String deviceId = openCase.getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId();
|
||||
CorrelationCase correlationCase = dbManager.getCase(openCase);
|
||||
if (null == correlationCase) {
|
||||
correlationCase = dbManager.newCase(Case.getCurrentCase());
|
||||
correlationCase = dbManager.newCase(openCase);
|
||||
}
|
||||
if (null == dbManager.getDataSource(correlationCase, deviceId)) {
|
||||
dbManager.newDataSource(CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource));
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2015-2017 Basis Technology Corp.
|
||||
* Copyright 2015-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -32,6 +32,7 @@ import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
@ -144,9 +145,9 @@ public class IngestEventsListener {
|
||||
tifArtifact.addAttributes(attributes);
|
||||
try {
|
||||
// index the artifact for keyword search
|
||||
Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard();
|
||||
Blackboard blackboard = Case.getOpenCase().getServices().getBlackboard();
|
||||
blackboard.indexArtifact(tifArtifact);
|
||||
} catch (Blackboard.BlackboardException ex) {
|
||||
} catch (Blackboard.BlackboardException | NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -26,6 +26,7 @@ import java.util.stream.Collectors;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
||||
import org.sleuthkit.autopsy.core.RuntimeProperties;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
@ -79,7 +80,12 @@ class IngestModule implements FileIngestModule {
|
||||
return ProcessResult.OK;
|
||||
}
|
||||
|
||||
blackboard = Case.getCurrentCase().getServices().getBlackboard();
|
||||
try {
|
||||
blackboard = Case.getOpenCase().getServices().getBlackboard();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
|
||||
return ProcessResult.ERROR;
|
||||
}
|
||||
|
||||
if (!EamArtifactUtil.isValidCentralRepoFile(af)) {
|
||||
return ProcessResult.OK;
|
||||
@ -190,8 +196,16 @@ class IngestModule implements FileIngestModule {
|
||||
}
|
||||
return;
|
||||
}
|
||||
Case autopsyCase;
|
||||
try {
|
||||
autopsyCase = Case.getOpenCase();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
|
||||
throw new IngestModuleException("Exception while getting open case.", ex);
|
||||
}
|
||||
|
||||
// Don't allow sqlite central repo databases to be used for multi user cases
|
||||
if ((Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE)
|
||||
if ((autopsyCase.getCaseType() == Case.CaseType.MULTI_USER_CASE)
|
||||
&& (EamDbPlatformEnum.getSelectedPlatform() == EamDbPlatformEnum.SQLITE)) {
|
||||
LOGGER.log(Level.SEVERE, "Cannot run correlation engine on a multi-user case with a SQLite central repository.");
|
||||
throw new IngestModuleException("Cannot run on a multi-user case with a SQLite central repository."); // NON-NLS
|
||||
@ -212,7 +226,7 @@ class IngestModule implements FileIngestModule {
|
||||
LOGGER.log(Level.SEVERE, "Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS
|
||||
throw new IngestModuleException("Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS
|
||||
}
|
||||
Case autopsyCase = Case.getCurrentCase();
|
||||
|
||||
try {
|
||||
eamCase = centralRepoDb.getCase(autopsyCase);
|
||||
} catch (EamDbException ex) {
|
||||
|
@ -58,3 +58,10 @@ ManageCorrelationPropertiesDialog.okButton.text=OK
|
||||
GlobalSettingsPanel.bnManageProperties.text=Manage Correlation Properties
|
||||
EamDbSettingsDialog.lbDatabaseDesc.text=Database File:
|
||||
EamDbSettingsDialog.lbFullDbPath.text=
|
||||
GlobalSettingsPanel.cbUseCentralRepo.text=Use a central repository
|
||||
GlobalSettingsPanel.correlationPropertiesTextArea.text=Choose which file and result properties to store in the central repository for later correlation.\n
|
||||
GlobalSettingsPanel.organizationTextArea.text=Organization information can be tracked in the central repository.
|
||||
GlobalSettingsPanel.manageOrganizationButton.text=Manage Organizations
|
||||
GlobalSettingsPanel.lbCentralRepository.text=A central repository allows you to correlate files and results between cases.
|
||||
GlobalSettingsPanel.pnCorrelationProperties.border.title=Correlation Properties
|
||||
GlobalSettingsPanel.organizationPanel.border.title=Organizations
|
||||
|
@ -3,6 +3,9 @@
|
||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<Properties>
|
||||
<Property name="name" type="java.lang.String" value="" noResource="true"/>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[1022, 488]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||
@ -19,44 +22,98 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="tbOops" alignment="1" max="32767" attributes="0"/>
|
||||
<Component id="jScrollPane1" alignment="0" pref="488" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="null"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[1022, 407]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="jPanel1">
|
||||
<Properties>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 0]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[1020, 407]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="lbCentralRepository" max="32767" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="cbUseCentralRepo" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="tbOops" min="-2" pref="974" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="36" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Component id="organizationPanel" alignment="0" pref="0" max="32767" attributes="0"/>
|
||||
<Component id="lbCentralRepository" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="pnCorrelationProperties" alignment="0" pref="349" max="32767" attributes="0"/>
|
||||
<Component id="pnDatabaseConfiguration" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="cbUseCentralRepo" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="pnCorrelationProperties" alignment="0" pref="1012" max="32767" attributes="0"/>
|
||||
<Component id="organizationPanel" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="lbCentralRepository" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="cbUseCentralRepo" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="pnDatabaseConfiguration" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="pnCorrelationProperties" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="organizationPanel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="tbOops" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="pnCorrelationProperties" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="organizationPanel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="tbOops" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="92" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="lbCentralRepository">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.lbCentralRepository.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="cbUseCentralRepo">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.cbUseCentralRepo.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="cbUseCentralRepoActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="pnDatabaseConfiguration">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
@ -161,37 +218,11 @@
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="javax.swing.JCheckBox" name="cbUseCentralRepo">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.cbUseCentralRepo.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="cbUseCentralRepoActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tbOops">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
|
||||
<FontInfo relative="true">
|
||||
<Font bold="true" component="tbOops" property="font" relativeSize="false" size="12"/>
|
||||
</FontInfo>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.tbOops.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="null"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="pnCorrelationProperties">
|
||||
<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="<GlobalSettingsPanel.pnCorrelationProperties.border.title>">
|
||||
<TitledBorder title="Correlation Properties">
|
||||
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.pnCorrelationProperties.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<Font PropertyName="font" name="Tahoma" size="12" style="0"/>
|
||||
</TitledBorder>
|
||||
@ -279,18 +310,11 @@
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="javax.swing.JLabel" name="lbCentralRepository">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.lbCentralRepository.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="organizationPanel">
|
||||
<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="<GlobalSettingsPanel.organizationPanel.border.title>">
|
||||
<TitledBorder title="Organizations">
|
||||
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.organizationPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<Font PropertyName="font" name="Tahoma" size="12" style="0"/>
|
||||
</TitledBorder>
|
||||
@ -374,5 +398,25 @@
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="javax.swing.JTextField" name="tbOops">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
|
||||
<FontInfo relative="true">
|
||||
<Font bold="true" component="tbOops" property="font" relativeSize="false" size="12"/>
|
||||
</FontInfo>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.tbOops.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="null"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
@ -58,22 +58,8 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
addIngestJobEventsListener();
|
||||
}
|
||||
|
||||
@Messages({"GlobalSettingsPanel.title=Central Repository Settings",
|
||||
"GlobalSettingsPanel.cbUseCentralRepo.text=Use a central repository",
|
||||
"GlobalSettingsPanel.pnTagManagement.border.title=Tags",
|
||||
"GlobalSettingsPanel.pnCorrelationProperties.border.title=Correlation Properties",
|
||||
"GlobalSettingsPanel.lbCentralRepository.text=A central repository allows you to correlate files and results between cases.",
|
||||
"GlobalSettingsPanel.manageTagsTextArea.text=Configure which tag names are associated with notable items. "
|
||||
+ "When these tags are used, the file or result will be recorded in the central repository. "
|
||||
+ "If that file or result is seen again in future cases, it will be flagged.",
|
||||
"GlobalSettingsPanel.correlationPropertiesTextArea.text=Choose which file and result properties to store in the central repository for later correlation.",
|
||||
"GlobalSettingsPanel.organizationPanel.border.title=Organizations",
|
||||
"GlobalSettingsPanel.manageOrganizationButton.text=Manage Organizations",
|
||||
"GlobalSettingsPanel.organizationTextArea.text=Organization information can be tracked in the central repository"
|
||||
})
|
||||
|
||||
private void customizeComponents() {
|
||||
setName(Bundle.GlobalSettingsPanel_title());
|
||||
setName(NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnCorrelationProperties.border.title"));
|
||||
}
|
||||
|
||||
private void addIngestJobEventsListener() {
|
||||
@ -116,6 +102,10 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
jScrollPane1 = new javax.swing.JScrollPane();
|
||||
jPanel1 = new javax.swing.JPanel();
|
||||
lbCentralRepository = new javax.swing.JLabel();
|
||||
cbUseCentralRepo = new javax.swing.JCheckBox();
|
||||
pnDatabaseConfiguration = new javax.swing.JPanel();
|
||||
lbDbPlatformTypeLabel = new javax.swing.JLabel();
|
||||
lbDbNameLabel = new javax.swing.JLabel();
|
||||
@ -124,19 +114,33 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
lbDbPlatformValue = new javax.swing.JLabel();
|
||||
lbDbNameValue = new javax.swing.JLabel();
|
||||
lbDbLocationValue = new javax.swing.JLabel();
|
||||
cbUseCentralRepo = new javax.swing.JCheckBox();
|
||||
tbOops = new javax.swing.JTextField();
|
||||
pnCorrelationProperties = new javax.swing.JPanel();
|
||||
bnManageTypes = new javax.swing.JButton();
|
||||
correlationPropertiesScrollPane = new javax.swing.JScrollPane();
|
||||
correlationPropertiesTextArea = new javax.swing.JTextArea();
|
||||
lbCentralRepository = new javax.swing.JLabel();
|
||||
organizationPanel = new javax.swing.JPanel();
|
||||
manageOrganizationButton = new javax.swing.JButton();
|
||||
organizationScrollPane = new javax.swing.JScrollPane();
|
||||
organizationTextArea = new javax.swing.JTextArea();
|
||||
tbOops = new javax.swing.JTextField();
|
||||
|
||||
setName(""); // NOI18N
|
||||
setPreferredSize(new java.awt.Dimension(1022, 488));
|
||||
|
||||
jScrollPane1.setBorder(null);
|
||||
jScrollPane1.setPreferredSize(new java.awt.Dimension(1022, 407));
|
||||
|
||||
jPanel1.setMinimumSize(new java.awt.Dimension(0, 0));
|
||||
jPanel1.setPreferredSize(new java.awt.Dimension(1020, 407));
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(lbCentralRepository, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.lbCentralRepository.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(cbUseCentralRepo, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.cbUseCentralRepo.text")); // NOI18N
|
||||
cbUseCentralRepo.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
cbUseCentralRepoActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
pnDatabaseConfiguration.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnDatabaseConfiguration.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N
|
||||
|
||||
@ -194,18 +198,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
.addGap(8, 8, 8))
|
||||
);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(cbUseCentralRepo, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.cbUseCentralRepo.text")); // NOI18N
|
||||
cbUseCentralRepo.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
cbUseCentralRepoActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
tbOops.setEditable(false);
|
||||
tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12));
|
||||
tbOops.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.tbOops.text")); // NOI18N
|
||||
tbOops.setBorder(null);
|
||||
|
||||
pnCorrelationProperties.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnCorrelationProperties.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N
|
||||
pnCorrelationProperties.setPreferredSize(new java.awt.Dimension(674, 93));
|
||||
|
||||
@ -253,8 +245,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
.addGap(8, 8, 8))
|
||||
);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(lbCentralRepository, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.lbCentralRepository.text")); // NOI18N
|
||||
|
||||
organizationPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.organizationPanel.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(manageOrganizationButton, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.manageOrganizationButton.text")); // NOI18N
|
||||
@ -300,38 +290,58 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
.addGap(8, 8, 8))
|
||||
);
|
||||
|
||||
tbOops.setEditable(false);
|
||||
tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12));
|
||||
tbOops.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.tbOops.text")); // NOI18N
|
||||
tbOops.setBorder(null);
|
||||
|
||||
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
|
||||
jPanel1.setLayout(jPanel1Layout);
|
||||
jPanel1Layout.setHorizontalGroup(
|
||||
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(lbCentralRepository, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addComponent(cbUseCentralRepo)
|
||||
.addGap(0, 0, Short.MAX_VALUE))
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 974, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(36, Short.MAX_VALUE))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(pnCorrelationProperties, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 1012, Short.MAX_VALUE)
|
||||
.addComponent(organizationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addContainerGap())
|
||||
);
|
||||
jPanel1Layout.setVerticalGroup(
|
||||
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addComponent(lbCentralRepository)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(cbUseCentralRepo)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(pnCorrelationProperties, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(organizationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 92, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
jScrollPane1.setViewportView(jPanel1);
|
||||
|
||||
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(tbOops, javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(organizationPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
|
||||
.addComponent(lbCentralRepository, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(pnCorrelationProperties, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 349, Short.MAX_VALUE)
|
||||
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(cbUseCentralRepo, javax.swing.GroupLayout.Alignment.LEADING))
|
||||
.addContainerGap())))
|
||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addComponent(lbCentralRepository)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(cbUseCentralRepo)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(pnCorrelationProperties, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(organizationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap())
|
||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 488, Short.MAX_VALUE)
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
@ -523,6 +533,8 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
private javax.swing.JCheckBox cbUseCentralRepo;
|
||||
private javax.swing.JScrollPane correlationPropertiesScrollPane;
|
||||
private javax.swing.JTextArea correlationPropertiesTextArea;
|
||||
private javax.swing.JPanel jPanel1;
|
||||
private javax.swing.JScrollPane jScrollPane1;
|
||||
private javax.swing.JLabel lbCentralRepository;
|
||||
private javax.swing.JLabel lbDbLocationLabel;
|
||||
private javax.swing.JLabel lbDbLocationValue;
|
||||
|
@ -25,6 +25,7 @@ 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;
|
||||
@ -38,12 +39,16 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
* relationships of all the accounts in this node.
|
||||
*
|
||||
*/
|
||||
class AccountDetailsNode extends AbstractNode {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017 Basis Technology Corp.
|
||||
* Copyright 2017-18 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,23 +18,31 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Key for AccountDeviceInstance node.
|
||||
*
|
||||
* Encapsulates a AccountDeviceInstance, and CommunicationsFilter.
|
||||
* Encapsulates a AccountDeviceInstanc,some meta data about it, and
|
||||
* CommunicationsFilter.
|
||||
*/
|
||||
class AccountDeviceInstanceKey {
|
||||
final class AccountDeviceInstanceKey {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AccountDeviceInstanceKey.class.getName());
|
||||
|
||||
private final AccountDeviceInstance accountDeviceInstance;
|
||||
private final CommunicationsFilter filter;
|
||||
private final long messageCount;
|
||||
private final String dataSourceName;
|
||||
|
||||
|
||||
|
||||
AccountDeviceInstanceKey(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter, long msgCount, String dataSourceName) {
|
||||
this.accountDeviceInstance = accountDeviceInstance;
|
||||
this.filter = filter;
|
||||
@ -42,6 +50,13 @@ class AccountDeviceInstanceKey {
|
||||
this.dataSourceName = dataSourceName;
|
||||
}
|
||||
|
||||
AccountDeviceInstanceKey(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter, long msgCount) {
|
||||
this.accountDeviceInstance = accountDeviceInstance;
|
||||
this.filter = filter;
|
||||
this.messageCount = msgCount;
|
||||
this.dataSourceName = getDataSourceName(accountDeviceInstance, Case.getCurrentCase().getSleuthkitCase());
|
||||
}
|
||||
|
||||
AccountDeviceInstance getAccountDeviceInstance() {
|
||||
return accountDeviceInstance;
|
||||
}
|
||||
@ -57,4 +72,52 @@ class AccountDeviceInstanceKey {
|
||||
String getDataSourceName() {
|
||||
return dataSourceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return accountDeviceInstance.getAccount().getTypeSpecificID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
hash = 37 * hash + Objects.hashCode(this.accountDeviceInstance);
|
||||
hash = 37 * hash + (int) (this.messageCount ^ (this.messageCount >>> 32));
|
||||
hash = 37 * hash + Objects.hashCode(this.dataSourceName);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final AccountDeviceInstanceKey other = (AccountDeviceInstanceKey) obj;
|
||||
if (this.messageCount != other.messageCount) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.dataSourceName, other.dataSourceName)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(this.accountDeviceInstance, other.accountDeviceInstance);
|
||||
}
|
||||
|
||||
private static String getDataSourceName(AccountDeviceInstance accountDeviceInstance, SleuthkitCase db) {
|
||||
try {
|
||||
for (DataSource dataSource : db.getDataSources()) {
|
||||
if (dataSource.getDeviceId().equals(accountDeviceInstance.getDeviceId())) {
|
||||
return db.getContentById(dataSource.getId()).getName();
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting datasource name, falling back on device ID.", ex);
|
||||
}
|
||||
return accountDeviceInstance.getDeviceId();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017-18 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.Utilities;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
|
||||
/**
|
||||
* Node to represent an Account Device Instance in the CVT
|
||||
*/
|
||||
final class AccountDeviceInstanceNode extends AbstractNode {
|
||||
|
||||
private final AccountDeviceInstanceKey accountDeviceInstanceKey;
|
||||
private final CommunicationsManager commsManager;
|
||||
private final Account account;
|
||||
|
||||
AccountDeviceInstanceNode(AccountDeviceInstanceKey accountDeviceInstanceKey, CommunicationsManager commsManager) {
|
||||
super(Children.LEAF, Lookups.fixed(accountDeviceInstanceKey, commsManager));
|
||||
this.accountDeviceInstanceKey = accountDeviceInstanceKey;
|
||||
this.commsManager = commsManager;
|
||||
this.account = accountDeviceInstanceKey.getAccountDeviceInstance().getAccount();
|
||||
setName(account.getTypeSpecificID());
|
||||
setDisplayName(getName());
|
||||
setIconBaseWithExtension(Utils.getIconFilePath(account.getAccountType()));
|
||||
}
|
||||
|
||||
AccountDeviceInstance getAccountDeviceInstance() {
|
||||
return accountDeviceInstanceKey.getAccountDeviceInstance();
|
||||
}
|
||||
|
||||
AccountDeviceInstanceKey getAccountDeviceInstanceKey() {
|
||||
return accountDeviceInstanceKey;
|
||||
}
|
||||
|
||||
CommunicationsManager getCommsManager() {
|
||||
return commsManager;
|
||||
}
|
||||
|
||||
long getMessageCount() {
|
||||
return accountDeviceInstanceKey.getMessageCount();
|
||||
}
|
||||
|
||||
CommunicationsFilter getFilter() {
|
||||
return accountDeviceInstanceKey.getCommunicationsFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NbBundle.Messages(value = {"AccountNode.device=Device", "AccountNode.accountName=Account", "AccountNode.accountType=Type", "AccountNode.messageCount=Msgs"})
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
Sheet.Set properties = s.get(Sheet.PROPERTIES);
|
||||
if (properties == null) {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
s.put(properties);
|
||||
}
|
||||
properties.put(new NodeProperty<>("type",
|
||||
Bundle.AccountNode_accountType(),
|
||||
"type",
|
||||
account.getAccountType().getDisplayName())); // NON-NLS
|
||||
properties.put(new NodeProperty<>("count",
|
||||
Bundle.AccountNode_messageCount(),
|
||||
"count",
|
||||
accountDeviceInstanceKey.getMessageCount())); // NON-NLS
|
||||
properties.put(new NodeProperty<>("device",
|
||||
Bundle.AccountNode_device(),
|
||||
"device",
|
||||
accountDeviceInstanceKey.getDataSourceName())); // NON-NLS
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action[] getActions(boolean context) {
|
||||
ArrayList<Action> actions = new ArrayList<>(Arrays.asList(super.getActions(context)));
|
||||
actions.add(PinAccountsAction.getInstance());
|
||||
actions.add(ResetAndPinAccountsAction.getInstance());
|
||||
return actions.toArray(new Action[actions.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action that pins the selected AccountDeviceInstances to the
|
||||
* visualization.
|
||||
*/
|
||||
static private class PinAccountsAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final static PinAccountsAction instance = new PinAccountsAction();
|
||||
|
||||
private static PinAccountsAction getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private PinAccountsAction() {
|
||||
super("Add Account(s) to Visualization");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Collection<? extends AccountDeviceInstanceKey> lookupAll =
|
||||
Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstanceKey.class);
|
||||
CVTEvents.getCVTEventBus().post(new CVTEvents.PinAccountsEvent(lookupAll, false));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action that pins the selected AccountDeviceInstances to the
|
||||
* visualization.
|
||||
*/
|
||||
static private class ResetAndPinAccountsAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final static ResetAndPinAccountsAction instance = new ResetAndPinAccountsAction();
|
||||
|
||||
private static ResetAndPinAccountsAction getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private ResetAndPinAccountsAction() {
|
||||
super("Visualize Account(s)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Collection<? extends AccountDeviceInstanceKey> lookupAll =
|
||||
Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstanceKey.class);
|
||||
CVTEvents.getCVTEventBus().post(new CVTEvents.PinAccountsEvent(lookupAll, true));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017-18 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* ChildFactory that creates AccountDeviceInstanceKeys and
|
||||
* AccountDeviceInstanceNodes using a provided CommunicationsManager and
|
||||
* CommunicationsFilter
|
||||
*/
|
||||
final class AccountDeviceInstanceNodeFactory extends ChildFactory<AccountDeviceInstanceKey> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AccountDeviceInstanceNodeFactory.class.getName());
|
||||
|
||||
private final CommunicationsManager commsManager;
|
||||
private final CommunicationsFilter commsFilter;
|
||||
|
||||
AccountDeviceInstanceNodeFactory(CommunicationsManager commsManager, CommunicationsFilter commsFilter) {
|
||||
this.commsManager = commsManager;
|
||||
this.commsFilter = commsFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<AccountDeviceInstanceKey> list) {
|
||||
List<AccountDeviceInstanceKey> accountDeviceInstanceKeys = new ArrayList<>();
|
||||
try {
|
||||
final List<AccountDeviceInstance> accountDeviceInstancesWithRelationships =
|
||||
commsManager.getAccountDeviceInstancesWithRelationships(commsFilter);
|
||||
for (AccountDeviceInstance accountDeviceInstance : accountDeviceInstancesWithRelationships) {
|
||||
//Filter out device accounts, in the table.
|
||||
if (Account.Type.DEVICE.equals(accountDeviceInstance.getAccount().getAccountType()) ==false) {
|
||||
long communicationsCount = commsManager.getRelationshipSourcesCount(accountDeviceInstance, commsFilter);
|
||||
accountDeviceInstanceKeys.add(new AccountDeviceInstanceKey(accountDeviceInstance, commsFilter, communicationsCount));
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.SEVERE, "Error getting filtered account device instances", tskCoreException);
|
||||
}
|
||||
list.addAll(accountDeviceInstanceKeys);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(AccountDeviceInstanceKey key) {
|
||||
return new AccountDeviceInstanceNode(key, commsManager);
|
||||
}
|
||||
}
|
@ -11,30 +11,28 @@
|
||||
<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,-76,0,0,2,68"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="outlineView" pref="400" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="outlineView" pref="300" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JSplitPane" name="jSplitPane1">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="Center"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="org.openide.explorer.view.OutlineView" name="outlineView">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||
<JSplitPaneConstraints position="left"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017 Basis Technology Corp.
|
||||
* Copyright 2017-18 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,7 +18,9 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.awt.Component;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.SwingUtilities;
|
||||
@ -26,21 +28,41 @@ import javax.swing.table.TableCellRenderer;
|
||||
import org.netbeans.swing.outline.DefaultOutlineModel;
|
||||
import org.netbeans.swing.outline.Outline;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.explorer.ExplorerUtils;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.lookup.ProxyLookup;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* A panel that goes in the Browse tab of the Communications Visualization Tool.
|
||||
* Hosts an OutlineView that shows information about Accounts.
|
||||
* Hosts an OutlineView that shows information about Accounts, and a
|
||||
* MessageBrowser for viewing details of communications.
|
||||
*
|
||||
* The Lookup provided by getLookup will be proxied by the lookup of the
|
||||
* CVTTopComponent when this tab is active allowing for context sensitive
|
||||
* actions to work correctly.
|
||||
*/
|
||||
public class AccountsBrowser extends JPanel {
|
||||
public final class AccountsBrowser extends JPanel implements ExplorerManager.Provider, Lookup.Provider {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger logger = Logger.getLogger(AccountsBrowser.class.getName());
|
||||
|
||||
private final Outline outline;
|
||||
private ExplorerManager em;
|
||||
|
||||
/**
|
||||
* Creates new form AccountsBrowser
|
||||
private final ExplorerManager messageBrowserEM = new ExplorerManager();
|
||||
private final ExplorerManager accountsTableEM = new ExplorerManager();
|
||||
|
||||
/*
|
||||
* This lookup proxies the selection lookup of both he accounts table and
|
||||
* the messages table.
|
||||
*/
|
||||
private final ProxyLookup proxyLookup;
|
||||
|
||||
public AccountsBrowser() {
|
||||
initComponents();
|
||||
outline = outlineView.getOutline();
|
||||
@ -54,19 +76,21 @@ public class AccountsBrowser extends JPanel {
|
||||
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AccountNode_accountName());
|
||||
outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||
outline.setColumnSorted(3, false, 1); //it would be nice if the column index wasn't hardcoded
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
em = ExplorerManager.find(this);
|
||||
em.addPropertyChangeListener(evt -> {
|
||||
accountsTableEM.addPropertyChangeListener(evt -> {
|
||||
if (ExplorerManager.PROP_ROOT_CONTEXT.equals(evt.getPropertyName())) {
|
||||
SwingUtilities.invokeLater(this::setColumnWidths);
|
||||
} else if (ExplorerManager.PROP_EXPLORED_CONTEXT.equals(evt.getPropertyName())) {
|
||||
SwingUtilities.invokeLater(this::setColumnWidths);
|
||||
}
|
||||
});
|
||||
final MessageBrowser messageBrowser = new MessageBrowser(accountsTableEM, messageBrowserEM);
|
||||
|
||||
jSplitPane1.setRightComponent(messageBrowser);
|
||||
|
||||
proxyLookup = new ProxyLookup(
|
||||
messageBrowser.getLookup(),
|
||||
ExplorerUtils.createLookup(accountsTableEM, getActionMap()));
|
||||
}
|
||||
|
||||
private void setColumnWidths() {
|
||||
@ -93,6 +117,16 @@ public class AccountsBrowser extends JPanel {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void handleFilterEvent(CVTEvents.FilterChangeEvent filterChangeEvent) {
|
||||
try {
|
||||
final CommunicationsManager commsManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
|
||||
accountsTableEM.setRootContext(new AbstractNode(Children.create(new AccountDeviceInstanceNodeFactory(commsManager, filterChangeEvent.getNewFilter()), true)));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "There was an error getting the CommunicationsManager for the current case.", 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
|
||||
@ -102,28 +136,29 @@ public class AccountsBrowser extends JPanel {
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
jSplitPane1 = new javax.swing.JSplitPane();
|
||||
outlineView = new org.openide.explorer.view.OutlineView();
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
|
||||
.addGap(0, 0, 0))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
|
||||
.addGap(0, 0, 0))
|
||||
);
|
||||
setLayout(new java.awt.BorderLayout());
|
||||
|
||||
jSplitPane1.setLeftComponent(outlineView);
|
||||
|
||||
add(jSplitPane1, java.awt.BorderLayout.CENTER);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JSplitPane jSplitPane1;
|
||||
private org.openide.explorer.view.OutlineView outlineView;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
@Override
|
||||
public ExplorerManager getExplorerManager() {
|
||||
return accountsTableEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lookup getLookup() {
|
||||
return proxyLookup;
|
||||
}
|
||||
}
|
||||
|
@ -1,143 +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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
class AccountsRootChildren extends ChildFactory<AccountDeviceInstanceKey> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AccountsRootChildren.class.getName());
|
||||
|
||||
private final CommunicationsManager commsManager;
|
||||
private final CommunicationsFilter commsFilter;
|
||||
|
||||
AccountsRootChildren(CommunicationsManager commsManager, CommunicationsFilter commsFilter) {
|
||||
super();
|
||||
this.commsManager = commsManager;
|
||||
this.commsFilter = commsFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<AccountDeviceInstanceKey> list) {
|
||||
List<AccountDeviceInstanceKey> accountDeviceInstanceKeys = new ArrayList<>();
|
||||
try {
|
||||
for (AccountDeviceInstance accountDeviceInstance : commsManager.getAccountDeviceInstancesWithRelationships(commsFilter)) {
|
||||
long communicationsCount = commsManager.getRelationshipSourcesCount(accountDeviceInstance, commsFilter);
|
||||
String dataSourceName = getDataSourceName(accountDeviceInstance);
|
||||
accountDeviceInstanceKeys.add(new AccountDeviceInstanceKey(accountDeviceInstance, commsFilter, communicationsCount, dataSourceName));
|
||||
};
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.SEVERE, "Error getting filtered account device instances", tskCoreException);
|
||||
}
|
||||
list.addAll(accountDeviceInstanceKeys);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(AccountDeviceInstanceKey key) {
|
||||
return new AccountDeviceInstanceNode(key, commsManager);
|
||||
}
|
||||
|
||||
private String getDataSourceName(AccountDeviceInstance accountDeviceInstance) {
|
||||
try {
|
||||
final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase();
|
||||
for (DataSource dataSource : sleuthkitCase.getDataSources()) {
|
||||
if (dataSource.getDeviceId().equals(accountDeviceInstance.getDeviceId())) {
|
||||
return sleuthkitCase.getContentById(dataSource.getId()).getName();
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting datasource name, falling back on device ID.", ex);
|
||||
}
|
||||
return accountDeviceInstance.getDeviceId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Node to represent an Account in the AccountsBrowser
|
||||
*/
|
||||
static class AccountDeviceInstanceNode extends AbstractNode {
|
||||
|
||||
private final AccountDeviceInstanceKey accountDeviceInstanceKey;
|
||||
private final CommunicationsManager commsManager;
|
||||
private final Account account;
|
||||
|
||||
private AccountDeviceInstanceNode(AccountDeviceInstanceKey accountDeviceInstanceKey, CommunicationsManager commsManager) {
|
||||
super(Children.LEAF, Lookups.fixed(accountDeviceInstanceKey, commsManager));
|
||||
this.accountDeviceInstanceKey = accountDeviceInstanceKey;
|
||||
this.commsManager = commsManager;
|
||||
this.account = accountDeviceInstanceKey.getAccountDeviceInstance().getAccount();
|
||||
setName(account.getTypeSpecificID());
|
||||
setIconBaseWithExtension("org/sleuthkit/autopsy/communications/images/" + Utils.getIconFileName(account.getAccountType()));
|
||||
}
|
||||
|
||||
public AccountDeviceInstance getAccountDeviceInstance() {
|
||||
return accountDeviceInstanceKey.getAccountDeviceInstance();
|
||||
}
|
||||
|
||||
public CommunicationsManager getCommsManager() {
|
||||
return commsManager;
|
||||
}
|
||||
|
||||
public CommunicationsFilter getFilter() {
|
||||
return accountDeviceInstanceKey.getCommunicationsFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NbBundle.Messages(value = {"AccountNode.device=Device",
|
||||
"AccountNode.accountName=Account",
|
||||
"AccountNode.accountType=Type",
|
||||
"AccountNode.messageCount=Msgs"})
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
Sheet.Set properties = s.get(Sheet.PROPERTIES);
|
||||
if (properties == null) {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
s.put(properties);
|
||||
}
|
||||
|
||||
properties.put(new NodeProperty<>("type", Bundle.AccountNode_accountType(), "type",
|
||||
account.getAccountType().getDisplayName())); // NON-NLS
|
||||
properties.put(new NodeProperty<>("count", Bundle.AccountNode_messageCount(), "count",
|
||||
accountDeviceInstanceKey.getMessageCount())); // NON-NLS
|
||||
properties.put(new NodeProperty<>("device", Bundle.AccountNode_device(), "device",
|
||||
accountDeviceInstanceKey.getDataSourceName())); // NON-NLS
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
@ -15,3 +15,31 @@ FiltersPanel.refreshButton.text=Refresh
|
||||
FiltersPanel.deviceRequiredLabel.text=Select at least one.
|
||||
FiltersPanel.accountTypeRequiredLabel.text=Select at least one.
|
||||
FiltersPanel.needsRefreshLabel.text=Displayed data is out of date. Press Refresh.
|
||||
VisualizationPanel.jButton1.text=Fast Organic
|
||||
CVTTopComponent.vizPanel.TabConstraints.tabTitle=Visualize
|
||||
CVTTopComponent.accountsBrowser.TabConstraints.tabTitle_1=Browse
|
||||
CVTTopComponent.browseVisualizeTabPane.AccessibleContext.accessibleName=Visualize
|
||||
CVTTopComponent.vizPanel.TabConstraints.tabTitle_1=Visualize
|
||||
VisualizationPanel.jButton6.text=Hierarchy
|
||||
VisualizationPanel.jButton7.text=Circle
|
||||
VisualizationPanel.jButton8.text=Organic
|
||||
VisualizationPanel.fitGraphButton.text=
|
||||
VisualizationPanel.zoomOutButton.text=
|
||||
# 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.
|
||||
VisualizationPanel.circleLayoutButton.text=Circle
|
||||
VisualizationPanel.organicLayoutButton.text=Organic
|
||||
VisualizationPanel.fastOrganicLayoutButton.text=Fast Organic
|
||||
VisualizationPanel.hierarchyLayoutButton.text=Hierarchy
|
||||
VisualizationPanel.zoomLabel.text=100%
|
||||
VisualizationPanel.jLabel1.text=Layouts:
|
||||
VisualizationPanel.jLabel2.text=Zoom:
|
||||
VisualizationPanel.fitZoomButton.toolTipText=fit visualization
|
||||
VisualizationPanel.fitZoomButton.text=
|
||||
VisualizationPanel.jTextArea1.text=Right-click an account in the Browse Accounts table, and select 'Visualize' to begin.
|
||||
VisualizationPanel.zoomActualButton.toolTipText=reset zoom
|
||||
VisualizationPanel.zoomActualButton.text=
|
||||
VisualizationPanel.zoomInButton.toolTipText=Zoom in
|
||||
VisualizationPanel.zoomInButton.text=
|
||||
VisualizationPanel.zoomOutButton.toolTipText=Zoom out
|
||||
|
86
Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017-18 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
|
||||
/**
|
||||
* Provide the singleton EventBus.
|
||||
*/
|
||||
final class CVTEvents {
|
||||
|
||||
private final static EventBus cvtEventBus = new EventBus();
|
||||
|
||||
static EventBus getCVTEventBus() {
|
||||
return cvtEventBus;
|
||||
}
|
||||
|
||||
private CVTEvents() {
|
||||
}
|
||||
|
||||
static final class FilterChangeEvent {
|
||||
|
||||
private final CommunicationsFilter newFilter;
|
||||
|
||||
CommunicationsFilter getNewFilter() {
|
||||
return newFilter;
|
||||
}
|
||||
|
||||
FilterChangeEvent(CommunicationsFilter newFilter) {
|
||||
this.newFilter = newFilter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class PinAccountsEvent {
|
||||
|
||||
private final ImmutableSet<AccountDeviceInstanceKey> accountDeviceInstances;
|
||||
private final boolean replace;
|
||||
|
||||
public boolean isReplace() {
|
||||
return replace;
|
||||
}
|
||||
|
||||
ImmutableSet<AccountDeviceInstanceKey> getAccountDeviceInstances() {
|
||||
return accountDeviceInstances;
|
||||
}
|
||||
|
||||
PinAccountsEvent(Collection<? extends AccountDeviceInstanceKey> accountDeviceInstances, boolean replace) {
|
||||
this.accountDeviceInstances = ImmutableSet.copyOf(accountDeviceInstances);
|
||||
this.replace = replace;
|
||||
}
|
||||
}
|
||||
|
||||
static final class UnpinAccountsEvent {
|
||||
|
||||
private final ImmutableSet<AccountDeviceInstanceKey> accountDeviceInstances;
|
||||
|
||||
public ImmutableSet<AccountDeviceInstanceKey> getAccountDeviceInstances() {
|
||||
return accountDeviceInstances;
|
||||
}
|
||||
|
||||
public UnpinAccountsEvent(Set<AccountDeviceInstanceKey> accountDeviceInstances) {
|
||||
this.accountDeviceInstances = ImmutableSet.copyOf(accountDeviceInstances);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
<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_generateFQN" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
@ -18,10 +18,10 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||
<Component id="filtersPane" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="splitPane" pref="1277" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="filtersPane" min="-2" pref="265" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
<Component id="browseVisualizeTabPane" pref="786" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@ -29,23 +29,16 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="filtersPane" max="32767" attributes="0"/>
|
||||
<Component id="splitPane" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="browseVisualizeTabPane" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JSplitPane" name="splitPane">
|
||||
<Properties>
|
||||
<Property name="dividerLocation" type="int" value="400"/>
|
||||
<Property name="resizeWeight" type="double" value="0.7"/>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JTabbedPane" name="browseVisualizeTabPane">
|
||||
<Properties>
|
||||
@ -53,11 +46,11 @@
|
||||
<Font name="Tahoma" size="18" style="0"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||
<JSplitPaneConstraints position="left"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
<AccessibilityProperties>
|
||||
<Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="CVTTopComponent.browseVisualizeTabPane.AccessibleContext.accessibleName" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</AccessibilityProperties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
@ -66,7 +59,7 @@
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
|
||||
<JTabbedPaneConstraints tabName="Browse">
|
||||
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="CVTTopComponent.accountsBrowser.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="CVTTopComponent.accountsBrowser.TabConstraints.tabTitle_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="tabIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/table.png"/>
|
||||
@ -75,8 +68,20 @@
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="org.sleuthkit.autopsy.communications.VisualizationPanel" name="vizPanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
|
||||
<JTabbedPaneConstraints tabName="Visualize">
|
||||
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="CVTTopComponent.vizPanel.TabConstraints.tabTitle_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="tabIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/emblem-web.png"/>
|
||||
</Property>
|
||||
</JTabbedPaneConstraints>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="org.sleuthkit.autopsy.communications.FiltersPanel" name="filtersPane">
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017 Basis Technology Corp.
|
||||
* Copyright 2017-18 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,10 +18,16 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.explorer.ExplorerUtils;
|
||||
import javax.swing.GroupLayout;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.LayoutStyle;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.windows.Mode;
|
||||
import org.openide.windows.RetainLocation;
|
||||
@ -36,33 +42,42 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||
@TopComponent.Registration(mode = "cvt", openAtStartup = false)
|
||||
@RetainLocation("cvt")
|
||||
@NbBundle.Messages("CVTTopComponent.name= Communications Visualization")
|
||||
public final class CVTTopComponent extends TopComponent implements ExplorerManager.Provider {
|
||||
public final class CVTTopComponent extends TopComponent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final ExplorerManager messagesBrowserExplorerManager;
|
||||
private final ExplorerManager acctsBrowserExplorerManager;
|
||||
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
public CVTTopComponent() {
|
||||
initComponents();
|
||||
setName(Bundle.CVTTopComponent_name());
|
||||
/*
|
||||
* Associate an explorer manager with the GlobalActionContext (GAC) for
|
||||
* use by the messages browser so that selections in the messages
|
||||
* browser can be exposed to context-sensitive actions.
|
||||
*/
|
||||
messagesBrowserExplorerManager = new ExplorerManager();
|
||||
associateLookup(ExplorerUtils.createLookup(messagesBrowserExplorerManager, getActionMap()));
|
||||
splitPane.setRightComponent(new MessageBrowser(messagesBrowserExplorerManager));
|
||||
|
||||
/*
|
||||
* Create a second explorer manager to be discovered by the accounts
|
||||
* browser and the message browser so that the browsers can both listen
|
||||
* for explorer manager property events for the outline view of the
|
||||
* accounts browser. This provides a mechanism for pushing selected
|
||||
* Nodes from the accounts browser to the messages browser.
|
||||
* Associate a Lookup with the GlobalActionContext (GAC) so that
|
||||
* selections in the sub views can be exposed to context-sensitive
|
||||
* actions.
|
||||
*/
|
||||
acctsBrowserExplorerManager = new ExplorerManager();
|
||||
final ModifiableProxyLookup proxyLookup = new ModifiableProxyLookup(accountsBrowser.getLookup());
|
||||
associateLookup(proxyLookup);
|
||||
// Make sure the Global Actions Context is proxying the selection of the active tab.
|
||||
browseVisualizeTabPane.addChangeListener(changeEvent -> {
|
||||
Lookup.Provider selectedComponent = (Lookup.Provider) browseVisualizeTabPane.getSelectedComponent();
|
||||
proxyLookup.setNewLookups(selectedComponent.getLookup());
|
||||
filtersPane.setDeviceAccountTypeEnabled(browseVisualizeTabPane.getSelectedIndex() != 0);
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
* Connect the filtersPane to the accountsBrowser and visualizaionPanel
|
||||
* via an Eventbus
|
||||
*/
|
||||
CVTEvents.getCVTEventBus().register(this);
|
||||
CVTEvents.getCVTEventBus().register(vizPanel);
|
||||
CVTEvents.getCVTEventBus().register(accountsBrowser);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
void pinAccount(CVTEvents.PinAccountsEvent pinEvent) {
|
||||
browseVisualizeTabPane.setSelectedIndex(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,49 +88,46 @@ public final class CVTTopComponent extends TopComponent implements ExplorerManag
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
splitPane = new javax.swing.JSplitPane();
|
||||
browseVisualizeTabPane = new javax.swing.JTabbedPane();
|
||||
accountsBrowser = new org.sleuthkit.autopsy.communications.AccountsBrowser();
|
||||
filtersPane = new org.sleuthkit.autopsy.communications.FiltersPanel();
|
||||
browseVisualizeTabPane = new JTabbedPane();
|
||||
accountsBrowser = new AccountsBrowser();
|
||||
vizPanel = new VisualizationPanel();
|
||||
filtersPane = new FiltersPanel();
|
||||
|
||||
splitPane.setDividerLocation(400);
|
||||
splitPane.setResizeWeight(0.7);
|
||||
browseVisualizeTabPane.setFont(new Font("Tahoma", 0, 18)); // NOI18N
|
||||
browseVisualizeTabPane.addTab(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.accountsBrowser.TabConstraints.tabTitle_1"), new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/table.png")), accountsBrowser); // NOI18N
|
||||
browseVisualizeTabPane.addTab(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.vizPanel.TabConstraints.tabTitle_1"), new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/emblem-web.png")), vizPanel); // NOI18N
|
||||
|
||||
browseVisualizeTabPane.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
|
||||
browseVisualizeTabPane.addTab(org.openide.util.NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.accountsBrowser.TabConstraints.tabTitle"), new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/table.png")), accountsBrowser); // NOI18N
|
||||
filtersPane.setMinimumSize(new Dimension(256, 495));
|
||||
|
||||
splitPane.setLeftComponent(browseVisualizeTabPane);
|
||||
|
||||
filtersPane.setMinimumSize(new java.awt.Dimension(256, 495));
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
GroupLayout layout = new GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(6, 6, 6)
|
||||
.addComponent(filtersPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(splitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1277, Short.MAX_VALUE)
|
||||
.addGap(0, 0, 0))
|
||||
.addComponent(filtersPane, GroupLayout.PREFERRED_SIZE, 265, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(browseVisualizeTabPane, GroupLayout.PREFERRED_SIZE, 786, Short.MAX_VALUE)
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(6, 6, 6)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(filtersPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(splitPane))
|
||||
.addComponent(filtersPane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGap(5, 5, 5))
|
||||
.addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addComponent(browseVisualizeTabPane)
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
browseVisualizeTabPane.getAccessibleContext().setAccessibleName(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.browseVisualizeTabPane.AccessibleContext.accessibleName")); // NOI18N
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private org.sleuthkit.autopsy.communications.AccountsBrowser accountsBrowser;
|
||||
private javax.swing.JTabbedPane browseVisualizeTabPane;
|
||||
private org.sleuthkit.autopsy.communications.FiltersPanel filtersPane;
|
||||
private javax.swing.JSplitPane splitPane;
|
||||
private AccountsBrowser accountsBrowser;
|
||||
private JTabbedPane browseVisualizeTabPane;
|
||||
private FiltersPanel filtersPane;
|
||||
private VisualizationPanel vizPanel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
@Override
|
||||
@ -124,11 +136,6 @@ public final class CVTTopComponent extends TopComponent implements ExplorerManag
|
||||
WindowManager.getDefault().setTopComponentFloating(this, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExplorerManager getExplorerManager() {
|
||||
return acctsBrowserExplorerManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
super.open();
|
||||
@ -138,7 +145,7 @@ public final class CVTTopComponent extends TopComponent implements ExplorerManag
|
||||
*
|
||||
* Re-applying the filters means we will lose the selection...
|
||||
*/
|
||||
filtersPane.updateAndApplyFilters();
|
||||
filtersPane.updateAndApplyFilters(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,333 @@
|
||||
/*
|
||||
* 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.github.mustachejava.DefaultMustacheFactory;
|
||||
import com.github.mustachejava.Mustache;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.MultimapBuilder;
|
||||
import com.mxgraph.model.mxCell;
|
||||
import com.mxgraph.model.mxICell;
|
||||
import com.mxgraph.util.mxConstants;
|
||||
import com.mxgraph.view.mxCellState;
|
||||
import com.mxgraph.view.mxGraph;
|
||||
import com.mxgraph.view.mxStylesheet;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringWriter;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.SwingWorker;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.progress.ProgressIndicator;
|
||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||
import org.sleuthkit.datamodel.AccountPair;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Implementation of mxGraph customized for our use in the CVT visualize mode.
|
||||
* Acts as the primary entry point into the JGraphX API.
|
||||
*/
|
||||
final class CommunicationsGraph extends mxGraph {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CommunicationsGraph.class.getName());
|
||||
private static final URL MARKER_PIN_URL = CommunicationsGraph.class.getResource("/org/sleuthkit/autopsy/communications/images/marker--pin.png");
|
||||
private static final URL LOCK_URL = CommunicationsGraph.class.getResource("/org/sleuthkit/autopsy/communications/images/lock_large_locked.png");
|
||||
|
||||
/* mustache.java template */
|
||||
private final static Mustache labelMustache;
|
||||
|
||||
static {
|
||||
final InputStream templateStream = CommunicationsGraph.class.getResourceAsStream("/org/sleuthkit/autopsy/communications/Vertex_Label_template.html");
|
||||
labelMustache = new DefaultMustacheFactory().compile(new InputStreamReader(templateStream), "Vertex_Label");
|
||||
}
|
||||
|
||||
/* Style sheet for default vertex and edge styles. These are initialized in
|
||||
* the static block below. */
|
||||
static final private mxStylesheet mxStylesheet = new mxStylesheet();
|
||||
|
||||
static {
|
||||
//initialize defaul vertex properties
|
||||
mxStylesheet.getDefaultVertexStyle().put(mxConstants.STYLE_SHAPE, mxConstants.SHAPE_ELLIPSE);
|
||||
mxStylesheet.getDefaultVertexStyle().put(mxConstants.STYLE_PERIMETER, mxConstants.PERIMETER_ELLIPSE);
|
||||
mxStylesheet.getDefaultVertexStyle().put(mxConstants.STYLE_FONTCOLOR, "000000");
|
||||
|
||||
//initialize defaul edge properties
|
||||
mxStylesheet.getDefaultEdgeStyle().put(mxConstants.STYLE_NOLABEL, true);
|
||||
mxStylesheet.getDefaultEdgeStyle().put(mxConstants.STYLE_PERIMETER_SPACING, 0);
|
||||
mxStylesheet.getDefaultEdgeStyle().put(mxConstants.STYLE_ENDARROW, mxConstants.NONE);
|
||||
mxStylesheet.getDefaultEdgeStyle().put(mxConstants.STYLE_STARTARROW, mxConstants.NONE);
|
||||
}
|
||||
|
||||
/* Map from type specific account identifier to mxCell(vertex). */
|
||||
private final Map<String, mxCell> nodeMap = new HashMap<>();
|
||||
|
||||
/* Map from relationship source (Content) to mxCell (edge). */
|
||||
private final Multimap<Content, mxCell> edgeMap = MultimapBuilder.hashKeys().hashSetValues().build();
|
||||
private final LockedVertexModel lockedVertexModel;
|
||||
|
||||
private final PinnedAccountModel pinnedAccountModel;
|
||||
|
||||
CommunicationsGraph() {
|
||||
super(mxStylesheet);
|
||||
//set fixed properties of graph.
|
||||
setAutoSizeCells(true);
|
||||
setCellsCloneable(false);
|
||||
setDropEnabled(false);
|
||||
setCellsCloneable(false);
|
||||
setCellsEditable(false);
|
||||
setCellsResizable(false);
|
||||
setCellsMovable(true);
|
||||
setCellsDisconnectable(false);
|
||||
setConnectableEdges(false);
|
||||
setDisconnectOnMove(false);
|
||||
setEdgeLabelsMovable(false);
|
||||
setVertexLabelsMovable(false);
|
||||
setAllowDanglingEdges(false);
|
||||
setCellsBendable(true);
|
||||
setKeepEdgesInBackground(true);
|
||||
setResetEdgesOnMove(true);
|
||||
setHtmlLabels(true);
|
||||
|
||||
lockedVertexModel = new LockedVertexModel();
|
||||
lockedVertexModel.registerhandler((LockedVertexModel.VertexLockEvent event) -> {
|
||||
if (event.isVertexLocked()) {
|
||||
getView().clear(event.getVertex(), true, true);
|
||||
getView().validate();
|
||||
} else {
|
||||
final mxCellState state = getView().getState(event.getVertex(), true);
|
||||
getView().updateLabel(state);
|
||||
getView().updateLabelBounds(state);
|
||||
getView().updateBoundingBox(state);
|
||||
}
|
||||
});
|
||||
|
||||
pinnedAccountModel = new PinnedAccountModel(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the LockedVertexModel
|
||||
*
|
||||
* @return the LockedVertexModel
|
||||
*/
|
||||
LockedVertexModel getLockedVertexModel() {
|
||||
return lockedVertexModel;
|
||||
}
|
||||
|
||||
PinnedAccountModel getPinnedAccountModel() {
|
||||
return pinnedAccountModel;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
nodeMap.clear();
|
||||
edgeMap.clear();
|
||||
removeCells(getChildVertices(getDefaultParent()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertValueToString(Object cell) {
|
||||
final StringWriter stringWriter = new StringWriter();
|
||||
HashMap<String, Object> scopes = new HashMap<>();
|
||||
|
||||
Object value = getModel().getValue(cell);
|
||||
if (value instanceof AccountDeviceInstanceKey) {
|
||||
final AccountDeviceInstanceKey adiKey = (AccountDeviceInstanceKey) value;
|
||||
|
||||
scopes.put("accountName", adiKey.getAccountDeviceInstance().getAccount().getTypeSpecificID());
|
||||
scopes.put("size", Math.round(Math.log(adiKey.getMessageCount()) + 5));
|
||||
scopes.put("iconFileName", CommunicationsGraph.class.getResource(Utils.getIconFilePath(adiKey.getAccountDeviceInstance().getAccount().getAccountType())));
|
||||
scopes.put("pinned", pinnedAccountModel.isAccountPinned(adiKey));
|
||||
scopes.put("MARKER_PIN_URL", MARKER_PIN_URL);
|
||||
scopes.put("locked", lockedVertexModel.isVertexLocked((mxCell) cell));
|
||||
scopes.put("LOCK_URL", LOCK_URL);
|
||||
|
||||
labelMustache.execute(stringWriter, scopes);
|
||||
|
||||
return stringWriter.toString();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolTipForCell(Object cell) {
|
||||
final StringWriter stringWriter = new StringWriter();
|
||||
HashMap<String, Object> scopes = new HashMap<>();
|
||||
|
||||
Object value = getModel().getValue(cell);
|
||||
if (value instanceof AccountDeviceInstanceKey) {
|
||||
final AccountDeviceInstanceKey adiKey = (AccountDeviceInstanceKey) value;
|
||||
|
||||
scopes.put("accountName", adiKey.getAccountDeviceInstance().getAccount().getTypeSpecificID());
|
||||
scopes.put("relationships", 12);// Math.round(Math.log(adiKey.getMessageCount()) + 5));
|
||||
scopes.put("iconFileName", CommunicationsGraph.class.getResource(Utils.getIconFilePath(adiKey.getAccountDeviceInstance().getAccount().getAccountType())));
|
||||
scopes.put("pinned", pinnedAccountModel.isAccountPinned(adiKey));
|
||||
scopes.put("MARKER_PIN_URL", MARKER_PIN_URL);
|
||||
scopes.put("locked", lockedVertexModel.isVertexLocked((mxCell) cell));
|
||||
scopes.put("LOCK_URL", LOCK_URL);
|
||||
scopes.put("device_id", adiKey.getAccountDeviceInstance().getDeviceId());
|
||||
|
||||
labelMustache.execute(stringWriter, scopes);
|
||||
|
||||
return stringWriter.toString();
|
||||
} else {
|
||||
final mxICell edge = (mxICell) cell;
|
||||
final long count = (long) edge.getValue();
|
||||
return "<html>" + edge.getId() + "<br>" + count + (count == 1 ? " relationship" : " relationships") + "</html>";
|
||||
}
|
||||
}
|
||||
|
||||
SwingWorker<?, ?> rebuild(ProgressIndicator progress, CommunicationsManager commsManager, CommunicationsFilter currentFilter) {
|
||||
return new RebuildWorker(progress, commsManager, currentFilter);
|
||||
}
|
||||
|
||||
void resetGraph() {
|
||||
clear();
|
||||
getView().setScale(1);
|
||||
pinnedAccountModel.clear();
|
||||
lockedVertexModel.clear();
|
||||
}
|
||||
|
||||
private mxCell getOrCreateVertex(AccountDeviceInstanceKey accountDeviceInstanceKey) {
|
||||
final AccountDeviceInstance accountDeviceInstance = accountDeviceInstanceKey.getAccountDeviceInstance();
|
||||
final String name = accountDeviceInstance.getAccount().getTypeSpecificID();
|
||||
|
||||
final mxCell vertex = nodeMap.computeIfAbsent(name + accountDeviceInstance.getDeviceId(), vertexName -> {
|
||||
double size = Math.sqrt(accountDeviceInstanceKey.getMessageCount()) + 10;
|
||||
|
||||
mxCell newVertex = (mxCell) insertVertex(
|
||||
getDefaultParent(),
|
||||
name, accountDeviceInstanceKey,
|
||||
Math.random() * 400,
|
||||
Math.random() * 400,
|
||||
size,
|
||||
size);
|
||||
return newVertex;
|
||||
});
|
||||
return vertex;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private mxCell addOrUpdateEdge(long relSources, AccountDeviceInstanceKey account1, AccountDeviceInstanceKey account2) {
|
||||
mxCell vertex1 = getOrCreateVertex(account1);
|
||||
mxCell vertex2 = getOrCreateVertex(account2);
|
||||
Object[] edgesBetween = getEdgesBetween(vertex1, vertex2);
|
||||
mxCell edge;
|
||||
if (edgesBetween.length == 0) {
|
||||
final String edgeName = vertex1.getId() + " - " + vertex2.getId();
|
||||
edge = (mxCell) insertEdge(getDefaultParent(), edgeName, relSources, vertex1, vertex2,
|
||||
"strokeWidth=" + (Math.log(relSources) + 1));
|
||||
} else {
|
||||
edge = (mxCell) edgesBetween[0];
|
||||
edge.setStyle("strokeWidth=" + (Math.log(relSources) + 1));
|
||||
}
|
||||
return edge;
|
||||
}
|
||||
|
||||
/**
|
||||
* SwingWorker that loads the accounts and edges for this graph according to
|
||||
* the pinned accounts and the current filters.
|
||||
*/
|
||||
private class RebuildWorker extends SwingWorker<Void, Void> {
|
||||
|
||||
private final ProgressIndicator progress;
|
||||
private final CommunicationsManager commsManager;
|
||||
private final CommunicationsFilter currentFilter;
|
||||
|
||||
RebuildWorker(ProgressIndicator progress, CommunicationsManager commsManager, CommunicationsFilter currentFilter) {
|
||||
this.progress = progress;
|
||||
this.currentFilter = currentFilter;
|
||||
this.commsManager = commsManager;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground() throws Exception {
|
||||
progress.start("Loading accounts");
|
||||
int progressCounter = 0;
|
||||
try {
|
||||
/**
|
||||
* set to keep track of accounts related to pinned accounts
|
||||
*/
|
||||
final Map<AccountDeviceInstance, AccountDeviceInstanceKey> relatedAccounts = new HashMap<>();
|
||||
for (final AccountDeviceInstanceKey adiKey : pinnedAccountModel.getPinnedAccounts()) {
|
||||
if (isCancelled()) {
|
||||
break;
|
||||
}
|
||||
final List<AccountDeviceInstance> relatedAccountDeviceInstances =
|
||||
commsManager.getRelatedAccountDeviceInstances(adiKey.getAccountDeviceInstance(), currentFilter);
|
||||
relatedAccounts.put(adiKey.getAccountDeviceInstance(), adiKey);
|
||||
getOrCreateVertex(adiKey);
|
||||
|
||||
//get accounts related to pinned account
|
||||
for (final AccountDeviceInstance relatedADI : relatedAccountDeviceInstances) {
|
||||
final long adiRelationshipsCount = commsManager.getRelationshipSourcesCount(relatedADI, currentFilter);
|
||||
final AccountDeviceInstanceKey relatedADIKey = new AccountDeviceInstanceKey(relatedADI, currentFilter, adiRelationshipsCount);
|
||||
relatedAccounts.put(relatedADI, relatedADIKey); //store related accounts
|
||||
}
|
||||
progress.progress(++progressCounter);
|
||||
}
|
||||
|
||||
Set<AccountDeviceInstance> accounts = relatedAccounts.keySet();
|
||||
|
||||
Map<AccountPair, Long> relationshipCounts = commsManager.getRelationshipCountsPairwise(accounts, currentFilter);
|
||||
|
||||
int total = relationshipCounts.size();
|
||||
int k = 0;
|
||||
progress.switchToDeterminate("", 0, total);
|
||||
for (Map.Entry<AccountPair, Long> entry : relationshipCounts.entrySet()) {
|
||||
Long count = entry.getValue();
|
||||
AccountPair relationshipKey = entry.getKey();
|
||||
AccountDeviceInstanceKey account1 = relatedAccounts.get(relationshipKey.getFirst());
|
||||
AccountDeviceInstanceKey account2 = relatedAccounts.get(relationshipKey.getSecond());
|
||||
mxCell addEdge = addOrUpdateEdge(count, account1, account2);
|
||||
progress.progress(addEdge.getId(), k++);
|
||||
}
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.SEVERE, "Error", tskCoreException);
|
||||
} finally {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
super.done();
|
||||
try {
|
||||
get();
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, "Error building graph visualization. ", ex);
|
||||
} catch (CancellationException ex) {
|
||||
logger.log(Level.INFO, "Graph visualization cancelled");
|
||||
} finally {
|
||||
progress.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public interface EventHandler<T> {
|
||||
|
||||
void handle(T event);
|
||||
}
|
@ -241,7 +241,7 @@
|
||||
<Component class="javax.swing.JLabel" name="devicesLabel">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/image.png"/>
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/images/image.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.devicesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017 Basis Technology Corp.
|
||||
* Copyright 2017-18 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -30,12 +30,11 @@ import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.swing.JCheckBox;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import javax.swing.JPanel;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import static org.sleuthkit.autopsy.casemodule.Case.Events.CURRENT_CASE;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||
@ -48,7 +47,6 @@ import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter.AccountTypeFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter.DateRangeFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG;
|
||||
import static org.sleuthkit.datamodel.Relationship.Type.MESSAGE;
|
||||
@ -56,18 +54,23 @@ import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Panel that holds the Filter control widgets and translates user filtering
|
||||
* changes into queries against the CommunicationsManager.
|
||||
* Panel that holds the Filter control widgets and triggers queries against the
|
||||
* CommunicationsManager on user filtering changes.
|
||||
*/
|
||||
final public class FiltersPanel extends javax.swing.JPanel {
|
||||
final public class FiltersPanel extends JPanel {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(FiltersPanel.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger logger = Logger.getLogger(FiltersPanel.class.getName());
|
||||
|
||||
private ExplorerManager em;
|
||||
|
||||
/**
|
||||
* Map from Account.Type to the checkbox for that account type's filter.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
private final Map<Account.Type, JCheckBox> accountTypeMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Map from datasource device id to the checkbox for that datasource.
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
private final Map<String, JCheckBox> devicesMap = new HashMap<>();
|
||||
|
||||
@ -75,6 +78,11 @@ final public class FiltersPanel extends javax.swing.JPanel {
|
||||
* Listens to ingest events to enable refresh button
|
||||
*/
|
||||
private final PropertyChangeListener ingestListener;
|
||||
|
||||
/**
|
||||
* Flag that indicates the UI is not up-sto-date with respect to the case DB
|
||||
* and it should be refreshed (by reapplying the filters).
|
||||
*/
|
||||
private boolean needsRefresh;
|
||||
|
||||
/**
|
||||
@ -84,8 +92,15 @@ final public class FiltersPanel extends javax.swing.JPanel {
|
||||
*/
|
||||
private final ItemListener validationListener;
|
||||
|
||||
@NbBundle.Messages({"refreshText=Refresh Results",
|
||||
"applyText=Apply"})
|
||||
/**
|
||||
* Is the device account type filter enabled or not. It should be enabled
|
||||
* when the Table/Brows mode is active and disabled when the visualization
|
||||
* is active. Initially false since the browse/table mode is active
|
||||
* initially.
|
||||
*/
|
||||
private boolean deviceAccountTypeEnabled;
|
||||
|
||||
@NbBundle.Messages({"refreshText=Refresh Results", "applyText=Apply"})
|
||||
public FiltersPanel() {
|
||||
initComponents();
|
||||
deviceRequiredLabel.setVisible(false);
|
||||
@ -106,8 +121,7 @@ final public class FiltersPanel extends javax.swing.JPanel {
|
||||
updateTimeZone();
|
||||
validationListener = itemEvent -> validateFilters();
|
||||
|
||||
updateFilters();
|
||||
setAllDevicesSelected(true);
|
||||
updateFilters(true);
|
||||
UserPreferences.addChangeListener(preferenceChangeEvent -> {
|
||||
if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME)) {
|
||||
updateTimeZone();
|
||||
@ -119,10 +133,10 @@ final public class FiltersPanel extends javax.swing.JPanel {
|
||||
if (eventType.equals(DATA_ADDED.toString())) {
|
||||
// Indicate that a refresh may be needed, unless the data added is Keyword or Hashset hits
|
||||
ModuleDataEvent eventData = (ModuleDataEvent) pce.getOldValue();
|
||||
if (null != eventData &&
|
||||
eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() &&
|
||||
eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
|
||||
updateFilters();
|
||||
if (null != eventData
|
||||
&& eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
|
||||
&& eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
|
||||
updateFilters(false);
|
||||
needsRefresh = true;
|
||||
validateFilters();
|
||||
}
|
||||
@ -154,32 +168,29 @@ final public class FiltersPanel extends javax.swing.JPanel {
|
||||
/**
|
||||
* Update the filter widgets, and apply them.
|
||||
*/
|
||||
void updateAndApplyFilters() {
|
||||
updateFilters();
|
||||
if (em != null) {
|
||||
void updateAndApplyFilters(boolean initialState) {
|
||||
updateFilters(initialState);
|
||||
applyFilters();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTimeZone() {
|
||||
dateRangeLabel.setText("Date Range ( " + Utils.getUserPreferredZoneId().toString() + "):");
|
||||
}
|
||||
|
||||
private void updateFilters() {
|
||||
/**
|
||||
* Updates the filter widgets to reflect he data sources/types in the case.
|
||||
*/
|
||||
private void updateFilters(boolean initialState) {
|
||||
updateAccountTypeFilter();
|
||||
updateDeviceFilter();
|
||||
updateDeviceFilter(initialState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
/*
|
||||
* Since we get the exploreremanager from the parent JComponenet, wait
|
||||
* till this FiltersPanel is actaully added to a parent.
|
||||
*/
|
||||
em = ExplorerManager.find(this);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(ingestListener);
|
||||
Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> {
|
||||
//clear the device filter widget when the case changes.
|
||||
devicesMap.clear();
|
||||
devicesPane.removeAll();
|
||||
});
|
||||
@ -198,51 +209,50 @@ final public class FiltersPanel extends javax.swing.JPanel {
|
||||
|
||||
//TODO: something like this commented code could be used to show only
|
||||
//the account types that are found:
|
||||
//final CommunicationsManager communicationsManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
|
||||
//final CommunicationsManager communicationsManager = Case.getOpenCase().getSleuthkitCase().getCommunicationsManager();
|
||||
//List<Account.Type> accountTypesInUse = communicationsManager.getAccountTypesInUse();
|
||||
//accountTypesInUSe.forEach(...)
|
||||
Account.Type.PREDEFINED_ACCOUNT_TYPES.forEach(type -> {
|
||||
if (type.equals(Account.Type.CREDIT_CARD)) {
|
||||
//don't show a check box for credit cards
|
||||
} else if (type.equals(Account.Type.DEVICE)) {
|
||||
//don't show a check box fro device
|
||||
} else {
|
||||
accountTypeMap.computeIfAbsent(type, t -> {
|
||||
final JCheckBox jCheckBox = new JCheckBox(
|
||||
"<html><table cellpadding=0><tr><td><img src=\""
|
||||
+ FiltersPanel.class.getResource("/org/sleuthkit/autopsy/communications/images/"
|
||||
+ Utils.getIconFileName(type))
|
||||
+ FiltersPanel.class.getResource(Utils.getIconFilePath(type))
|
||||
+ "\"/></td><td width=" + 3 + "><td>" + type.getDisplayName() + "</td></tr></table></html>",
|
||||
true
|
||||
);
|
||||
jCheckBox.addItemListener(validationListener);
|
||||
accountTypePane.add(jCheckBox);
|
||||
if (t.equals(Account.Type.DEVICE)) {
|
||||
//Deveice type filter is enabled based on whether we are in table or graph view.
|
||||
jCheckBox.setEnabled(deviceAccountTypeEnabled);
|
||||
}
|
||||
return jCheckBox;
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the devices filter widgets
|
||||
*/
|
||||
private void updateDeviceFilter() {
|
||||
private void updateDeviceFilter(boolean initialState) {
|
||||
try {
|
||||
final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase();
|
||||
final SleuthkitCase sleuthkitCase = Case.getOpenCase().getSleuthkitCase();
|
||||
|
||||
for (DataSource dataSource : sleuthkitCase.getDataSources()) {
|
||||
String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName();
|
||||
//store the device id in the map, but display a datasource name in the UI.
|
||||
devicesMap.computeIfAbsent(dataSource.getDeviceId(), ds -> {
|
||||
final JCheckBox jCheckBox = new JCheckBox(dsName, false);
|
||||
final JCheckBox jCheckBox = new JCheckBox(dsName, initialState);
|
||||
jCheckBox.addItemListener(validationListener);
|
||||
devicesPane.add(jCheckBox);
|
||||
return jCheckBox;
|
||||
});
|
||||
};
|
||||
|
||||
} catch (IllegalStateException ex) {
|
||||
}
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.WARNING, "Communications Visualization Tool opened with no open case.", ex);
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.SEVERE, "There was a error loading the datasources for the case.", tskCoreException);
|
||||
@ -332,7 +342,7 @@ final public class FiltersPanel extends javax.swing.JPanel {
|
||||
}
|
||||
});
|
||||
|
||||
devicesLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/image.png"))); // NOI18N
|
||||
devicesLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/image.png"))); // NOI18N
|
||||
devicesLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.devicesLabel.text")); // NOI18N
|
||||
|
||||
checkAllDevicesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.checkAllDevicesButton.text")); // NOI18N
|
||||
@ -488,26 +498,22 @@ final public class FiltersPanel extends javax.swing.JPanel {
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
/**
|
||||
* Query for accounts using the selected filters, and send the results to
|
||||
* the AccountsBrowser via the ExplorerManager.
|
||||
* Post an event with the new filters.
|
||||
*/
|
||||
private void applyFilters() {
|
||||
CVTEvents.getCVTEventBus().post(new CVTEvents.FilterChangeEvent(getFilter()));
|
||||
needsRefresh = false;
|
||||
validateFilters();
|
||||
}
|
||||
|
||||
private CommunicationsFilter getFilter() {
|
||||
CommunicationsFilter commsFilter = new CommunicationsFilter();
|
||||
commsFilter.addAndFilter(getDeviceFilter());
|
||||
commsFilter.addAndFilter(getAccountTypeFilter());
|
||||
commsFilter.addAndFilter(getDateRangeFilter());
|
||||
commsFilter.addAndFilter(new CommunicationsFilter.RelationshipTypeFilter(
|
||||
ImmutableSet.of(CALL_LOG, MESSAGE)));
|
||||
|
||||
try {
|
||||
final CommunicationsManager commsManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
|
||||
em.setRootContext(new AbstractNode(Children.create(new AccountsRootChildren(commsManager, commsFilter), true)));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "There was an error getting the CommunicationsManager for the current case.", ex);
|
||||
}
|
||||
|
||||
needsRefresh = false;
|
||||
validateFilters();
|
||||
return commsFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -538,6 +544,11 @@ final public class FiltersPanel extends javax.swing.JPanel {
|
||||
return accountTypeFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an DateRangeFilter that matches the state of the UI widgets
|
||||
*
|
||||
* @return an DateRangeFilter
|
||||
*/
|
||||
private DateRangeFilter getDateRangeFilter() {
|
||||
ZoneId zone = Utils.getUserPreferredZoneId();
|
||||
long start = startDatePicker.isEnabled() ? startDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0;
|
||||
@ -545,6 +556,21 @@ final public class FiltersPanel extends javax.swing.JPanel {
|
||||
return new DateRangeFilter(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable the device account type filter. The filter should be
|
||||
* disabled for the browse/table mode and enabled for the visualization.
|
||||
*
|
||||
* @param enable True to enable the device account type filter, False to
|
||||
* disable it.
|
||||
*/
|
||||
void setDeviceAccountTypeEnabled(boolean enable) {
|
||||
deviceAccountTypeEnabled = enable;
|
||||
JCheckBox deviceCheckbox = accountTypeMap.get(Account.Type.DEVICE);
|
||||
if (deviceCheckbox != null) {
|
||||
deviceCheckbox.setEnabled(deviceAccountTypeEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selection state of all the account type check boxes
|
||||
*
|
||||
@ -576,6 +602,7 @@ final public class FiltersPanel extends javax.swing.JPanel {
|
||||
private void setAllSelected(Map<?, JCheckBox> map, boolean selected) {
|
||||
map.values().forEach(box -> box.setSelected(selected));
|
||||
}
|
||||
|
||||
private void unCheckAllAccountTypesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_unCheckAllAccountTypesButtonActionPerformed
|
||||
setAllAccountTypesSelected(false);
|
||||
}//GEN-LAST:event_unCheckAllAccountTypesButtonActionPerformed
|
||||
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.eventbus.EventBus;
|
||||
import com.mxgraph.model.mxCell;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
class LockedVertexModel {
|
||||
|
||||
void registerhandler(EventHandler<VertexLockEvent> handler) {
|
||||
eventBus.register(handler);
|
||||
}
|
||||
|
||||
void unregisterhandler(EventHandler<VertexLockEvent> handler) {
|
||||
eventBus.unregister(handler);
|
||||
}
|
||||
|
||||
private final EventBus eventBus = new EventBus();
|
||||
|
||||
/**
|
||||
* Set of mxCells (vertices) that are 'locked'. Locked vertices are not
|
||||
* affected by layout algorithms, but may be repositioned manually by the
|
||||
* user.
|
||||
*/
|
||||
private final Set<mxCell> lockedVertices = new HashSet<>();
|
||||
|
||||
LockedVertexModel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock the given vertex so that applying a layout algorithm doesn't move
|
||||
* it. The user can still manually position the vertex.
|
||||
*
|
||||
* @param vertex The vertex to lock.
|
||||
*/
|
||||
void lockVertex(mxCell vertex) {
|
||||
lockedVertices.add(vertex);
|
||||
eventBus.post(new VertexLockEvent(vertex, true));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock the given vertex so that applying a layout algorithm can move it.
|
||||
*
|
||||
* @param vertex The vertex to unlock.
|
||||
*/
|
||||
void unlockVertex(mxCell vertex) {
|
||||
lockedVertices.remove(vertex);
|
||||
eventBus.post(new VertexLockEvent(vertex, false));
|
||||
|
||||
}
|
||||
|
||||
boolean isVertexLocked(mxCell vertex) {
|
||||
return lockedVertices.contains(vertex);
|
||||
|
||||
}
|
||||
|
||||
void clear() {
|
||||
lockedVertices.clear();
|
||||
}
|
||||
|
||||
static class VertexLockEvent {
|
||||
|
||||
private final mxCell vertex;
|
||||
|
||||
public mxCell getVertex() {
|
||||
return vertex;
|
||||
}
|
||||
|
||||
public boolean isVertexLocked() {
|
||||
return locked;
|
||||
}
|
||||
private final boolean locked;
|
||||
|
||||
VertexLockEvent(mxCell vertex, boolean locked) {
|
||||
this.vertex = vertex;
|
||||
this.locked = locked;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017 Basis Technology Corp.
|
||||
* Copyright 2017-18 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,96 +18,106 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import java.util.Collections;
|
||||
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.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
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.sleuthkit.autopsy.communications.AccountsRootChildren.AccountDeviceInstanceNode;
|
||||
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;
|
||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
|
||||
/**
|
||||
* The right hand side of the CVT. Has a DataResultPanel to show messages and
|
||||
* other account details, and a ContentViewer to show individual
|
||||
* 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.
|
||||
*/
|
||||
final class MessageBrowser extends javax.swing.JPanel implements ExplorerManager.Provider {
|
||||
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;
|
||||
private DataResultViewerTable dataResultViewerTable;
|
||||
/* lookup that will be exposed through the (Global Actions Context) */
|
||||
private final ModifiableProxyLookup proxyLookup = new ModifiableProxyLookup();
|
||||
/* Listener that keeps the proxyLookup in sync with the focused area of the
|
||||
* UI. */
|
||||
private final FocusPropertyListener focusPropertyListener = new FocusPropertyListener();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
MessageBrowser(ExplorerManager gacExplorerManager) {
|
||||
@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();
|
||||
|
||||
//add listener that maintains correct selection in the Global Actions Context
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.addPropertyChangeListener("focusOwner", focusPropertyListener);
|
||||
|
||||
this.tableEM.addPropertyChangeListener(new PropertyChangeListener() {
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
ExplorerManager parentExplorerManager = ExplorerManager.find(this);
|
||||
parentExplorerManager.addPropertyChangeListener(pce -> {
|
||||
public void propertyChange(PropertyChangeEvent pce) {
|
||||
if (pce.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
|
||||
final Node[] selectedNodes = parentExplorerManager.getSelectedNodes();
|
||||
|
||||
final Node[] selectedNodes = MessageBrowser.this.tableEM.getSelectedNodes();
|
||||
messagesResultPanel.setNumMatches(0);
|
||||
messagesResultPanel.setNode(null);
|
||||
|
||||
if (selectedNodes.length == 0) {
|
||||
//reset panel when there is no selection
|
||||
messagesResultPanel.setPath("");
|
||||
} else {
|
||||
AccountDeviceInstanceNode adiNode = (AccountDeviceInstanceNode) selectedNodes[0];
|
||||
CommunicationsFilter filter = adiNode.getFilter();
|
||||
CommunicationsManager commsManager = adiNode.getCommsManager();
|
||||
final Set<AccountDeviceInstance> accountDeviceInstances;
|
||||
if (selectedNodes.length > 0) {
|
||||
Node rootNode;
|
||||
final Node selectedNode = selectedNodes[0];
|
||||
|
||||
if (selectedNodes.length == 1) {
|
||||
final AccountDeviceInstance accountDeviceInstance = adiNode.getAccountDeviceInstance();
|
||||
accountDeviceInstances = Collections.singleton(accountDeviceInstance);
|
||||
messagesResultPanel.setPath(accountDeviceInstance.getAccount().getTypeSpecificID());
|
||||
if (selectedNode instanceof AccountDeviceInstanceNode) {
|
||||
rootNode = makeRootNodeFromAccountDeviceInstanceNodes(selectedNodes);
|
||||
} else {
|
||||
accountDeviceInstances = Stream.of(selectedNodes)
|
||||
.map(node -> (AccountDeviceInstanceNode) node)
|
||||
.map(AccountDeviceInstanceNode::getAccountDeviceInstance)
|
||||
.collect(Collectors.toSet());
|
||||
messagesResultPanel.setPath(selectedNodes.length + " accounts");
|
||||
rootNode = selectedNode;
|
||||
}
|
||||
messagesResultPanel.setPath(rootNode.getDisplayName());
|
||||
messagesResultPanel.setNode(new TableFilterNode(new DataResultFilterNode(rootNode, gacExplorerManager), true));
|
||||
}
|
||||
AccountDetailsNode accountDetailsNode
|
||||
= new AccountDetailsNode(accountDeviceInstances, filter, commsManager);
|
||||
TableFilterNode wrappedNode
|
||||
= new TableFilterNode(new DataResultFilterNode(accountDetailsNode, parentExplorerManager), true);
|
||||
messagesResultPanel.setNode(wrappedNode);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//add the required result viewers and THEN open the panel
|
||||
if (null == dataResultViewerTable) {
|
||||
dataResultViewerTable = new DataResultViewerTable(gacExplorerManager, "Messages");
|
||||
messagesResultPanel.addResultViewer(dataResultViewerTable);
|
||||
private Node makeRootNodeFromAccountDeviceInstanceNodes(final Node[] selectedNodes) {
|
||||
//Use lookup here?
|
||||
final AccountDeviceInstanceNode adiNode = (AccountDeviceInstanceNode) selectedNodes[0];
|
||||
|
||||
final Set<AccountDeviceInstance> accountDeviceInstances = new HashSet<>();
|
||||
for (final Node n : selectedNodes) {
|
||||
//Use lookup here?
|
||||
accountDeviceInstances.add(((AccountDeviceInstanceNode) n).getAccountDeviceInstance());
|
||||
}
|
||||
messagesResultPanel.open();
|
||||
return SelectionNode.createFromAccounts(accountDeviceInstances, adiNode.getFilter(), adiNode.getCommsManager());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -115,6 +125,18 @@ final class MessageBrowser extends javax.swing.JPanel implements ExplorerManager
|
||||
return gacExplorerManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lookup getLookup() {
|
||||
return proxyLookup;
|
||||
}
|
||||
|
||||
@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
|
||||
@ -156,4 +178,38 @@ final class MessageBrowser extends javax.swing.JPanel implements ExplorerManager
|
||||
private javax.swing.JSplitPane splitPane;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
/**
|
||||
* 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 include have
|
||||
* 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.
|
||||
*/
|
||||
private class FocusPropertyListener implements PropertyChangeListener {
|
||||
|
||||
@Override
|
||||
public void propertyChange(final PropertyChangeEvent focusEvent) {
|
||||
|
||||
if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
|
||||
final Component newFocusOwner = (Component) focusEvent.getNewValue();
|
||||
|
||||
if (newFocusOwner != null) {
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017 Basis Technology Corp.
|
||||
* Copyright 2017-18 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -19,6 +19,7 @@
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.sleuthkit.autopsy.contentviewers.MessageContentViewer;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
|
||||
|
||||
@ -26,12 +27,18 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent;
|
||||
* Extends MessageContentViewer so that it implements DataContent and can be set
|
||||
* as the only ContentViewer for a DataResultPanel
|
||||
*/
|
||||
public class MessageDataContent extends MessageContentViewer implements DataContent {
|
||||
final class MessageDataContent extends MessageContentViewer implements DataContent, ExplorerManager.Provider {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
final private ExplorerManager explorerManager = new ExplorerManager();
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
public void propertyChange(final PropertyChangeEvent evt) {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExplorerManager getExplorerManager() {
|
||||
return explorerManager;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 org.openide.util.Lookup;
|
||||
import org.openide.util.lookup.ProxyLookup;
|
||||
|
||||
/**
|
||||
* Extension of ProxyLookup that exposes the ability to change the Lookups
|
||||
* delegated to.
|
||||
*
|
||||
*/
|
||||
final class ModifiableProxyLookup extends ProxyLookup {
|
||||
|
||||
ModifiableProxyLookup(final Lookup... lookups) {
|
||||
super(lookups);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Lookups delegated to by this lookup.
|
||||
*
|
||||
* @param lookups The new Lookups to delegate to.
|
||||
*/
|
||||
void setNewLookups(final Lookup... lookups) {
|
||||
/* default */
|
||||
setLookups(lookups);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017 Basis Technology Corp.
|
||||
* Copyright 2017-18 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -19,6 +19,8 @@
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import org.openide.awt.ActionID;
|
||||
@ -29,9 +31,10 @@ import org.openide.util.HelpCtx;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.actions.CallableSystemAction;
|
||||
import org.openide.util.actions.Presenter;
|
||||
import org.openide.windows.TopComponent;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.core.RuntimeProperties;
|
||||
|
||||
/**
|
||||
* Action that opens the CVT. Available through the Tools menu and the main
|
||||
@ -41,18 +44,27 @@ import org.openide.windows.WindowManager;
|
||||
id = "org.sleuthkit.autopsy.communicationsVisualization.OpenCVTAction")
|
||||
@ActionRegistration(displayName = "#CTL_OpenCVTAction", lazy = false)
|
||||
@ActionReferences(value = {
|
||||
@ActionReference(path = "Menu/Tools", position = 102)})
|
||||
@ActionReference(path = "Menu/Tools", position = 102)
|
||||
,
|
||||
@ActionReference(path = "Toolbars/Case", position = 102)})
|
||||
@Messages("CTL_OpenCVTAction=Communications")
|
||||
public final class OpenCommVisualizationToolAction extends CallableSystemAction implements Presenter.Toolbar {
|
||||
public final class OpenCommVisualizationToolAction extends CallableSystemAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final PropertyChangeListener pcl;
|
||||
private final JButton toolbarButton = new JButton(getName(),
|
||||
new ImageIcon(getClass().getResource("images/emblem-web24.png"))); //NON-NLS
|
||||
|
||||
public OpenCommVisualizationToolAction() {
|
||||
toolbarButton.addActionListener(actionEvent -> performAction());
|
||||
setEnabled(false); //disabled by default. Will be enabled in Case.java when a case is opened.
|
||||
pcl = (PropertyChangeEvent evt) -> {
|
||||
if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
setEnabled(RuntimeProperties.runningWithGUI() && evt.getNewValue() != null);
|
||||
}
|
||||
};
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.ImmutableSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
class PinnedAccountModel {
|
||||
|
||||
/**
|
||||
* Set of AccountDeviceInstanceKeys that are 'Pinned' to this graph. Pinned
|
||||
* accounts are shown regardless of filters, and accounts that are related
|
||||
* to pinned accounts and pass the filters are show. Pinning accounts is the
|
||||
* primary way to populate the graph.
|
||||
*/
|
||||
private final Set<AccountDeviceInstanceKey> pinnedAccountDevices = new HashSet<>();
|
||||
private final CommunicationsGraph graph;
|
||||
|
||||
PinnedAccountModel(CommunicationsGraph graph) {
|
||||
this.graph = graph;
|
||||
}
|
||||
|
||||
boolean isAccountPinned(AccountDeviceInstanceKey account) {
|
||||
return pinnedAccountDevices.contains(account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpin the given accounts from the graph. Pinned accounts will always be
|
||||
* shown regardless of the filter state. Furthermore, accounts with
|
||||
* relationships that pass the filters will also be shown.
|
||||
*
|
||||
* @param accountDeviceInstances The accounts to unpin.
|
||||
*/
|
||||
void unpinAccount(ImmutableSet<AccountDeviceInstanceKey> accountDeviceInstances) {
|
||||
pinnedAccountDevices.removeAll(accountDeviceInstances);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pin the given accounts to the graph. Pinned accounts will always be shown
|
||||
* regardless of the filter state. Furthermore, accounts with relationships
|
||||
* that pass the filters will also be shown.
|
||||
*
|
||||
* @param accountDeviceInstances The accounts to pin.
|
||||
*/
|
||||
void pinAccount(ImmutableSet<AccountDeviceInstanceKey> accountDeviceInstances) {
|
||||
pinnedAccountDevices.addAll(accountDeviceInstances);
|
||||
}
|
||||
|
||||
/**
|
||||
* Are there any accounts in this graph? If there are no pinned accounts the
|
||||
* graph will be empty.
|
||||
*
|
||||
* @return True if this graph is empty.
|
||||
*/
|
||||
boolean isEmpty() {
|
||||
return pinnedAccountDevices.isEmpty();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
pinnedAccountDevices.clear();
|
||||
}
|
||||
|
||||
Iterable<AccountDeviceInstanceKey> getPinnedAccounts() {
|
||||
return ImmutableSet.copyOf(pinnedAccountDevices);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017 Basis Technology Corp.
|
||||
* Copyright 2017-18 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -43,11 +43,11 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
/**
|
||||
* Node for a relationship, as represented by a BlackboardArtifact.
|
||||
*/
|
||||
public class RelationshipNode extends BlackboardArtifactNode {
|
||||
final class RelationshipNode extends BlackboardArtifactNode {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(RelationshipNode.class.getName());
|
||||
|
||||
public RelationshipNode(BlackboardArtifact artifact) {
|
||||
RelationshipNode(BlackboardArtifact artifact) {
|
||||
super(artifact);
|
||||
final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s");
|
||||
String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message");
|
||||
@ -113,6 +113,9 @@ public class RelationshipNode extends BlackboardArtifactNode {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
addTagProperty(ss);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -144,4 +147,14 @@ public class RelationshipNode extends BlackboardArtifactNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
133
Core/src/org/sleuthkit/autopsy/communications/SelectionNode.java
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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 org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.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) {
|
||||
super(children);
|
||||
}
|
||||
|
||||
static SelectionNode createFromAccountsAndRelationships(
|
||||
Set<Content> edgeRelationshipArtifacts,
|
||||
Set<AccountDeviceInstance> accountDeviceInstances,
|
||||
CommunicationsFilter filter,
|
||||
CommunicationsManager commsManager) {
|
||||
|
||||
SelectionNode node = new SelectionNode(Children.create(
|
||||
new RelationshipChildren(
|
||||
edgeRelationshipArtifacts,
|
||||
accountDeviceInstances,
|
||||
commsManager,
|
||||
filter),
|
||||
true));
|
||||
|
||||
//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<AccountDeviceInstance> 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 t) {
|
||||
if (t instanceof BlackboardArtifact) {
|
||||
return new RelationshipNode((BlackboardArtifact) t);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Cannot create a RelationshipNode for non BlackboardArtifact content.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.communications;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
|
||||
/**
|
||||
@ -37,36 +38,12 @@ class Utils {
|
||||
}
|
||||
|
||||
/**
|
||||
* The file name of the icon for the given Account Type. Will not include
|
||||
* the path but will include the extension.
|
||||
* Get the path of the icon for the given Account Type.
|
||||
*
|
||||
* @return The file name of the icon for the given Account Type.
|
||||
* @return The path of the icon for the given Account Type.
|
||||
*/
|
||||
static final String getIconFileName(Account.Type type) {
|
||||
if (type.equals(Account.Type.CREDIT_CARD)) {
|
||||
return "credit-card.png";
|
||||
} else if (type.equals(Account.Type.DEVICE)) {
|
||||
return "image.png";
|
||||
} else if (type.equals(Account.Type.EMAIL)) {
|
||||
return "email.png";
|
||||
} else if (type.equals(Account.Type.FACEBOOK)) {
|
||||
return "facebook.png";
|
||||
} else if (type.equals(Account.Type.INSTAGRAM)) {
|
||||
return "instagram.png";
|
||||
} else if (type.equals(Account.Type.MESSAGING_APP)) {
|
||||
return "messaging.png";
|
||||
} else if (type.equals(Account.Type.PHONE)) {
|
||||
return "phone.png";
|
||||
} else if (type.equals(Account.Type.TWITTER)) {
|
||||
return "twitter.png";
|
||||
} else if (type.equals(Account.Type.WEBSITE)) {
|
||||
return "web-file.png";
|
||||
} else if (type.equals(Account.Type.WHATSAPP)) {
|
||||
return "WhatsApp.png";
|
||||
} else {
|
||||
//there could be a default icon instead...
|
||||
throw new IllegalArgumentException("Unknown Account.Type: " + type.getTypeName());
|
||||
}
|
||||
static final String getIconFilePath(Account.Type type) {
|
||||
return Accounts.getIconFilePath(type);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,3 @@
|
||||
<html>
|
||||
<div style="font-size:{{size}}px;">{{#pinned}}<img style="vertical-align: middle;" height={{size}} width={{size}} src={{MARKER_PIN_URL}}>{{/pinned}}{{#locked}}<img style="vertical-align: middle;"height={{size}} width={{size}} src={{LOCK_URL}}>{{/locked}}<img style="vertical-align: middle;" height={{size}} width={{size}} src={{iconFileName}}>{{accountName}} {{#device_id}}<br>data source: {{device_id}}{{/device_id}}</div>
|
||||
</html>
|
@ -0,0 +1,305 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.9" 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="false"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/>
|
||||
<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,0,-111,0,0,3,32"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JSplitPane" name="splitPane">
|
||||
<Properties>
|
||||
<Property name="dividerLocation" type="int" value="800"/>
|
||||
<Property name="resizeWeight" type="double" value="0.5"/>
|
||||
</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>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="borderLayoutPanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||
<JSplitPaneConstraints position="left"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="placeHolderPanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="Center"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="jTextArea1" min="-2" pref="424" max="-2" attributes="0"/>
|
||||
<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 max="32767" attributes="0"/>
|
||||
<Component id="jTextArea1" min="-2" pref="47" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JTextArea" name="jTextArea1">
|
||||
<Properties>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="f0" green="f0" red="f0" type="rgb"/>
|
||||
</Property>
|
||||
<Property name="columns" type="int" value="20"/>
|
||||
<Property name="lineWrap" type="boolean" value="true"/>
|
||||
<Property name="rows" type="int" value="5"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.jTextArea1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="toolbar">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="First"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
|
||||
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="fastOrganicLayoutButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="organicLayoutButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="hierarchyLayoutButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="circleLayoutButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jSeparator1" min="-2" pref="10" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="zoomOutButton" min="-2" pref="32" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="zoomInButton" min="-2" pref="32" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="zoomActualButton" min="-2" pref="33" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="fitZoomButton" min="-2" pref="32" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="zoomLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="27" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="2" attributes="0">
|
||||
<Component id="jLabel1" alignment="2" min="-2" pref="25" max="-2" attributes="0"/>
|
||||
<Component id="hierarchyLayoutButton" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="fastOrganicLayoutButton" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="organicLayoutButton" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="circleLayoutButton" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jSeparator1" alignment="2" max="32767" attributes="0"/>
|
||||
<Component id="zoomOutButton" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="zoomInButton" alignment="2" max="32767" attributes="0"/>
|
||||
<Component id="zoomActualButton" alignment="2" max="32767" attributes="0"/>
|
||||
<Component id="fitZoomButton" alignment="2" max="32767" attributes="0"/>
|
||||
<Component id="jLabel2" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="zoomLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<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/communications/Bundle.properties" key="VisualizationPanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="hierarchyLayoutButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.hierarchyLayoutButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="horizontalTextPosition" type="int" value="0"/>
|
||||
<Property name="verticalTextPosition" type="int" value="3"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="hierarchyLayoutButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="fastOrganicLayoutButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.fastOrganicLayoutButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="horizontalTextPosition" type="int" value="0"/>
|
||||
<Property name="verticalTextPosition" type="int" value="3"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="fastOrganicLayoutButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="organicLayoutButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.organicLayoutButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="horizontalTextPosition" type="int" value="0"/>
|
||||
<Property name="verticalTextPosition" type="int" value="3"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="organicLayoutButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="circleLayoutButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.circleLayoutButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="horizontalTextPosition" type="int" value="0"/>
|
||||
<Property name="verticalTextPosition" type="int" value="3"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="circleLayoutButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JToolBar$Separator" name="jSeparator1">
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="zoomOutButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out-red.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.zoomOutButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.zoomOutButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="horizontalTextPosition" type="int" value="0"/>
|
||||
<Property name="verticalTextPosition" type="int" value="3"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="zoomOutButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="zoomInButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.zoomInButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.zoomInButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="horizontalTextPosition" type="int" value="0"/>
|
||||
<Property name="verticalTextPosition" type="int" value="3"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="zoomInButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="zoomActualButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.zoomActualButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.zoomActualButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="horizontalTextPosition" type="int" value="0"/>
|
||||
<Property name="verticalTextPosition" type="int" value="3"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="zoomActualButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="fitZoomButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.fitZoomButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.fitZoomButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="horizontalTextPosition" type="int" value="0"/>
|
||||
<Property name="verticalTextPosition" type="int" value="3"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="fitZoomButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel2">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.jLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="zoomLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="VisualizationPanel.zoomLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
@ -0,0 +1,866 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017-18 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.eventbus.Subscribe;
|
||||
import com.mxgraph.layout.hierarchical.mxHierarchicalLayout;
|
||||
import com.mxgraph.layout.mxCircleLayout;
|
||||
import com.mxgraph.layout.mxFastOrganicLayout;
|
||||
import com.mxgraph.layout.mxIGraphLayout;
|
||||
import com.mxgraph.layout.mxOrganicLayout;
|
||||
import com.mxgraph.model.mxCell;
|
||||
import com.mxgraph.model.mxICell;
|
||||
import com.mxgraph.swing.handler.mxRubberband;
|
||||
import com.mxgraph.swing.mxGraphComponent;
|
||||
import com.mxgraph.swing.util.mxMorphing;
|
||||
import com.mxgraph.util.mxEvent;
|
||||
import com.mxgraph.util.mxEventObject;
|
||||
import com.mxgraph.util.mxEventSource;
|
||||
import com.mxgraph.util.mxPoint;
|
||||
import com.mxgraph.util.mxRectangle;
|
||||
import com.mxgraph.util.mxUndoManager;
|
||||
import com.mxgraph.util.mxUndoableEdit;
|
||||
import com.mxgraph.view.mxGraph;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Frame;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyVetoException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Arrays;
|
||||
import static java.util.Collections.singleton;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
import org.jdesktop.layout.GroupLayout;
|
||||
import org.jdesktop.layout.LayoutStyle;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.explorer.ExplorerUtils;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ProxyLookup;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import static org.sleuthkit.autopsy.casemodule.Case.Events.CURRENT_CASE;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||
import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator;
|
||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* A panel that goes in the Visualize tab of the Communications Visualization
|
||||
* Tool. Hosts an JGraphX mxGraphComponent that implements the communications
|
||||
* network visualization and a MessageBrowser for viewing details of
|
||||
* communications.
|
||||
*
|
||||
* The Lookup provided by getLookup will be proxied by the lookup of the
|
||||
* CVTTopComponent when this tab is active allowing for context sensitive
|
||||
* actions to work correctly.
|
||||
*/
|
||||
@NbBundle.Messages("VisualizationPanel.cancelButton.text=Cancel")
|
||||
final public class VisualizationPanel extends JPanel implements Lookup.Provider {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger logger = Logger.getLogger(VisualizationPanel.class.getName());
|
||||
private static final String BASE_IMAGE_PATH = "/org/sleuthkit/autopsy/communications/images";
|
||||
static final private ImageIcon pinIcon =
|
||||
new ImageIcon(VisualizationPanel.class.getResource(BASE_IMAGE_PATH + "/marker--pin.png"));
|
||||
static final private ImageIcon addPinIcon =
|
||||
new ImageIcon(VisualizationPanel.class.getResource(BASE_IMAGE_PATH + "/marker--plus.png"));
|
||||
static final private ImageIcon unpinIcon =
|
||||
new ImageIcon(VisualizationPanel.class.getResource(BASE_IMAGE_PATH + "/marker--minus.png"));
|
||||
static final private ImageIcon unlockIcon =
|
||||
new ImageIcon(VisualizationPanel.class.getResource(BASE_IMAGE_PATH + "/lock_large_unlocked.png"));
|
||||
static final private ImageIcon lockIcon =
|
||||
new ImageIcon(VisualizationPanel.class.getResource(BASE_IMAGE_PATH + "/lock_large_locked.png"));
|
||||
|
||||
private static final String CANCEL = Bundle.VisualizationPanel_cancelButton_text();
|
||||
|
||||
private final ExplorerManager vizEM = new ExplorerManager();
|
||||
private final ExplorerManager gacEM = new ExplorerManager();
|
||||
private final ProxyLookup proxyLookup;
|
||||
private Frame windowAncestor;
|
||||
|
||||
private CommunicationsManager commsManager;
|
||||
private CommunicationsFilter currentFilter;
|
||||
|
||||
private final mxGraphComponent graphComponent;
|
||||
private final CommunicationsGraph graph;
|
||||
|
||||
private mxUndoManager undoManager = new mxUndoManager();
|
||||
private final mxRubberband rubberband;
|
||||
private final mxFastOrganicLayout fastOrganicLayout;
|
||||
private final mxCircleLayout circleLayout;
|
||||
private final mxOrganicLayout organicLayout;
|
||||
private final mxHierarchicalLayout hierarchicalLayout;
|
||||
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
private SwingWorker<?, ?> worker;
|
||||
private final PinnedAccountModel pinnedAccountModel;
|
||||
private final LockedVertexModel lockedVertexModel;
|
||||
|
||||
public VisualizationPanel() {
|
||||
initComponents();
|
||||
graph = new CommunicationsGraph();
|
||||
pinnedAccountModel = graph.getPinnedAccountModel();
|
||||
lockedVertexModel = graph.getLockedVertexModel();
|
||||
|
||||
fastOrganicLayout = new mxFastOrganicLayoutImpl(graph);
|
||||
circleLayout = new mxCircleLayoutImpl(graph);
|
||||
organicLayout = new mxOrganicLayoutImpl(graph);
|
||||
hierarchicalLayout = new mxHierarchicalLayoutImpl(graph);
|
||||
|
||||
graphComponent = new mxGraphComponent(graph);
|
||||
graphComponent.setAutoExtend(true);
|
||||
graphComponent.setAutoScroll(true);
|
||||
graphComponent.setAutoscrolls(true);
|
||||
graphComponent.setConnectable(false);
|
||||
graphComponent.setDragEnabled(false);
|
||||
graphComponent.setKeepSelectionVisibleOnZoom(true);
|
||||
graphComponent.setOpaque(true);
|
||||
graphComponent.setToolTips(true);
|
||||
graphComponent.setBackground(Color.WHITE);
|
||||
borderLayoutPanel.add(graphComponent, BorderLayout.CENTER);
|
||||
|
||||
//install rubber band selection handler
|
||||
rubberband = new mxRubberband(graphComponent);
|
||||
|
||||
final mxEventSource.mxIEventListener scaleListener = (Object sender, mxEventObject evt) ->
|
||||
zoomLabel.setText(DecimalFormat.getPercentInstance().format(graph.getView().getScale()));
|
||||
graph.getView().addListener(mxEvent.SCALE, scaleListener);
|
||||
graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, scaleListener);
|
||||
|
||||
//right click handler
|
||||
graphComponent.getGraphControl().addMouseWheelListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseWheelMoved(final MouseWheelEvent event) {
|
||||
super.mouseWheelMoved(event);
|
||||
if (event.getPreciseWheelRotation() > 0) {
|
||||
graphComponent.zoomIn();
|
||||
} else if (event.getPreciseWheelRotation() < 0) {
|
||||
graphComponent.zoomOut();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
graphComponent.getGraphControl().addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(final MouseEvent event) {
|
||||
super.mouseClicked(event);
|
||||
if (SwingUtilities.isRightMouseButton(event)) {
|
||||
final mxCell cellAt = (mxCell) graphComponent.getCellAt(event.getX(), event.getY());
|
||||
if (cellAt != null && cellAt.isVertex()) {
|
||||
final JPopupMenu jPopupMenu = new JPopupMenu();
|
||||
final AccountDeviceInstanceKey adiKey = (AccountDeviceInstanceKey) cellAt.getValue();
|
||||
|
||||
if (lockedVertexModel.isVertexLocked(cellAt)) {
|
||||
jPopupMenu.add(new JMenuItem(new AbstractAction("UnLock " + cellAt.getId(), unlockIcon) {
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
lockedVertexModel.unlockVertex(cellAt);
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
jPopupMenu.add(new JMenuItem(new AbstractAction("Lock " + cellAt.getId(), lockIcon) {
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
lockedVertexModel.lockVertex(cellAt);
|
||||
}
|
||||
}));
|
||||
}
|
||||
if (pinnedAccountModel.isAccountPinned(adiKey)) {
|
||||
jPopupMenu.add(new JMenuItem(new AbstractAction("Unpin " + cellAt.getId(), unpinIcon) {
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
handleUnPinEvent(new CVTEvents.UnpinAccountsEvent(singleton((AccountDeviceInstanceKey) cellAt.getValue())));
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
jPopupMenu.add(new JMenuItem(new AbstractAction("Pin " + cellAt.getId(), addPinIcon) {
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
handlePinEvent(new CVTEvents.PinAccountsEvent(singleton((AccountDeviceInstanceKey) cellAt.getValue()), false));
|
||||
}
|
||||
}));
|
||||
jPopupMenu.add(new JMenuItem(new AbstractAction("Pin only " + cellAt.getId(), pinIcon) {
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
handlePinEvent(new CVTEvents.PinAccountsEvent(singleton((AccountDeviceInstanceKey) cellAt.getValue()), true));
|
||||
}
|
||||
}));
|
||||
}
|
||||
jPopupMenu.show(graphComponent.getGraphControl(), event.getX(), event.getY());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
final MessageBrowser messageBrowser = new MessageBrowser(vizEM, gacEM);
|
||||
|
||||
splitPane.setRightComponent(messageBrowser);
|
||||
|
||||
proxyLookup = new ProxyLookup(
|
||||
messageBrowser.getLookup(),
|
||||
ExplorerUtils.createLookup(vizEM, getActionMap()));
|
||||
|
||||
//feed selection to explorermanager
|
||||
graph.getSelectionModel().addListener(null, new SelectionListener());
|
||||
final mxEventSource.mxIEventListener undoListener = (Object sender, mxEventObject evt) ->
|
||||
undoManager.undoableEditHappened((mxUndoableEdit) evt.getProperty("edit"));
|
||||
|
||||
graph.getModel().addListener(mxEvent.UNDO, undoListener);
|
||||
graph.getView().addListener(mxEvent.UNDO, undoListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public Lookup getLookup() {
|
||||
return proxyLookup;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
void handleUnPinEvent(final CVTEvents.UnpinAccountsEvent pinEvent) {
|
||||
graph.getModel().beginUpdate();
|
||||
pinnedAccountModel.unpinAccount(pinEvent.getAccountDeviceInstances());
|
||||
graph.clear();
|
||||
rebuildGraph();
|
||||
// Updates the display
|
||||
graph.getModel().endUpdate();
|
||||
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
void handlePinEvent(final CVTEvents.PinAccountsEvent pinEvent) {
|
||||
graph.getModel().beginUpdate();
|
||||
if (pinEvent.isReplace()) {
|
||||
graph.resetGraph();
|
||||
}
|
||||
pinnedAccountModel.pinAccount(pinEvent.getAccountDeviceInstances());
|
||||
rebuildGraph();
|
||||
// Updates the display
|
||||
graph.getModel().endUpdate();
|
||||
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
void handleFilterEvent(final CVTEvents.FilterChangeEvent filterChangeEvent) {
|
||||
|
||||
graph.getModel().beginUpdate();
|
||||
graph.clear();
|
||||
currentFilter = filterChangeEvent.getNewFilter();
|
||||
rebuildGraph();
|
||||
// Updates the display
|
||||
graph.getModel().endUpdate();
|
||||
|
||||
}
|
||||
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
private void rebuildGraph() {
|
||||
if (pinnedAccountModel.isEmpty()) {
|
||||
borderLayoutPanel.remove(graphComponent);
|
||||
borderLayoutPanel.add(placeHolderPanel, BorderLayout.CENTER);
|
||||
repaint();
|
||||
} else {
|
||||
borderLayoutPanel.remove(placeHolderPanel);
|
||||
borderLayoutPanel.add(graphComponent, BorderLayout.CENTER);
|
||||
if (worker != null) {
|
||||
worker.cancel(true);
|
||||
}
|
||||
|
||||
final CancelationListener cancelationListener = new CancelationListener();
|
||||
final ModalDialogProgressIndicator progress = new ModalDialogProgressIndicator(windowAncestor, "Loading Visualization", new String[]{CANCEL}, CANCEL, cancelationListener);
|
||||
worker = graph.rebuild(progress, commsManager, currentFilter);
|
||||
cancelationListener.configure(worker, progress);
|
||||
worker.addPropertyChangeListener((final PropertyChangeEvent evt) -> {
|
||||
if (worker.isDone()) {
|
||||
if (worker.isCancelled()) {
|
||||
graph.resetGraph();
|
||||
rebuildGraph();
|
||||
} else if (graph.getModel().getChildCount(graph.getDefaultParent()) < 64) {
|
||||
applyOrganicLayout(10);
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
"Too many accounts, layout aborted.",
|
||||
"Autopsy",
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
worker.execute();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
windowAncestor = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, this);
|
||||
|
||||
try {
|
||||
commsManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
|
||||
} catch (IllegalStateException ex) {
|
||||
logger.log(Level.SEVERE, "Can't get CommunicationsManager when there is no case open.", ex);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting CommunicationsManager for the current case.", ex);
|
||||
|
||||
}
|
||||
|
||||
Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> {
|
||||
graph.getModel().beginUpdate();
|
||||
try {
|
||||
graph.resetGraph();
|
||||
} finally {
|
||||
graph.getModel().endUpdate();
|
||||
}
|
||||
if (evt.getNewValue() == null) {
|
||||
commsManager = null;
|
||||
} else {
|
||||
Case currentCase = (Case) evt.getNewValue();
|
||||
try {
|
||||
commsManager = currentCase.getSleuthkitCase().getCommunicationsManager();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting CommunicationsManager for the current case.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotify() {
|
||||
super.removeNotify();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 JSplitPane();
|
||||
borderLayoutPanel = new JPanel();
|
||||
placeHolderPanel = new JPanel();
|
||||
jTextArea1 = new JTextArea();
|
||||
toolbar = new JPanel();
|
||||
jLabel1 = new JLabel();
|
||||
hierarchyLayoutButton = new JButton();
|
||||
fastOrganicLayoutButton = new JButton();
|
||||
organicLayoutButton = new JButton();
|
||||
circleLayoutButton = new JButton();
|
||||
jSeparator1 = new JToolBar.Separator();
|
||||
zoomOutButton = new JButton();
|
||||
zoomInButton = new JButton();
|
||||
zoomActualButton = new JButton();
|
||||
fitZoomButton = new JButton();
|
||||
jLabel2 = new JLabel();
|
||||
zoomLabel = new JLabel();
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
splitPane.setDividerLocation(800);
|
||||
splitPane.setResizeWeight(0.5);
|
||||
|
||||
borderLayoutPanel.setLayout(new BorderLayout());
|
||||
|
||||
jTextArea1.setBackground(new Color(240, 240, 240));
|
||||
jTextArea1.setColumns(20);
|
||||
jTextArea1.setLineWrap(true);
|
||||
jTextArea1.setRows(5);
|
||||
jTextArea1.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.jTextArea1.text")); // NOI18N
|
||||
|
||||
GroupLayout placeHolderPanelLayout = new GroupLayout(placeHolderPanel);
|
||||
placeHolderPanel.setLayout(placeHolderPanelLayout);
|
||||
placeHolderPanelLayout.setHorizontalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING)
|
||||
.add(placeHolderPanelLayout.createSequentialGroup()
|
||||
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(jTextArea1, GroupLayout.PREFERRED_SIZE, 424, GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
placeHolderPanelLayout.setVerticalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING)
|
||||
.add(placeHolderPanelLayout.createSequentialGroup()
|
||||
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(jTextArea1, GroupLayout.PREFERRED_SIZE, 47, GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
borderLayoutPanel.add(placeHolderPanel, BorderLayout.CENTER);
|
||||
|
||||
jLabel1.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.jLabel1.text")); // NOI18N
|
||||
|
||||
hierarchyLayoutButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.hierarchyLayoutButton.text")); // NOI18N
|
||||
hierarchyLayoutButton.setFocusable(false);
|
||||
hierarchyLayoutButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||
hierarchyLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
||||
hierarchyLayoutButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
hierarchyLayoutButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
fastOrganicLayoutButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.text")); // NOI18N
|
||||
fastOrganicLayoutButton.setFocusable(false);
|
||||
fastOrganicLayoutButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||
fastOrganicLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
||||
fastOrganicLayoutButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
fastOrganicLayoutButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
organicLayoutButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.organicLayoutButton.text")); // NOI18N
|
||||
organicLayoutButton.setFocusable(false);
|
||||
organicLayoutButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||
organicLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
||||
organicLayoutButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
organicLayoutButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
circleLayoutButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.circleLayoutButton.text")); // NOI18N
|
||||
circleLayoutButton.setFocusable(false);
|
||||
circleLayoutButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||
circleLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
||||
circleLayoutButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
circleLayoutButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
zoomOutButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out-red.png"))); // NOI18N
|
||||
zoomOutButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.text")); // NOI18N
|
||||
zoomOutButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.toolTipText")); // NOI18N
|
||||
zoomOutButton.setFocusable(false);
|
||||
zoomOutButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||
zoomOutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
||||
zoomOutButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
zoomOutButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
zoomInButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png"))); // NOI18N
|
||||
zoomInButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.text")); // NOI18N
|
||||
zoomInButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.toolTipText")); // NOI18N
|
||||
zoomInButton.setFocusable(false);
|
||||
zoomInButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||
zoomInButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
||||
zoomInButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
zoomInButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
zoomActualButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png"))); // NOI18N
|
||||
zoomActualButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.text")); // NOI18N
|
||||
zoomActualButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.toolTipText")); // NOI18N
|
||||
zoomActualButton.setFocusable(false);
|
||||
zoomActualButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||
zoomActualButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
||||
zoomActualButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
zoomActualButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
fitZoomButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png"))); // NOI18N
|
||||
fitZoomButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.text")); // NOI18N
|
||||
fitZoomButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.toolTipText")); // NOI18N
|
||||
fitZoomButton.setFocusable(false);
|
||||
fitZoomButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||
fitZoomButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
||||
fitZoomButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
fitZoomButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
jLabel2.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.jLabel2.text")); // NOI18N
|
||||
|
||||
zoomLabel.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomLabel.text")); // NOI18N
|
||||
|
||||
GroupLayout toolbarLayout = new GroupLayout(toolbar);
|
||||
toolbar.setLayout(toolbarLayout);
|
||||
toolbarLayout.setHorizontalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING)
|
||||
.add(toolbarLayout.createSequentialGroup()
|
||||
.add(3, 3, 3)
|
||||
.add(jLabel1)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(fastOrganicLayoutButton)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(organicLayoutButton)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(hierarchyLayoutButton)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(circleLayoutButton)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(jSeparator1, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(zoomOutButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(zoomInButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(zoomActualButton, GroupLayout.PREFERRED_SIZE, 33, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(fitZoomButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(jLabel2)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(zoomLabel)
|
||||
.add(27, 27, 27))
|
||||
);
|
||||
toolbarLayout.setVerticalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING)
|
||||
.add(toolbarLayout.createSequentialGroup()
|
||||
.add(3, 3, 3)
|
||||
.add(toolbarLayout.createParallelGroup(GroupLayout.CENTER)
|
||||
.add(jLabel1, GroupLayout.PREFERRED_SIZE, 25, GroupLayout.PREFERRED_SIZE)
|
||||
.add(hierarchyLayoutButton)
|
||||
.add(fastOrganicLayoutButton)
|
||||
.add(organicLayoutButton)
|
||||
.add(circleLayoutButton)
|
||||
.add(jSeparator1, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(zoomOutButton)
|
||||
.add(zoomInButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(zoomActualButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(fitZoomButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(jLabel2)
|
||||
.add(zoomLabel))
|
||||
.add(3, 3, 3))
|
||||
);
|
||||
|
||||
borderLayoutPanel.add(toolbar, BorderLayout.PAGE_START);
|
||||
|
||||
splitPane.setLeftComponent(borderLayoutPanel);
|
||||
|
||||
add(splitPane, BorderLayout.CENTER);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void fitZoomButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_fitZoomButtonActionPerformed
|
||||
fitGraph();
|
||||
}//GEN-LAST:event_fitZoomButtonActionPerformed
|
||||
|
||||
private void zoomActualButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_zoomActualButtonActionPerformed
|
||||
graphComponent.zoomActual();
|
||||
}//GEN-LAST:event_zoomActualButtonActionPerformed
|
||||
|
||||
private void zoomInButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_zoomInButtonActionPerformed
|
||||
graphComponent.zoomIn();
|
||||
}//GEN-LAST:event_zoomInButtonActionPerformed
|
||||
|
||||
private void zoomOutButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_zoomOutButtonActionPerformed
|
||||
graphComponent.zoomOut();
|
||||
}//GEN-LAST:event_zoomOutButtonActionPerformed
|
||||
|
||||
private void circleLayoutButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_circleLayoutButtonActionPerformed
|
||||
morph(circleLayout);
|
||||
}//GEN-LAST:event_circleLayoutButtonActionPerformed
|
||||
|
||||
private void organicLayoutButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_organicLayoutButtonActionPerformed
|
||||
applyOrganicLayout(10);
|
||||
}//GEN-LAST:event_organicLayoutButtonActionPerformed
|
||||
|
||||
private void fastOrganicLayoutButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_fastOrganicLayoutButtonActionPerformed
|
||||
morph(fastOrganicLayout);
|
||||
}//GEN-LAST:event_fastOrganicLayoutButtonActionPerformed
|
||||
|
||||
private void hierarchyLayoutButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_hierarchyLayoutButtonActionPerformed
|
||||
morph(hierarchicalLayout);
|
||||
}//GEN-LAST:event_hierarchyLayoutButtonActionPerformed
|
||||
|
||||
private void applyOrganicLayout(int iterations) {
|
||||
organicLayout.setMaxIterations(iterations);
|
||||
morph(organicLayout);
|
||||
}
|
||||
|
||||
private void fitGraph() {
|
||||
graphComponent.zoomTo(1, true);
|
||||
mxPoint translate = graph.getView().getTranslate();
|
||||
if (translate == null || Double.isNaN(translate.getX()) || Double.isNaN(translate.getY())) {
|
||||
translate = new mxPoint();
|
||||
}
|
||||
|
||||
mxRectangle boundsForCells = graph.getCellBounds(graph.getDefaultParent(), true, true, true);
|
||||
if (boundsForCells == null || Double.isNaN(boundsForCells.getWidth()) || Double.isNaN(boundsForCells.getHeight())) {
|
||||
boundsForCells = new mxRectangle(0, 0, 1, 1);
|
||||
}
|
||||
final mxPoint mxPoint = new mxPoint(translate.getX() - boundsForCells.getX(), translate.getY() - boundsForCells.getY());
|
||||
|
||||
graph.cellsMoved(graph.getChildCells(graph.getDefaultParent()), mxPoint.getX(), mxPoint.getY(), false, false);
|
||||
|
||||
boundsForCells = graph.getCellBounds(graph.getDefaultParent(), true, true, true);
|
||||
if (boundsForCells == null || Double.isNaN(boundsForCells.getWidth()) || Double.isNaN(boundsForCells.getHeight())) {
|
||||
boundsForCells = new mxRectangle(0, 0, 1, 1);
|
||||
}
|
||||
|
||||
final Dimension size = graphComponent.getSize();
|
||||
final double widthFactor = size.getWidth() / boundsForCells.getWidth();
|
||||
|
||||
graphComponent.zoom(widthFactor);
|
||||
|
||||
}
|
||||
|
||||
private void morph(mxIGraphLayout layout) {
|
||||
// layout using morphing
|
||||
graph.getModel().beginUpdate();
|
||||
|
||||
CancelationListener cancelationListener = new CancelationListener();
|
||||
ModalDialogProgressIndicator progress = new ModalDialogProgressIndicator(windowAncestor, "Computing layout", new String[]{CANCEL}, CANCEL, cancelationListener);
|
||||
SwingWorker<Void, Void> morphWorker = new SwingWorker<Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground() throws Exception {
|
||||
progress.start("Computing layout");
|
||||
layout.execute(graph.getDefaultParent());
|
||||
if (isCancelled()) {
|
||||
progress.finish();
|
||||
return null;
|
||||
}
|
||||
mxMorphing morph = new mxMorphing(graphComponent, 20, 1.2, 20) {
|
||||
@Override
|
||||
public void updateAnimation() {
|
||||
fireEvent(new mxEventObject(mxEvent.EXECUTE));
|
||||
super.updateAnimation(); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
};
|
||||
morph.addListener(mxEvent.EXECUTE, (Object sender, mxEventObject evt) -> {
|
||||
if (isCancelled()) {
|
||||
morph.stopAnimation();
|
||||
}
|
||||
});
|
||||
morph.addListener(mxEvent.DONE, (Object sender, mxEventObject event) -> {
|
||||
graph.getModel().endUpdate();
|
||||
if (isCancelled()) {
|
||||
undoManager.undo();
|
||||
} else {
|
||||
fitGraph();
|
||||
}
|
||||
progress.finish();
|
||||
});
|
||||
|
||||
morph.startAnimation();
|
||||
return null;
|
||||
|
||||
}
|
||||
};
|
||||
cancelationListener.configure(morphWorker, progress);
|
||||
morphWorker.execute();
|
||||
}
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private JPanel borderLayoutPanel;
|
||||
private JButton circleLayoutButton;
|
||||
private JButton fastOrganicLayoutButton;
|
||||
private JButton fitZoomButton;
|
||||
private JButton hierarchyLayoutButton;
|
||||
private JLabel jLabel1;
|
||||
private JLabel jLabel2;
|
||||
private JToolBar.Separator jSeparator1;
|
||||
private JTextArea jTextArea1;
|
||||
private JButton organicLayoutButton;
|
||||
private JPanel placeHolderPanel;
|
||||
private JSplitPane splitPane;
|
||||
private JPanel toolbar;
|
||||
private JButton zoomActualButton;
|
||||
private JButton zoomInButton;
|
||||
private JLabel zoomLabel;
|
||||
private JButton zoomOutButton;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
final private class SelectionListener implements mxEventSource.mxIEventListener {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void invoke(Object sender, mxEventObject evt) {
|
||||
Object[] selectionCells = graph.getSelectionCells();
|
||||
Node rootNode = Node.EMPTY;
|
||||
Node[] selectedNodes = new Node[0];
|
||||
if (selectionCells.length > 0) {
|
||||
mxICell[] selectedCells = Arrays.asList(selectionCells).toArray(new mxCell[selectionCells.length]);
|
||||
HashSet<Content> relationshipSources = new HashSet<>();
|
||||
HashSet<AccountDeviceInstance> adis = new HashSet<>();
|
||||
for (mxICell cell : selectedCells) {
|
||||
if (cell.isEdge()) {
|
||||
mxICell source = (mxICell) graph.getModel().getTerminal(cell, true);
|
||||
AccountDeviceInstanceKey account1 = (AccountDeviceInstanceKey) source.getValue();
|
||||
mxICell target = (mxICell) graph.getModel().getTerminal(cell, false);
|
||||
AccountDeviceInstanceKey account2 = (AccountDeviceInstanceKey) target.getValue();
|
||||
try {
|
||||
final List<Content> relationshipSources1 = commsManager.getRelationshipSources(
|
||||
account1.getAccountDeviceInstance(),
|
||||
account2.getAccountDeviceInstance(),
|
||||
currentFilter);
|
||||
relationshipSources.addAll(relationshipSources1);
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.SEVERE, " Error getting relationsips....", tskCoreException);
|
||||
}
|
||||
} else if (cell.isVertex()) {
|
||||
adis.add(((AccountDeviceInstanceKey) cell.getValue()).getAccountDeviceInstance());
|
||||
}
|
||||
}
|
||||
|
||||
rootNode = SelectionNode.createFromAccountsAndRelationships(relationshipSources, adis, currentFilter, commsManager);
|
||||
selectedNodes = new Node[]{rootNode};
|
||||
}
|
||||
vizEM.setRootContext(rootNode);
|
||||
try {
|
||||
vizEM.setSelectedNodes(selectedNodes);
|
||||
} catch (PropertyVetoException ex) {
|
||||
logger.log(Level.SEVERE, "Selection vetoed.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final private class mxFastOrganicLayoutImpl extends mxFastOrganicLayout {
|
||||
|
||||
mxFastOrganicLayoutImpl(mxGraph graph) {
|
||||
super(graph);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVertexIgnored(Object vertex) {
|
||||
return super.isVertexIgnored(vertex)
|
||||
|| lockedVertexModel.isVertexLocked((mxCell) vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public mxRectangle setVertexLocation(Object vertex, double x, double y) {
|
||||
if (isVertexIgnored(vertex)) {
|
||||
return getVertexBounds(vertex);
|
||||
} else {
|
||||
return super.setVertexLocation(vertex, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final private class mxCircleLayoutImpl extends mxCircleLayout {
|
||||
|
||||
mxCircleLayoutImpl(mxGraph graph) {
|
||||
super(graph);
|
||||
setResetEdges(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVertexIgnored(Object vertex) {
|
||||
return super.isVertexIgnored(vertex)
|
||||
|| lockedVertexModel.isVertexLocked((mxCell) vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public mxRectangle setVertexLocation(Object vertex, double x, double y) {
|
||||
if (isVertexIgnored(vertex)) {
|
||||
return getVertexBounds(vertex);
|
||||
} else {
|
||||
return super.setVertexLocation(vertex, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final private class mxOrganicLayoutImpl extends mxOrganicLayout {
|
||||
|
||||
mxOrganicLayoutImpl(mxGraph graph) {
|
||||
super(graph);
|
||||
setResetEdges(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVertexIgnored(Object vertex) {
|
||||
return super.isVertexIgnored(vertex)
|
||||
|| lockedVertexModel.isVertexLocked((mxCell) vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public mxRectangle setVertexLocation(Object vertex, double x, double y) {
|
||||
if (isVertexIgnored(vertex)) {
|
||||
return getVertexBounds(vertex);
|
||||
} else {
|
||||
return super.setVertexLocation(vertex, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final private class mxHierarchicalLayoutImpl extends mxHierarchicalLayout {
|
||||
|
||||
mxHierarchicalLayoutImpl(mxGraph graph) {
|
||||
super(graph);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVertexIgnored(Object vertex) {
|
||||
return super.isVertexIgnored(vertex)
|
||||
|| lockedVertexModel.isVertexLocked((mxCell) vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public mxRectangle setVertexLocation(Object vertex, double x, double y) {
|
||||
if (isVertexIgnored(vertex)) {
|
||||
return getVertexBounds(vertex);
|
||||
} else {
|
||||
return super.setVertexLocation(vertex, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CancelationListener implements ActionListener {
|
||||
|
||||
private Future<?> cancellable;
|
||||
private ModalDialogProgressIndicator progress;
|
||||
|
||||
void configure(Future<?> cancellable, ModalDialogProgressIndicator progress) {
|
||||
this.cancellable = cancellable;
|
||||
this.progress = progress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
progress.setCancelling("Cancelling...");
|
||||
cancellable.cancel(true);
|
||||
progress.finish();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 691 B |
Before Width: | Height: | Size: 536 B |
After Width: | Height: | Size: 663 B |
After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 615 B |
After Width: | Height: | Size: 680 B |
After Width: | Height: | Size: 657 B |
After Width: | Height: | Size: 672 B |
After Width: | Height: | Size: 695 B |
After Width: | Height: | Size: 567 B |
After Width: | Height: | Size: 660 B |
After Width: | Height: | Size: 497 B |
After Width: | Height: | Size: 656 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/marker.png
Normal file
After Width: | Height: | Size: 622 B |
Before Width: | Height: | Size: 928 B |
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-15 Basis Technology Corp.
|
||||
* Copyright 2013-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -59,6 +59,7 @@ import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.openide.util.lookup.ServiceProviders;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.Installer;
|
||||
import org.sleuthkit.autopsy.corecomponents.FrameCapture;
|
||||
import org.sleuthkit.autopsy.corecomponents.VideoFrame;
|
||||
@ -136,7 +137,13 @@ public class FXVideoPanel extends MediaViewVideoPanel {
|
||||
mediaPane.setInfoLabelText(path);
|
||||
mediaPane.setInfoLabelToolTipText(path);
|
||||
|
||||
final File tempFile = VideoUtils.getTempVideoFile(currentFile);
|
||||
final File tempFile;
|
||||
try {
|
||||
tempFile = VideoUtils.getTempVideoFile(currentFile);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
|
||||
return;
|
||||
}
|
||||
|
||||
new Thread(mediaPane.new ExtractMedia(currentFile, tempFile)).start();
|
||||
|
||||
|
@ -36,7 +36,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.FileTypeViewer;
|
||||
/**
|
||||
* Generic Application content viewer
|
||||
*/
|
||||
@ServiceProvider(service = DataContentViewer.class, position = 5)
|
||||
@ServiceProvider(service = DataContentViewer.class, position = 3)
|
||||
public class FileViewer extends javax.swing.JPanel implements DataContentViewer {
|
||||
|
||||
private static final int CONFIDENCE_LEVEL = 7;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-15 Basis Technology Corp.
|
||||
* Copyright 2013-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -55,6 +55,7 @@ import org.netbeans.api.progress.ProgressHandle;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.openide.util.lookup.ServiceProviders;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.corecomponents.FrameCapture;
|
||||
import org.sleuthkit.autopsy.corecomponents.VideoFrame;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
@ -181,6 +182,7 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
}
|
||||
|
||||
@Override
|
||||
@NbBundle.Messages ({"GstVideoPanel.noOpenCase.errMsg=No open case available."})
|
||||
void setupVideo(final AbstractFile file, final Dimension dims) {
|
||||
reset();
|
||||
infoLabel.setText("");
|
||||
@ -194,6 +196,18 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
return;
|
||||
}
|
||||
|
||||
java.io.File ioFile;
|
||||
try {
|
||||
ioFile = VideoUtils.getTempVideoFile(file);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
|
||||
infoLabel.setText(Bundle.GstVideoPanel_noOpenCase_errMsg());
|
||||
pauseButton.setEnabled(false);
|
||||
progressSlider.setEnabled(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
String path = "";
|
||||
try {
|
||||
path = file.getUniquePath();
|
||||
@ -205,7 +219,6 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
pauseButton.setEnabled(true);
|
||||
progressSlider.setEnabled(true);
|
||||
|
||||
java.io.File ioFile = VideoUtils.getTempVideoFile(file);
|
||||
|
||||
gstVideoComponent = new VideoComponent();
|
||||
synchronized (playbinLock) {
|
||||
@ -537,7 +550,14 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
return;
|
||||
}
|
||||
} else if (state.equals(State.READY)) {
|
||||
final File tempVideoFile = VideoUtils.getTempVideoFile(currentFile);
|
||||
final File tempVideoFile;
|
||||
try {
|
||||
tempVideoFile = VideoUtils.getTempVideoFile(currentFile);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.WARNING, "Exception while getting open case."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
return;
|
||||
}
|
||||
|
||||
new ExtractMedia(currentFile, tempVideoFile).execute();
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017 Basis Technology Corp.
|
||||
* Copyright 2017-18 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -70,7 +70,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
/**
|
||||
* Shows SMS/MMS/EMail messages
|
||||
*/
|
||||
@ServiceProvider(service = DataContentViewer.class, position = 4)
|
||||
@ServiceProvider(service = DataContentViewer.class, position = 5)
|
||||
public class MessageContentViewer extends javax.swing.JPanel implements DataContentViewer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@ -90,7 +90,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
||||
*/
|
||||
private BlackboardArtifact artifact;
|
||||
private final DataResultPanel drp;
|
||||
private final ExplorerManager drpExplorerManager;
|
||||
private ExplorerManager drpExplorerManager;
|
||||
|
||||
/**
|
||||
* Creates new MessageContentViewer
|
||||
@ -108,6 +108,12 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
||||
Utilities.configureTextPaneAsRtf(rtfbodyTextPane);
|
||||
resetComponent();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify(); //To change body of generated methods, choose Tools | Templates.
|
||||
|
||||
drp.open();
|
||||
drpExplorerManager = drp.getExplorerManager();
|
||||
drpExplorerManager.addPropertyChangeListener(evt ->
|
||||
@ -706,7 +712,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
||||
private static class AttachmentNode extends FileNode {
|
||||
|
||||
AttachmentNode(AbstractFile file) {
|
||||
super(file, true);
|
||||
super(file, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -35,7 +35,7 @@ import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
||||
* shows the same data that can also be found in the ResultViewer table, just a
|
||||
* different order and allows the full path to be visible in the bottom area.
|
||||
*/
|
||||
@ServiceProvider(service = DataContentViewer.class, position = 3)
|
||||
@ServiceProvider(service = DataContentViewer.class, position = 6)
|
||||
public class Metadata extends javax.swing.JPanel implements DataContentViewer {
|
||||
|
||||
/**
|
||||
|
@ -35,11 +35,13 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
@ -50,7 +52,9 @@ import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.xml.sax.SAXException;
|
||||
@ -186,8 +190,21 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E
|
||||
*/
|
||||
private void exportButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportButtonActionPerformed
|
||||
|
||||
Case openCase;
|
||||
try {
|
||||
openCase = Case.getOpenCase();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
"Failed to export plist file.",
|
||||
Bundle.PListViewer_ExportFailed_message(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
|
||||
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
final JFileChooser fileChooser = new JFileChooser();
|
||||
fileChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory()));
|
||||
fileChooser.setCurrentDirectory(new File(openCase.getExportDirectory()));
|
||||
fileChooser.setFileFilter(new FileNameExtensionFilter("XML file", "xml"));
|
||||
|
||||
final int returnVal = fileChooser.showSaveDialog(this);
|
||||
@ -262,35 +279,50 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
@NbBundle.Messages({"PListViewer.processPlist.interruptedMessage=Interrupted while parsing/displaying plist file.",
|
||||
"PListViewer.processPlist.errorMessage=Error while parsing/displaying plist file."})
|
||||
private void processPlist(final AbstractFile plistFile) {
|
||||
|
||||
final byte[] plistFileBuf = new byte[(int) plistFile.getSize()];
|
||||
try {
|
||||
plistFile.read(plistFileBuf, 0, plistFile.getSize());
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error reading bytes of plist file.", ex);
|
||||
}
|
||||
|
||||
final List<PropKeyValue> plist;
|
||||
try {
|
||||
plist = parsePList(plistFileBuf);
|
||||
new SwingWorker<Void, Void>() {
|
||||
new SwingWorker<List<PropKeyValue>, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground() {
|
||||
setupTable(plist);
|
||||
return null;
|
||||
protected List<PropKeyValue> doInBackground() throws TskCoreException, IOException, PropertyListFormatException, ParseException, ParserConfigurationException, SAXException {
|
||||
// Read in and parse the file
|
||||
final byte[] plistFileBuf = new byte[(int) plistFile.getSize()];
|
||||
plistFile.read(plistFileBuf, 0, plistFile.getSize());
|
||||
final List<PropKeyValue> plist = parsePList(plistFileBuf);
|
||||
|
||||
return plist;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
super.done();
|
||||
List<PropKeyValue> plist;
|
||||
try {
|
||||
plist = get();
|
||||
setupTable(plist);
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
setColumnWidths();
|
||||
});
|
||||
} catch (InterruptedException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Interruption while parsing/dislaying plist file " + plistFile.getName(), ex);
|
||||
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
ex.getMessage(),
|
||||
Bundle.PListViewer_processPlist_interruptedMessage(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
|
||||
} catch (ExecutionException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while parsing/dislaying plist file " + plistFile.getName(), ex);
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
ex.getCause().getMessage(),
|
||||
Bundle.PListViewer_processPlist_errorMessage(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
}
|
||||
}.execute();
|
||||
|
||||
} catch (IOException | PropertyListFormatException | ParseException | ParserConfigurationException | SAXException ex) {
|
||||
LOGGER.log(Level.SEVERE, String.format("Error parsing plist for file (obj_id = %d)", plistFile.getId()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,9 +39,13 @@ import java.util.TreeMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||
import org.sleuthkit.autopsy.casemodule.services.Services;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
@ -50,32 +54,27 @@ import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.FileTypeViewer;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
|
||||
/**
|
||||
* A file content viewer for SQLITE db files.
|
||||
*
|
||||
* A file content viewer for SQLite database files.
|
||||
*/
|
||||
public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
public static final String[] SUPPORTED_MIMETYPES = new String[]{"application/x-sqlite3"};
|
||||
private static final Logger LOGGER = Logger.getLogger(FileViewer.class.getName());
|
||||
private Connection connection = null;
|
||||
|
||||
private String tmpDBPathName = null;
|
||||
private File tmpDBFile = null;
|
||||
|
||||
private final Map<String, String> dbTablesMap = new TreeMap<>();
|
||||
|
||||
private static final int ROWS_PER_PAGE = 100;
|
||||
private static final Logger logger = Logger.getLogger(FileViewer.class.getName());
|
||||
private final SQLiteTableView selectedTableView = new SQLiteTableView();
|
||||
private AbstractFile sqliteDbFile;
|
||||
private File tmpDbFile;
|
||||
private Connection connection;
|
||||
private int numRows; // num of rows in the selected table
|
||||
private int currPage = 0; // curr page of rows being displayed
|
||||
|
||||
SQLiteTableView selectedTableView = new SQLiteTableView();
|
||||
private SwingWorker<? extends Object, ? extends Object> worker;
|
||||
|
||||
|
||||
/**
|
||||
* Creates new form SQLiteViewer
|
||||
* Constructs a file content viewer for SQLite database files.
|
||||
*/
|
||||
public SQLiteViewer() {
|
||||
initComponents();
|
||||
@ -214,7 +213,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed
|
||||
|
||||
currPage++;
|
||||
if (currPage * ROWS_PER_PAGE > numRows) {
|
||||
nextPageButton.setEnabled(false);
|
||||
@ -228,7 +226,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
}//GEN-LAST:event_nextPageButtonActionPerformed
|
||||
|
||||
private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed
|
||||
|
||||
currPage--;
|
||||
if (currPage == 1) {
|
||||
prevPageButton.setEnabled(false);
|
||||
@ -247,7 +244,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
if (null == tableName) {
|
||||
return;
|
||||
}
|
||||
|
||||
selectTable(tableName);
|
||||
}//GEN-LAST:event_tablesDropdownListActionPerformed
|
||||
|
||||
@ -273,7 +269,8 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
|
||||
@Override
|
||||
public void setFile(AbstractFile file) {
|
||||
processSQLiteFile(file);
|
||||
sqliteDbFile = file;
|
||||
processSQLiteFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -283,9 +280,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
|
||||
@Override
|
||||
public void resetComponent() {
|
||||
|
||||
dbTablesMap.clear();
|
||||
|
||||
tablesDropdownList.setEnabled(true);
|
||||
tablesDropdownList.removeAllItems();
|
||||
numEntriesField.setText("");
|
||||
@ -296,146 +290,151 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
connection.close();
|
||||
connection = null;
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to close DB connection to file.", ex); //NON-NLS
|
||||
logger.log(Level.SEVERE, "Failed to close DB connection to file.", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
// delete last temp file
|
||||
if (null != tmpDBFile) {
|
||||
tmpDBFile.delete();
|
||||
tmpDBFile = null;
|
||||
if (null != tmpDbFile) {
|
||||
tmpDbFile.delete();
|
||||
tmpDbFile = null;
|
||||
}
|
||||
|
||||
sqliteDbFile = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the given SQLite DB file
|
||||
*
|
||||
* @param sqliteFile -
|
||||
*
|
||||
* @return none
|
||||
* Process the given SQLite DB file.
|
||||
*/
|
||||
private void processSQLiteFile(AbstractFile sqliteFile) {
|
||||
|
||||
@NbBundle.Messages({
|
||||
"SQLiteViewer.comboBox.noTableEntry=No tables found",
|
||||
"SQLiteViewer.errorMessage.interrupted=The processing of the file was interrupted.",
|
||||
"SQLiteViewer.errorMessage.noCurrentCase=The case has been closed.",
|
||||
"SQLiteViewer.errorMessage.failedToExtractFile=The file could not be extracted from the data source.",
|
||||
"SQLiteViewer.errorMessage.failedToQueryDatabase=The database tables in the file could not be read.",
|
||||
"SQLiteViewer.errorMessage.failedToinitJDBCDriver=The JDBC driver for SQLite could not be loaded.",
|
||||
"# {0} - exception message", "SQLiteViewer.errorMessage.unexpectedError=An unexpected error occurred:\n{0).",})
|
||||
private void processSQLiteFile() {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
tablesDropdownList.removeAllItems();
|
||||
|
||||
new SwingWorker<Boolean, Void>() {
|
||||
});
|
||||
new SwingWorker<Map<String, String>, Void>() {
|
||||
@Override
|
||||
protected Boolean doInBackground() throws Exception {
|
||||
|
||||
try {
|
||||
protected Map<String, String> doInBackground() throws NoCurrentCaseException, TskCoreException, IOException, SQLException, ClassNotFoundException {
|
||||
// Copy the file to temp folder
|
||||
tmpDBPathName = Case.getCurrentCase().getTempDirectory() + File.separator + sqliteFile.getName();
|
||||
tmpDBFile = new File(tmpDBPathName);
|
||||
ContentUtils.writeToFile(sqliteFile, tmpDBFile);
|
||||
String tmpDBPathName = Case.getOpenCase().getTempDirectory() + File.separator + sqliteDbFile.getName();
|
||||
tmpDbFile = new File(tmpDBPathName);
|
||||
ContentUtils.writeToFile(sqliteDbFile, tmpDbFile);
|
||||
|
||||
// look for any meta files associated with this DB - WAL, SHM
|
||||
findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-wal");
|
||||
findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-shm");
|
||||
// Look for any meta files associated with this DB - WAL, SHM, etc.
|
||||
findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-wal");
|
||||
findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-shm");
|
||||
|
||||
// Open copy using JDBC
|
||||
Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver
|
||||
// Load the SQLite JDBC driver, if necessary.
|
||||
Class.forName("org.sqlite.JDBC"); //NON-NLS
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + tmpDBPathName); //NON-NLS
|
||||
|
||||
// Read all table names and schema
|
||||
// Query the file for the table names and schemas.
|
||||
return getTables();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to copy DB file.", ex); //NON-NLS
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to Open DB.", ex); //NON-NLS
|
||||
} catch (ClassNotFoundException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to initialize JDBC Sqlite.", ex); //NON-NLS
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
super.done();
|
||||
try {
|
||||
boolean status = get();
|
||||
if ((status == true) && (dbTablesMap.size() > 0)) {
|
||||
Map<String, String> dbTablesMap = get();
|
||||
if (dbTablesMap.isEmpty()) {
|
||||
tablesDropdownList.addItem(Bundle.SQLiteViewer_comboBox_noTableEntry());
|
||||
tablesDropdownList.setEnabled(false);
|
||||
} else {
|
||||
dbTablesMap.keySet().forEach((tableName) -> {
|
||||
tablesDropdownList.addItem(tableName);
|
||||
});
|
||||
} else {
|
||||
// Populate error message
|
||||
tablesDropdownList.addItem("No tables found");
|
||||
tablesDropdownList.setEnabled(false);
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unexpected exception while opening DB file", ex); //NON-NLS
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Interrupted while opening SQLite database file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
|
||||
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_interrupted());
|
||||
} catch (ExecutionException ex) {
|
||||
String errorMessage;
|
||||
Throwable cause = ex.getCause();
|
||||
if (cause instanceof NoCurrentCaseException) {
|
||||
logger.log(Level.SEVERE, "Current case has been closed", ex); //NON-NLS
|
||||
errorMessage = Bundle.SQLiteViewer_errorMessage_noCurrentCase();
|
||||
} else if (cause instanceof TskCoreException || cause instanceof IOException) {
|
||||
logger.log(Level.SEVERE, String.format("Failed to create temp copy of DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
|
||||
errorMessage = Bundle.SQLiteViewer_errorMessage_failedToExtractFile();
|
||||
} else if (cause instanceof SQLException) {
|
||||
logger.log(Level.SEVERE, String.format("Failed to get tables from DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
|
||||
errorMessage = Bundle.SQLiteViewer_errorMessage_failedToQueryDatabase();
|
||||
} else if (cause instanceof ClassNotFoundException) {
|
||||
logger.log(Level.SEVERE, String.format("Failed to initialize JDBC SQLite '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
|
||||
errorMessage = Bundle.SQLiteViewer_errorMessage_failedToinitJDBCDriver();
|
||||
} else {
|
||||
logger.log(Level.SEVERE, String.format("Unexpected exception while processing DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
|
||||
errorMessage = Bundle.SQLiteViewer_errorMessage_unexpectedError(cause.getLocalizedMessage());
|
||||
}
|
||||
MessageNotifyUtil.Message.error(errorMessage);
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a meta file associated with the give SQLite db
|
||||
* If found, copies the file to the temp folder
|
||||
* Searches for a meta file associated with the give SQLite db If found,
|
||||
* copies the file to the temp folder
|
||||
*
|
||||
* @param sqliteFile - SQLIte db file being processed
|
||||
* @param metaFileName name of meta file to look for
|
||||
*
|
||||
* @return true if the meta file is found and copied successfully, false otherwise
|
||||
*/
|
||||
private boolean findAndCopySQLiteMetaFile(AbstractFile sqliteFile, String metaFileName ) {
|
||||
|
||||
SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase();
|
||||
private void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException {
|
||||
Case openCase = Case.getOpenCase();
|
||||
SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase();
|
||||
Services services = new Services(sleuthkitCase);
|
||||
FileManager fileManager = services.getFileManager();
|
||||
|
||||
List<AbstractFile> metaFiles = null;
|
||||
try {
|
||||
metaFiles = fileManager.findFiles(sqliteFile.getDataSource(), metaFileName, sqliteFile.getParent().getName() );
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unexpected exception while searching SQLite meta file = " + metaFileName , ex); //NON-NLS
|
||||
return false;
|
||||
}
|
||||
|
||||
List<AbstractFile> metaFiles = fileManager.findFiles(sqliteFile.getDataSource(), metaFileName, sqliteFile.getParent().getName());
|
||||
if (metaFiles != null) {
|
||||
for (AbstractFile metaFile : metaFiles) {
|
||||
String tmpMetafilePathName = Case.getCurrentCase().getTempDirectory() + File.separator + metaFile.getName();
|
||||
|
||||
String tmpMetafilePathName = openCase.getTempDirectory() + File.separator + metaFile.getName();
|
||||
File tmpMetafile = new File(tmpMetafilePathName);
|
||||
try {
|
||||
ContentUtils.writeToFile(metaFile, tmpMetafile);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unexpected exception while copying SQLite meta file = " + metaFileName , ex); //NON-NLS
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Gets the table names and their schema from loaded SQLite db file
|
||||
* Gets the table names and schemas from the SQLite database file.
|
||||
*
|
||||
* @return true if success, false otherwise
|
||||
* @return A mapping of table names to SQL CREATE TABLE statements.
|
||||
*/
|
||||
private boolean getTables() {
|
||||
|
||||
private Map<String, String> getTables() throws SQLException {
|
||||
Map<String, String> dbTablesMap = new TreeMap<>();
|
||||
Statement statement = null;
|
||||
ResultSet resultSet = null;
|
||||
try {
|
||||
Statement statement = connection.createStatement();
|
||||
|
||||
ResultSet resultSet = statement.executeQuery(
|
||||
statement = connection.createStatement();
|
||||
resultSet = statement.executeQuery(
|
||||
"SELECT name, sql FROM sqlite_master "
|
||||
+ " WHERE type= 'table' "
|
||||
+ " ORDER BY name;"); //NON-NLS
|
||||
|
||||
while (resultSet.next()) {
|
||||
String tableName = resultSet.getString("name"); //NON-NLS
|
||||
String tableSQL = resultSet.getString("sql"); //NON-NLS
|
||||
|
||||
dbTablesMap.put(tableName, tableSQL);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.log(Level.SEVERE, "Error getting table names from the DB", e); //NON-NLS
|
||||
} finally {
|
||||
if (null != resultSet) {
|
||||
resultSet.close();
|
||||
}
|
||||
return true;
|
||||
if (null != statement) {
|
||||
statement.close();
|
||||
}
|
||||
}
|
||||
return dbTablesMap;
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"# {0} - tableName",
|
||||
"SQLiteViewer.selectTable.errorText=Error getting row count for table: {0}"
|
||||
})
|
||||
private void selectTable(String tableName) {
|
||||
if (worker != null && !worker.isDone()) {
|
||||
worker.cancel(false);
|
||||
@ -446,17 +445,24 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
@Override
|
||||
protected Integer doInBackground() throws Exception {
|
||||
|
||||
Statement statement = null;
|
||||
ResultSet resultSet = null;
|
||||
try {
|
||||
Statement statement = connection.createStatement();
|
||||
ResultSet resultSet = statement.executeQuery(
|
||||
statement = connection.createStatement();
|
||||
resultSet = statement.executeQuery(
|
||||
"SELECT count (*) as count FROM " + tableName); //NON-NLS
|
||||
|
||||
return resultSet.getInt("count");
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to get data for table.", ex); //NON-NLS
|
||||
throw ex;
|
||||
} finally {
|
||||
if (null != resultSet) {
|
||||
resultSet.close();
|
||||
}
|
||||
if (null != statement) {
|
||||
statement.close();
|
||||
}
|
||||
}
|
||||
//NON-NLS
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -473,7 +479,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
|
||||
prevPageButton.setEnabled(false);
|
||||
|
||||
|
||||
if (numRows > 0) {
|
||||
nextPageButton.setEnabled(((numRows > ROWS_PER_PAGE)));
|
||||
readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
|
||||
@ -482,14 +487,26 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
selectedTableView.setupTable(Collections.emptyList());
|
||||
}
|
||||
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unexpected exception while reading table.", ex); //NON-NLS
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, "Interrupted while getting row count from table " + tableName, ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
ex.getMessage(),
|
||||
Bundle.SQLiteViewer_selectTable_errorText(tableName),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, "Unexpected exception while getting row count from table " + tableName, ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
ex.getCause().getMessage(),
|
||||
Bundle.SQLiteViewer_selectTable_errorText(tableName),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
};
|
||||
worker.execute();
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"# {0} - tableName",
|
||||
"SQLiteViewer.readTable.errorText=Error getting rows for table: {0}"})
|
||||
private void readTable(String tableName, int startRow, int numRowsToRead) {
|
||||
|
||||
if (worker != null && !worker.isDone()) {
|
||||
@ -500,9 +517,12 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
worker = new SwingWorker<ArrayList<Map<String, Object>>, Void>() {
|
||||
@Override
|
||||
protected ArrayList<Map<String, Object>> doInBackground() throws Exception {
|
||||
|
||||
Statement statement = null;
|
||||
ResultSet resultSet = null;
|
||||
try {
|
||||
Statement statement = connection.createStatement();
|
||||
ResultSet resultSet = statement.executeQuery(
|
||||
statement = connection.createStatement();
|
||||
resultSet = statement.executeQuery(
|
||||
"SELECT * FROM " + tableName
|
||||
+ " LIMIT " + Integer.toString(numRowsToRead)
|
||||
+ " OFFSET " + Integer.toString(startRow - 1)
|
||||
@ -510,10 +530,15 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
|
||||
return resultSetToArrayList(resultSet);
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to get data for table " + tableName, ex); //NON-NLS
|
||||
throw ex;
|
||||
} finally {
|
||||
if (null != resultSet) {
|
||||
resultSet.close();
|
||||
}
|
||||
if (null != statement) {
|
||||
statement.close();
|
||||
}
|
||||
}
|
||||
//NON-NLS
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -531,8 +556,18 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
} else {
|
||||
selectedTableView.setupTable(Collections.emptyList());
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unexpected exception while reading table " + tableName, ex); //NON-NLS
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, "Interrupted while reading table " + tableName, ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
ex.getMessage(),
|
||||
Bundle.SQLiteViewer_readTable_errorText(tableName),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, "Unexpected exception while reading table " + tableName, ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
ex.getCause().getMessage(),
|
||||
Bundle.SQLiteViewer_readTable_errorText(tableName),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -54,7 +54,7 @@ public class ServicesMonitor {
|
||||
|
||||
private static final String PERIODIC_TASK_THREAD_NAME = "services-monitor-periodic-task-%d"; //NON-NLS
|
||||
private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 1;
|
||||
private static final long CRASH_DETECTION_INTERVAL_MINUTES = 2;
|
||||
private static final long CRASH_DETECTION_INTERVAL_MINUTES = 15;
|
||||
|
||||
private static final Set<String> servicesList = Stream.of(ServicesMonitor.Service.values())
|
||||
.map(Service::toString)
|
||||
@ -143,7 +143,7 @@ public class ServicesMonitor {
|
||||
* services.
|
||||
*/
|
||||
periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build());
|
||||
periodicTasksExecutor.scheduleAtFixedRate(new CrashDetectionTask(), CRASH_DETECTION_INTERVAL_MINUTES, CRASH_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES);
|
||||
periodicTasksExecutor.scheduleWithFixedDelay(new CrashDetectionTask(), CRASH_DETECTION_INTERVAL_MINUTES, CRASH_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
/**
|
||||
|