3562 merge changes from develop

This commit is contained in:
William Schaefer 2018-03-15 17:18:22 -04:00
commit aa27324b57
272 changed files with 5925 additions and 2283 deletions

View File

@ -6,6 +6,13 @@
</configurations> </configurations>
<dependencies > <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.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-client" rev="2.8.0"/>
<dependency conf="core->default" org="org.apache.curator" name="curator-framework" rev="2.8.0"/> <dependency conf="core->default" org="org.apache.curator" name="curator-framework" rev="2.8.0"/>

View File

@ -3,7 +3,8 @@
<resolvers> <resolvers>
<chain name="main"> <chain name="main">
<ibiblio name="central" m2compatible="true"/> <ibiblio name="central" m2compatible="true"/>
<ibiblio name="maven.restlet.org" root="http://maven.restlet.com" 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> </chain>
</resolvers> </resolvers>
</ivysettings> </ivysettings>

View File

@ -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.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-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar
file.reference.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.jsoup-1.10.3.jar=release/modules/ext/jsoup-1.10.3.jar
file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar
file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar

View File

@ -15,6 +15,15 @@
<specification-version>1.27.1.121</specification-version> <specification-version>1.27.1.121</specification-version>
</run-dependency> </run-dependency>
</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> <dependency>
<code-name-base>org.netbeans.api.progress</code-name-base> <code-name-base>org.netbeans.api.progress</code-name-base>
<build-prerequisite/> <build-prerequisite/>
@ -349,6 +358,14 @@
<runtime-relative-path>ext/curator-framework-2.8.0.jar</runtime-relative-path> <runtime-relative-path>ext/curator-framework-2.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/curator-framework-2.8.0.jar</binary-origin> <binary-origin>release/modules/ext/curator-framework-2.8.0.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/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> <class-path-extension>
<runtime-relative-path>ext/commons-compress-1.14.jar</runtime-relative-path> <runtime-relative-path>ext/commons-compress-1.14.jar</runtime-relative-path>
<binary-origin>release/modules/ext/commons-compress-1.14.jar</binary-origin> <binary-origin>release/modules/ext/commons-compress-1.14.jar</binary-origin>

View File

@ -36,10 +36,10 @@ GetTagNameDialog.tagNameExistsTskCore.msg=The {0} tag name already exists in the
OpenLogFolder.error1=Log File Not Found: {0} OpenLogFolder.error1=Log File Not Found: {0}
OpenLogFolder.CouldNotOpenLogFolder=Could not open log folder OpenLogFolder.CouldNotOpenLogFolder=Could not open log folder
CTL_OpenLogFolder=Open Log Folder CTL_OpenLogFolder=Open Log Folder
CTL_OpenOutputFolder=Open Case Folder CTL_OpenOutputFolder=Open Output Folder
OpenOutputFolder.error1=Case Output Folder Not Found\: {0} OpenOutputFolder.error1=Output Folder Not Found\: {0}
OpenOutputFolder.noCaseOpen=No open case, therefore no current case output folder available. OpenOutputFolder.noCaseOpen=No open case, therefore no current output folder available.
OpenOutputFolder.CouldNotOpenOutputFolder=Could not open case output folder OpenOutputFolder.CouldNotOpenOutputFolder=Could not open output folder
ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot
OpenPythonModulesFolderAction.actionName.text=Python Plugins OpenPythonModulesFolderAction.actionName.text=Python Plugins
OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python plugins folder not found: {0} OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python plugins folder not found: {0}

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2018 Basis Technology Corp. * Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger; 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 * 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. 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 * 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). * This action should only be invoked in the event dispatch thread (EDT).
*/ */
@ActionRegistration(displayName = "#CTL_OpenOutputFolder", iconInMenu = true, lazy = false) @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") @ActionID(id = "org.sleuthkit.autopsy.actions.OpenOutputFolderAction", category = "Help")
public final class OpenOutputFolderAction extends CallableSystemAction { public final class OpenOutputFolderAction extends CallableSystemAction {
@ -63,7 +63,7 @@ public final class OpenOutputFolderAction extends CallableSystemAction {
try { try {
Desktop.getDesktop().open(outputDir); Desktop.getDesktop().open(outputDir);
} catch (IOException ex) { } 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( NotifyDescriptor descriptor = new NotifyDescriptor.Message(
NbBundle.getMessage(this.getClass(), "OpenOutputFolder.CouldNotOpenOutputFolder", outputDir.getAbsolutePath()), NotifyDescriptor.ERROR_MESSAGE); NbBundle.getMessage(this.getClass(), "OpenOutputFolder.CouldNotOpenOutputFolder", outputDir.getAbsolutePath()), NotifyDescriptor.ERROR_MESSAGE);
DialogDisplayer.getDefault().notify(descriptor); DialogDisplayer.getDefault().notify(descriptor);

View File

@ -107,9 +107,15 @@ class AddImageTask implements Runnable {
*/ */
@Override @Override
public void run() { 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.setIndeterminate(true);
progressMonitor.setProgress(0); progressMonitor.setProgress(0);
Case currentCase = Case.getCurrentCase();
String imageWriterPath = ""; String imageWriterPath = "";
if (imageWriterSettings != null) { if (imageWriterSettings != null) {
imageWriterPath = imageWriterSettings.getPath(); imageWriterPath = imageWriterSettings.getPath();

View File

@ -29,6 +29,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent; 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.IngestManager;
import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescriptorPanel; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescriptorPanel;
import org.sleuthkit.datamodel.Content; 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 * The final panel of the add image wizard. It displays a progress bar and
@ -331,7 +333,11 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel {
cleanupTask.enable(); cleanupTask.enable();
new Thread(() -> { 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(); }).start();
DataSourceProcessorCallback cbObj = new DataSourceProcessorCallback() { DataSourceProcessorCallback cbObj = new DataSourceProcessorCallback() {
@Override @Override
@ -398,10 +404,14 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel {
//notify the UI of the new content added to the case //notify the UI of the new content added to the case
new Thread(() -> { new Thread(() -> {
if (!contents.isEmpty()) { try {
Case.getCurrentCase().notifyDataSourceAdded(contents.get(0), dataSourceId); if (!contents.isEmpty()) {
} else { Case.getOpenCase().notifyDataSourceAdded(contents.get(0), dataSourceId);
Case.getCurrentCase().notifyFailedAddingDataSource(dataSourceId); } else {
Case.getOpenCase().notifyFailedAddingDataSource(dataSourceId);
}
} catch (NoCurrentCaseException ex) {
Logger.getLogger(AddImageWizardAddingProgressVisual.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
} }
}).start(); }).start();

View File

@ -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. * Gets the current case, if there is one, at the time of the call.
* *
* @return The current case. * @return The current case.

View File

@ -66,7 +66,7 @@ final class CaseDeleteAction extends CallableSystemAction {
"# {0} - exception message", "Case.deleteCaseFailureMessageBox.message=Error deleting case: {0}",}) "# {0} - exception message", "Case.deleteCaseFailureMessageBox.message=Error deleting case: {0}",})
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
try { try {
Case currentCase = Case.getCurrentCase(); Case currentCase = Case.getOpenCase();
String caseName = currentCase.getName(); String caseName = currentCase.getName();
String caseDirectory = currentCase.getCaseDirectory(); String caseDirectory = currentCase.getCaseDirectory();
@ -110,7 +110,7 @@ final class CaseDeleteAction extends CallableSystemAction {
} }
}.execute(); }.execute();
} }
} catch (IllegalStateException ex) { } catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Case delete action called with no current case", ex); logger.log(Level.SEVERE, "Case delete action called with no current case", ex);
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2018 Basis Technology Corp. * Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -20,9 +20,11 @@ package org.sleuthkit.autopsy.casemodule;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.util.logging.Level;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
@ -51,7 +53,11 @@ class CaseInformationPanel extends javax.swing.JPanel {
"CaseInformationPanel.editDetailsDialog.title=Edit Case Details" "CaseInformationPanel.editDetailsDialog.title=Edit Case Details"
}) })
private void customizeComponents() { 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()); propertiesPanel.setSize(propertiesPanel.getPreferredSize());
this.tabbedPane.addTab(Bundle.CaseInformationPanel_caseDetails_header(), propertiesPanel); this.tabbedPane.addTab(Bundle.CaseInformationPanel_caseDetails_header(), propertiesPanel);
this.tabbedPane.addTab(Bundle.CaseInformationPanel_ingestJobInfo_header(), new IngestJobInfoPanel()); this.tabbedPane.addTab(Bundle.CaseInformationPanel_ingestJobInfo_header(), new IngestJobInfoPanel());
@ -59,11 +65,6 @@ class CaseInformationPanel extends javax.swing.JPanel {
@Override @Override
public void stateChanged(ChangeEvent e) { public void stateChanged(ChangeEvent e) {
tabbedPane.getSelectedComponent().setSize(tabbedPane.getSelectedComponent().getPreferredSize()); tabbedPane.getSelectedComponent().setSize(tabbedPane.getSelectedComponent().getPreferredSize());
if (tabbedPane.getSelectedComponent() instanceof CasePropertiesPanel) {
editDetailsButton.setVisible(true);
} else {
editDetailsButton.setVisible(false);
}
} }
}); });
} }

View File

@ -49,7 +49,12 @@ final class CasePropertiesPanel extends javax.swing.JPanel {
} }
void updateCaseInfo() { 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()); lbCaseNameText.setText(theCase.getDisplayName());
lbCaseNumberText.setText(theCase.getNumber()); lbCaseNumberText.setText(theCase.getNumber());
lbExaminerNameText.setText(theCase.getExaminer()); lbExaminerNameText.setText(theCase.getExaminer());
@ -78,9 +83,9 @@ final class CasePropertiesPanel extends javax.swing.JPanel {
try { try {
EamDb dbManager = EamDb.getInstance(); EamDb dbManager = EamDb.getInstance();
if (dbManager != null) { if (dbManager != null) {
CorrelationCase correlationCase = dbManager.getCase(Case.getCurrentCase()); CorrelationCase correlationCase = dbManager.getCase(theCase);
if (null == correlationCase) { if (null == correlationCase) {
correlationCase = dbManager.newCase(Case.getCurrentCase()); correlationCase = dbManager.newCase(theCase);
} }
currentOrg = correlationCase.getOrg(); currentOrg = correlationCase.getOrg();
} }

View File

@ -122,8 +122,8 @@ final class CollaborationMonitor {
* 2. Check for stale remote tasks.<br> * 2. Check for stale remote tasks.<br>
*/ */
periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build()); 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.scheduleWithFixedDelay(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 StaleTaskDetectionTask(), STALE_TASKS_DETECT_INTERVAL_MINS, STALE_TASKS_DETECT_INTERVAL_MINS, TimeUnit.MINUTES);
} }
/** /**

View File

@ -31,6 +31,7 @@ import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener; import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileFilter;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import static org.sleuthkit.autopsy.casemodule.Bundle.*; import static org.sleuthkit.autopsy.casemodule.Bundle.*;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; 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 * @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() { public boolean validatePanel() {
pathErrorLabel.setVisible(false); pathErrorLabel.setVisible(false);
String path = getContentPaths(); String path = getContentPaths();
@ -315,9 +318,14 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
} }
// Display warning if there is one (but don't disable "next" button) // 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.setVisible(true);
pathErrorLabel.setText(Bundle.ImageFilePanel_pathValidation_dataSourceOnCDriveError()); pathErrorLabel.setText(Bundle.ImageFilePanel_pathValidation_getOpenCase_Error());
} }
return new File(path).isFile() return new File(path).isFile()

View File

@ -75,12 +75,12 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
} }
private void refresh() { private void refresh() {
SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
try { try {
SleuthkitCase skCase = Case.getOpenCase().getSleuthkitCase();
List<IngestJobInfo> ingestJobs = skCase.getIngestJobs(); List<IngestJobInfo> ingestJobs = skCase.getIngestJobs();
this.ingestJobs = ingestJobs; this.ingestJobs = ingestJobs;
this.repaint(); this.repaint();
} catch (TskCoreException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Failed to load ingest jobs.", 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); 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 @Override
public Object getValueAt(int rowIndex, int columnIndex) { public Object getValueAt(int rowIndex, int columnIndex) {
IngestJobInfo currIngestJob = ingestJobs.get(rowIndex); IngestJobInfo currIngestJob = ingestJobs.get(rowIndex);
SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
if (columnIndex == 0) { if (columnIndex == 0) {
try { try {
SleuthkitCase skCase = Case.getOpenCase().getSleuthkitCase();
return skCase.getContentById(currIngestJob.getObjectId()).getName(); return skCase.getContentById(currIngestJob.getObjectId()).getName();
} catch (TskCoreException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Failed to get content from db", ex); logger.log(Level.SEVERE, "Failed to get content from db", ex);
return ""; return "";
} }

View File

@ -31,6 +31,7 @@ import javax.swing.JPanel;
import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileFilter;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.openide.modules.InstalledFileLocator; import org.openide.modules.InstalledFileLocator;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProvider;

View File

@ -275,17 +275,23 @@ final class LocalFilesPanel extends javax.swing.JPanel {
* *
* @param paths Absolute paths to the selected data source * @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) { private void warnIfPathIsInvalid(final List<String> pathsList) {
errorLabel.setVisible(false); errorLabel.setVisible(false);
final Case.CaseType currentCaseType = Case.getCurrentCase().getCaseType(); try {
final Case.CaseType currentCaseType = Case.getOpenCase().getCaseType();
for (String currentPath : pathsList) { for (String currentPath : pathsList) {
if (!PathValidator.isValid(currentPath, currentCaseType)) { if (!PathValidator.isValid(currentPath, currentCaseType)) {
errorLabel.setVisible(true); errorLabel.setVisible(true);
errorLabel.setText(NbBundle.getMessage(this.getClass(), "DataSourceOnCDriveError.text")); errorLabel.setText(NbBundle.getMessage(this.getClass(), "DataSourceOnCDriveError.text"));
return; return;
}
} }
} catch (NoCurrentCaseException ex) {
errorLabel.setVisible(true);
errorLabel.setText(Bundle.LocalFilesPanel_pathValidation_error());
} }
} }

View File

@ -32,6 +32,7 @@ import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener; import javax.swing.event.DocumentListener;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.autopsy.coreutils.PathValidator;
@ -178,7 +179,8 @@ final class LogicalEvidenceFilePanel extends javax.swing.JPanel implements Docum
*/ */
@Messages({ @Messages({
"LogicalEvidenceFilePanel.validatePanel.nonL01Error.text=Only files with the .l01 file extension are supported here.", "LogicalEvidenceFilePanel.validatePanel.nonL01Error.text=Only files with the .l01 file extension are supported here.",
"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() { boolean validatePanel() {
errorLabel.setVisible(false); errorLabel.setVisible(false);
@ -188,9 +190,15 @@ final class LogicalEvidenceFilePanel extends javax.swing.JPanel implements Docum
return false; return false;
} }
// display warning if there is one (but don't disable "next" button) // 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.setVisible(true);
errorLabel.setText(Bundle.LogicalEvidenceFilePanel_pathValidation_dataSourceOnCDriveError()); errorLabel.setText(Bundle.LogicalEvidenceFilePanel_pathValidation_getOpenCase_Error());
return false; return false;
} }
//check the extension incase the path was manually entered //check the extension incase the path was manually entered

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -62,12 +62,19 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
OptionalCasePropertiesPanel(boolean editCurrentCase) { OptionalCasePropertiesPanel(boolean editCurrentCase) {
initComponents(); initComponents();
if (editCurrentCase) { if (editCurrentCase) {
caseDisplayNameTextField.setText(Case.getCurrentCase().getDisplayName()); Case openCase;
caseNumberTextField.setText(Case.getCurrentCase().getNumber()); try {
examinerTextField.setText(Case.getCurrentCase().getExaminer()); openCase = Case.getOpenCase();
tfExaminerEmailText.setText(Case.getCurrentCase().getExaminerEmail()); } catch (NoCurrentCaseException ex) {
tfExaminerPhoneText.setText(Case.getCurrentCase().getExaminerPhone()); LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
taNotesText.setText(Case.getCurrentCase().getCaseNotes()); 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(); setUpCaseDetailsFields();
setUpOrganizationData(); setUpOrganizationData();
} else { } else {
@ -86,15 +93,18 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
private void setUpOrganizationData() { private void setUpOrganizationData() {
if (EamDb.isEnabled()) { if (EamDb.isEnabled()) {
Case currentCase = Case.getCurrentCase(); try {
if (currentCase != null) { Case currentCase = Case.getOpenCase();
try { if (currentCase != null) {
EamDb dbManager = EamDb.getInstance(); EamDb dbManager = EamDb.getInstance();
selectedOrg = dbManager.getCase(currentCase).getOrg(); 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 (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) { if (selectedOrg != null) {
setCurrentlySelectedOrganization(selectedOrg.getName()); setCurrentlySelectedOrganization(selectedOrg.getName());
} }
@ -533,7 +543,8 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
@Messages({ @Messages({
"OptionalCasePropertiesPanel.errorDialog.emptyCaseNameMessage=No case name entered.", "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() { void saveUpdatedCaseDetails() {
if (caseDisplayNameTextField.getText().trim().isEmpty()) { if (caseDisplayNameTextField.getText().trim().isEmpty()) {
@ -544,14 +555,19 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
MessageNotifyUtil.Message.error(Bundle.OptionalCasePropertiesPanel_errorDialog_invalidCaseNameMessage()); MessageNotifyUtil.Message.error(Bundle.OptionalCasePropertiesPanel_errorDialog_invalidCaseNameMessage());
return; return;
} }
updateCaseDetails(); try {
updateCaseDetails();
} catch (NoCurrentCaseException ex) {
MessageNotifyUtil.Message.error(Bundle.OptionalCasePropertiesPanel_errorDialog_noOpenCase_errMsg());
return;
}
updateCorrelationCase(); updateCorrelationCase();
} }
private void updateCaseDetails() { private void updateCaseDetails() throws NoCurrentCaseException {
if (caseDisplayNameTextField.isVisible()) { if (caseDisplayNameTextField.isVisible()) {
try { try {
Case.getCurrentCase().updateCaseDetails(new CaseDetails( Case.getOpenCase().updateCaseDetails(new CaseDetails(
caseDisplayNameTextField.getText(), caseNumberTextField.getText(), caseDisplayNameTextField.getText(), caseNumberTextField.getText(),
examinerTextField.getText(), tfExaminerPhoneText.getText(), examinerTextField.getText(), tfExaminerPhoneText.getText(),
tfExaminerEmailText.getText(), taNotesText.getText())); tfExaminerEmailText.getText(), taNotesText.getText()));
@ -570,7 +586,7 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
if (EamDb.isEnabled()) { if (EamDb.isEnabled()) {
try { try {
EamDb dbManager = EamDb.getInstance(); EamDb dbManager = EamDb.getInstance();
CorrelationCase correlationCase = dbManager.getCase(Case.getCurrentCase()); CorrelationCase correlationCase = dbManager.getCase(Case.getOpenCase());
if (caseDisplayNameTextField.isVisible()) { if (caseDisplayNameTextField.isVisible()) {
correlationCase.setDisplayName(caseDisplayNameTextField.getText()); correlationCase.setDisplayName(caseDisplayNameTextField.getText());
} }
@ -582,7 +598,9 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
correlationCase.setNotes(taNotesText.getText()); correlationCase.setNotes(taNotesText.getText());
dbManager.updateCase(correlationCase); dbManager.updateCase(correlationCase);
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to central repository database", ex); // NON-NLS 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 { } finally {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2015 Basis Technology Corp. * Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable; import java.io.Serializable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -41,11 +42,11 @@ public class BlackBoardArtifactTagAddedEvent extends TagAddedEvent<BlackboardArt
* *
* @return BlackboardArtifactTag that was added * @return BlackboardArtifactTag that was added
* *
* @throws IllegalStateException * @throws NoCurrentCaseException
* @throws TskCoreException * @throws TskCoreException
*/ */
@Override @Override
BlackboardArtifactTag getTagByID() throws IllegalStateException, TskCoreException { BlackboardArtifactTag getTagByID() throws NoCurrentCaseException, TskCoreException {
return Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagByTagID(getTagID()); return Case.getOpenCase().getServices().getTagsManager().getBlackboardArtifactTagByTagID(getTagID());
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2015 Basis Technology Corp. * Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable; import java.io.Serializable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -41,10 +42,10 @@ public class ContentTagAddedEvent extends TagAddedEvent<ContentTag> implements S
* *
* @return ContentTag that was added * @return ContentTag that was added
* *
* @throws IllegalStateException * @throws NoCurrentCaseException
* @throws TskCoreException * @throws TskCoreException
*/ */
ContentTag getTagByID() throws IllegalStateException, TskCoreException { ContentTag getTagByID() throws NoCurrentCaseException, TskCoreException {
return Case.getCurrentCase().getServices().getTagsManager().getContentTagByTagID(getTagID()); return Case.getOpenCase().getServices().getTagsManager().getContentTagByTagID(getTagID());
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2015 Basis Technology Corp. * Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -22,6 +22,7 @@ import java.io.Serializable;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
@ -78,9 +79,9 @@ public final class DataSourceAddedEvent extends AutopsyEvent implements Serializ
} }
try { try {
long id = (Long) super.getNewValue(); long id = (Long) super.getNewValue();
dataSource = Case.getCurrentCase().getSleuthkitCase().getContentById(id); dataSource = Case.getOpenCase().getSleuthkitCase().getContentById(id);
return dataSource; return dataSource;
} catch (IllegalStateException | TskCoreException ex) { } catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS
return null; return null;
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2015 Basis Technology Corp. * Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -22,6 +22,7 @@ import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.datamodel.Report; import org.sleuthkit.datamodel.Report;
@ -69,7 +70,7 @@ public final class ReportAddedEvent extends AutopsyEvent implements Serializable
} }
try { try {
long id = (Long) super.getNewValue(); long id = (Long) super.getNewValue();
List<Report> reports = Case.getCurrentCase().getSleuthkitCase().getAllReports(); List<Report> reports = Case.getOpenCase().getSleuthkitCase().getAllReports();
for (Report thisReport : reports) { for (Report thisReport : reports) {
if (thisReport.getId() == id) { if (thisReport.getId() == id) {
report = thisReport; report = thisReport;
@ -77,7 +78,7 @@ public final class ReportAddedEvent extends AutopsyEvent implements Serializable
} }
} }
return report; return report;
} catch (IllegalStateException | TskCoreException ex) { } catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS
return null; return null;
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2015 Basis Technology Corp. * Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable; import java.io.Serializable;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.Tag;
@ -84,7 +85,7 @@ abstract class TagAddedEvent<T extends Tag> extends AutopsyEvent implements Seri
try { try {
tag = getTagByID(); tag = getTagByID();
return tag; 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 Logger.getLogger(TagAddedEvent.class.getName()).log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS
return null; 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 * @return the Tag based on the saved tag id
* *
* @throws IllegalStateException * @throws NoCurrentCaseException
* @throws TskCoreException * @throws TskCoreException
*/ */
abstract T getTagByID() throws IllegalStateException, TskCoreException; abstract T getTagByID() throws NoCurrentCaseException, TskCoreException;
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -28,6 +28,7 @@ import java.util.logging.Level;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
@ -295,9 +296,11 @@ final class TagNameDefinition implements Comparable<TagNameDefinition> {
setting.append(";"); setting.append(";");
} }
setting.append(tagName.toSettingsFormat()); setting.append(tagName.toSettingsFormat());
if (Case.isCaseOpen()) { try {
SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase(); SleuthkitCase caseDb = Case.getOpenCase().getSleuthkitCase();
tagName.saveToCase(caseDb); 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()); ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString());

View File

@ -24,6 +24,7 @@ import java.beans.PropertyChangeListener;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.logging.Level;
import javax.swing.DefaultListModel; import javax.swing.DefaultListModel;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
@ -32,10 +33,12 @@ import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.autopsy.coreutils.Logger;
/** /**
* A panel to allow the user to create and delete custom tag types. * 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() { private void sendStatusChangedEvents() {
for (String modifiedTagDisplayName : updatedStatusTags) { 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 user closes their case after options have been changed but before application of them is complete don't notify
if (Case.isCaseOpen()) { try {
Case.getCurrentCase().notifyTagDefinitionChanged(modifiedTagDisplayName); 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(); updatedStatusTags.clear();

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -29,6 +29,7 @@ import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardArtifactTag;
@ -98,11 +99,11 @@ public class TagsManager implements Closeable {
tagDisplayNames.add(tagType.getDisplayName()); tagDisplayNames.add(tagType.getDisplayName());
}); });
try { try {
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); TagsManager tagsManager = Case.getOpenCase().getServices().getTagsManager();
for (TagName tagName : tagsManager.getAllTagNames()) { for (TagName tagName : tagsManager.getAllTagNames()) {
tagDisplayNames.add(tagName.getDisplayName()); tagDisplayNames.add(tagName.getDisplayName());
} }
} catch (IllegalStateException ignored) { } catch (NoCurrentCaseException ignored) {
/* /*
* No current case, nothing more to add to the set. * No current case, nothing more to add to the set.
*/ */
@ -339,8 +340,8 @@ public class TagsManager implements Closeable {
ContentTag tag; ContentTag tag;
tag = caseDb.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); tag = caseDb.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset);
try { try {
Case.getCurrentCase().notifyContentTagAdded(tag); Case.getOpenCase().notifyContentTagAdded(tag);
} catch (IllegalStateException ex) { } catch (NoCurrentCaseException ex) {
throw new TskCoreException("Added a tag to a closed case", ex); throw new TskCoreException("Added a tag to a closed case", ex);
} }
return tag; return tag;
@ -357,8 +358,8 @@ public class TagsManager implements Closeable {
public void deleteContentTag(ContentTag tag) throws TskCoreException { public void deleteContentTag(ContentTag tag) throws TskCoreException {
caseDb.deleteContentTag(tag); caseDb.deleteContentTag(tag);
try { try {
Case.getCurrentCase().notifyContentTagDeleted(tag); Case.getOpenCase().notifyContentTagDeleted(tag);
} catch (IllegalStateException ex) { } catch (NoCurrentCaseException ex) {
throw new TskCoreException("Deleted a tag from a closed case", 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 { public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
BlackboardArtifactTag tag = caseDb.addBlackboardArtifactTag(artifact, tagName, comment); BlackboardArtifactTag tag = caseDb.addBlackboardArtifactTag(artifact, tagName, comment);
try { try {
Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(tag); Case.getOpenCase().notifyBlackBoardArtifactTagAdded(tag);
} catch (IllegalStateException ex) { } catch (NoCurrentCaseException ex) {
throw new TskCoreException("Added a tag to a closed case", ex); throw new TskCoreException("Added a tag to a closed case", ex);
} }
return tag; return tag;
@ -487,8 +488,8 @@ public class TagsManager implements Closeable {
public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
caseDb.deleteBlackboardArtifactTag(tag); caseDb.deleteBlackboardArtifactTag(tag);
try { try {
Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); Case.getOpenCase().notifyBlackBoardArtifactTagDeleted(tag);
} catch (IllegalStateException ex) { } catch (NoCurrentCaseException ex) {
throw new TskCoreException("Deleted a tag from a closed case", ex); throw new TskCoreException("Deleted a tag from a closed case", ex);
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Central Repository * Central Repository
* *
* Copyright 2015-2017 Basis Technology Corp. * Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -46,6 +46,7 @@ import org.openide.nodes.Node;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; 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)) { } else if (jmi.equals(showCaseDetailsMenuItem)) {
showCaseDetails(otherCasesTable.getSelectedRow()); showCaseDetails(otherCasesTable.getSelectedRow());
} else if (jmi.equals(exportToCSVMenuItem)) { } else if (jmi.equals(exportToCSVMenuItem)) {
saveToCSV(); try {
saveToCSV();
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
}
} else if (jmi.equals(showCommonalityMenuItem)) { } else if (jmi.equals(showCommonalityMenuItem)) {
showCommonalityDetails(); showCommonalityDetails();
} }
@ -159,8 +164,19 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D
@Messages({"DataContentViewerOtherCases.caseDetailsDialog.notSelected=No Row Selected", @Messages({"DataContentViewerOtherCases.caseDetailsDialog.notSelected=No Row Selected",
"DataContentViewerOtherCases.caseDetailsDialog.noDetails=No details for this case.", "DataContentViewerOtherCases.caseDetailsDialog.noDetails=No details for this case.",
"DataContentViewerOtherCases.caseDetailsDialog.noDetailsReference=No case details for Global reference properties.", "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) { 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(); String caseDisplayName = Bundle.DataContentViewerOtherCases_caseDetailsDialog_noCaseNameError();
try { try {
if (-1 != selectedRowViewIdx) { if (-1 != selectedRowViewIdx) {
@ -177,7 +193,7 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D
} }
caseDisplayName = eamCasePartial.getDisplayName(); caseDisplayName = eamCasePartial.getDisplayName();
// query case details // query case details
CorrelationCase eamCase = dbManager.getCase(Case.getCurrentCase()); CorrelationCase eamCase = dbManager.getCase(openCase);
if (eamCase == null) { if (eamCase == null) {
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem, JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(), 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()) { if (0 != otherCasesTable.getSelectedRowCount()) {
Calendar now = Calendar.getInstance(); 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); 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.setSelectedFile(new File(fileName));
CSVFileChooser.setFileFilter(new FileNameExtensionFilter("csv file", "csv")); 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) { private Collection<CorrelationAttributeInstance> getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) {
// @@@ Check exception // @@@ Check exception
String caseUUID = Case.getCurrentCase().getName();
try { try {
String caseUUID = Case.getOpenCase().getName();
EamDb dbManager = EamDb.getInstance(); EamDb dbManager = EamDb.getInstance();
Collection<CorrelationAttributeInstance> artifactInstances = dbManager.getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).stream() Collection<CorrelationAttributeInstance> artifactInstances = dbManager.getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).stream()
.filter(artifactInstance -> !artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID) .filter(artifactInstance -> !artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
@ -428,6 +444,8 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D
return artifactInstances; return artifactInstances;
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS 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(); return Collections.emptyList();
@ -473,9 +491,9 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D
if (af != null) { if (af != null) {
Content dataSource = af.getDataSource(); Content dataSource = af.getDataSource();
dataSourceName = dataSource.getName(); 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. // do nothing.
// @@@ Review this behavior // @@@ Review this behavior
} }

View File

@ -2334,7 +2334,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
} }
CorrelationAttributeInstance eamArtifactInstance = new CorrelationAttributeInstance( CorrelationAttributeInstance eamArtifactInstance = new CorrelationAttributeInstance(
new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), resultSet.getString("case_name")), 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("file_path"),
resultSet.getString("comment"), resultSet.getString("comment"),
TskData.FileKnown.valueOf(resultSet.getByte("known_status")) TskData.FileKnown.valueOf(resultSet.getByte("known_status"))

View File

@ -1,7 +1,7 @@
/* /*
* Central Repository * Central Repository
* *
* Copyright 2015-2017 Basis Technology Corp. * Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.centralrepository.datamodel;
import java.io.Serializable; import java.io.Serializable;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskDataException; import org.sleuthkit.datamodel.TskDataException;
@ -73,8 +74,8 @@ public class CorrelationDataSource implements Serializable {
public static CorrelationDataSource fromTSKDataSource(CorrelationCase correlationCase, Content dataSource) throws EamDbException { public static CorrelationDataSource fromTSKDataSource(CorrelationCase correlationCase, Content dataSource) throws EamDbException {
Case curCase; Case curCase;
try { try {
curCase = Case.getCurrentCase(); curCase = Case.getOpenCase();
} catch (IllegalStateException ex) { } catch (NoCurrentCaseException ex) {
throw new EamDbException("Autopsy case is closed"); throw new EamDbException("Autopsy case is closed");
} }
String deviceId; String deviceId;

View File

@ -1,7 +1,7 @@
/* /*
* Central Repository * Central Repository
* *
* Copyright 2015-2017 Basis Technology Corp. * Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -23,6 +23,7 @@ import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; 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 they asked for it, add the instance details associated with this occurance.
if (!eamArtifacts.isEmpty() && addInstanceDetails) { if (!eamArtifacts.isEmpty() && addInstanceDetails) {
try { try {
Case currentCase = Case.getCurrentCase(); Case currentCase = Case.getOpenCase();
AbstractFile bbSourceFile = currentCase.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID()); AbstractFile bbSourceFile = currentCase.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID());
if (null == bbSourceFile) { if (null == bbSourceFile) {
//@@@ Log this //@@@ Log this
@ -97,9 +98,9 @@ public class EamArtifactUtil {
} }
// make an instance for the BB source file // 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) { if (null == correlationCase) {
correlationCase = EamDb.getInstance().newCase(Case.getCurrentCase()); correlationCase = EamDb.getInstance().newCase(Case.getOpenCase());
} }
CorrelationAttributeInstance eamInstance = new CorrelationAttributeInstance( CorrelationAttributeInstance eamInstance = new CorrelationAttributeInstance(
correlationCase, correlationCase,
@ -116,7 +117,7 @@ public class EamArtifactUtil {
} catch (TskCoreException | EamDbException ex) { } catch (TskCoreException | EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error creating artifact instance.", ex); // NON-NLS LOGGER.log(Level.SEVERE, "Error creating artifact instance.", ex); // NON-NLS
return eamArtifacts; return eamArtifacts;
} catch (IllegalStateException ex) { } catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Case is closed.", ex); // NON-NLS LOGGER.log(Level.SEVERE, "Case is closed.", ex); // NON-NLS
return eamArtifacts; return eamArtifacts;
} }
@ -145,7 +146,7 @@ public class EamArtifactUtil {
// Get the associated artifact // Get the associated artifact
BlackboardAttribute attribute = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); BlackboardAttribute attribute = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
if (attribute != null) { if (attribute != null) {
BlackboardArtifact associatedArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong()); BlackboardArtifact associatedArtifact = Case.getOpenCase().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
return EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(correlationType, associatedArtifact); return EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(correlationType, associatedArtifact);
} }
@ -203,6 +204,9 @@ public class EamArtifactUtil {
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS LOGGER.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS
return null; return null;
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
return null;
} }
if (null != value) { if (null != value) {
@ -250,9 +254,9 @@ public class EamArtifactUtil {
try { try {
CorrelationAttribute.Type filesType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID); CorrelationAttribute.Type filesType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID);
eamArtifact = new CorrelationAttribute(filesType, af.getMd5Hash()); eamArtifact = new CorrelationAttribute(filesType, af.getMd5Hash());
CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getCurrentCase()); CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getOpenCase());
if (null == correlationCase) { if (null == correlationCase) {
correlationCase = EamDb.getInstance().newCase(Case.getCurrentCase()); correlationCase = EamDb.getInstance().newCase(Case.getOpenCase());
} }
CorrelationAttributeInstance cei = new CorrelationAttributeInstance( CorrelationAttributeInstance cei = new CorrelationAttributeInstance(
correlationCase, correlationCase,
@ -263,7 +267,7 @@ public class EamArtifactUtil {
); );
eamArtifact.addInstance(cei); eamArtifact.addInstance(cei);
return eamArtifact; return eamArtifact;
} catch (TskCoreException | EamDbException ex) { } catch (TskCoreException | EamDbException | NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Error making correlation attribute.", ex); LOGGER.log(Level.SEVERE, "Error making correlation attribute.", ex);
return null; return null;
} }

View File

@ -1,7 +1,7 @@
/* /*
* Central Repository * Central Repository
* *
* Copyright 2015-2017 Basis Technology Corp. * Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -28,6 +28,7 @@ import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case; 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.BlackBoardArtifactTagAddedEvent;
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent;
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
@ -162,8 +163,8 @@ final class CaseEventListener implements PropertyChangeListener {
try { try {
// Get the remaining tags on the content object // Get the remaining tags on the content object
Content content = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID); Content content = Case.getOpenCase().getSleuthkitCase().getContentById(contentID);
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); TagsManager tagsManager = Case.getOpenCase().getServices().getTagsManager();
List<ContentTag> tags = tagsManager.getContentTagsByContent(content); List<ContentTag> tags = tagsManager.getContentTagsByContent(content);
if (tags.stream() 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 // There's still at least one bad tag, so leave the known status as is
return; return;
} }
} catch (TskCoreException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Failed to find content", ex); LOGGER.log(Level.SEVERE, "Failed to find content", ex);
return; return;
} }
@ -241,6 +242,13 @@ final class CaseEventListener implements PropertyChangeListener {
return; return;
} }
} else { //BLACKBOARD_ARTIFACT_TAG_DELETED } 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: // For deleted tags, we want to set the file status to UNKNOWN if:
// - The tag that was just removed is notable in central repo // - The tag that was just removed is notable in central repo
// - There are no remaining tags that are notable // - There are no remaining tags that are notable
@ -256,9 +264,9 @@ final class CaseEventListener implements PropertyChangeListener {
try { try {
// Get the remaining tags on the artifact // Get the remaining tags on the artifact
content = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID); content = openCase.getSleuthkitCase().getContentById(contentID);
bbArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(artifactID); bbArtifact = openCase.getSleuthkitCase().getBlackboardArtifact(artifactID);
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); TagsManager tagsManager = openCase.getServices().getTagsManager();
List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact); List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
if (tags.stream() if (tags.stream()
@ -319,10 +327,10 @@ final class CaseEventListener implements PropertyChangeListener {
* that are tagged with the given tag name. * that are tagged with the given tag name.
*/ */
try { try {
TagName tagName = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(modifiedTagName); TagName tagName = Case.getOpenCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(modifiedTagName);
//First update the artifacts //First update the artifacts
//Get all BlackboardArtifactTags with this tag name //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) { 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 //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; boolean hasTagWithConflictingKnownStatus = false;
@ -338,7 +346,7 @@ final class CaseEventListener implements PropertyChangeListener {
} }
//Get the BlackboardArtifact which this BlackboardArtifactTag has been applied to. //Get the BlackboardArtifact which this BlackboardArtifactTag has been applied to.
BlackboardArtifact bbArtifact = bbTag.getArtifact(); BlackboardArtifact bbArtifact = bbTag.getArtifact();
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); TagsManager tagsManager = Case.getOpenCase().getServices().getTagsManager();
List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact); List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
//get all tags which are on this blackboard artifact //get all tags which are on this blackboard artifact
for (BlackboardArtifactTag t : tags) { for (BlackboardArtifactTag t : tags) {
@ -366,7 +374,7 @@ final class CaseEventListener implements PropertyChangeListener {
} }
// Next update the files // 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 //Get all ContentTags with this tag name
for (ContentTag contentTag : fileTags) { 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 //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 // the status of the file in the central repository
if (tagName.getKnownStatus() == TskData.FileKnown.UNKNOWN) { if (tagName.getKnownStatus() == TskData.FileKnown.UNKNOWN) {
Content content = contentTag.getContent(); Content content = contentTag.getContent();
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); TagsManager tagsManager = Case.getOpenCase().getServices().getTagsManager();
List<ContentTag> tags = tagsManager.getContentTagsByContent(content); List<ContentTag> tags = tagsManager.getContentTagsByContent(content);
//get all tags which are on this file //get all tags which are on this file
for (ContentTag t : tags) { 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 LOGGER.log(Level.SEVERE, "Cannot update known status in central repository for tag: " + modifiedTagName, ex); //NON-NLS
} catch (EamDbException ex) { } catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Cannot get central repository for tag: " + modifiedTagName, ex); //NON-NLS 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 } //TAG_STATUS_CHANGED
} }
@ -424,15 +434,22 @@ final class CaseEventListener implements PropertyChangeListener {
if (!EamDb.isEnabled()) { if (!EamDb.isEnabled()) {
return; 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; final DataSourceAddedEvent dataSourceAddedEvent = (DataSourceAddedEvent) event;
Content newDataSource = dataSourceAddedEvent.getDataSource(); Content newDataSource = dataSourceAddedEvent.getDataSource();
try { try {
String deviceId = Case.getCurrentCase().getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId(); String deviceId = openCase.getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId();
CorrelationCase correlationCase = dbManager.getCase(Case.getCurrentCase()); CorrelationCase correlationCase = dbManager.getCase(openCase);
if (null == correlationCase) { if (null == correlationCase) {
correlationCase = dbManager.newCase(Case.getCurrentCase()); correlationCase = dbManager.newCase(openCase);
} }
if (null == dbManager.getDataSource(correlationCase, deviceId)) { if (null == dbManager.getDataSource(correlationCase, deviceId)) {
dbManager.newDataSource(CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource)); dbManager.newDataSource(CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource));

View File

@ -1,7 +1,7 @@
/* /*
* Central Repository * Central Repository
* *
* Copyright 2015-2017 Basis Technology Corp. * Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -32,6 +32,7 @@ import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.Blackboard;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
@ -144,9 +145,9 @@ public class IngestEventsListener {
tifArtifact.addAttributes(attributes); tifArtifact.addAttributes(attributes);
try { try {
// index the artifact for keyword search // index the artifact for keyword search
Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard(); Blackboard blackboard = Case.getOpenCase().getServices().getBlackboard();
blackboard.indexArtifact(tifArtifact); 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 LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS
} }

View File

@ -1,7 +1,7 @@
/* /*
* Central Repository * Central Repository
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -26,6 +26,7 @@ import java.util.stream.Collectors;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.Blackboard;
import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.core.RuntimeProperties;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
@ -79,7 +80,12 @@ class IngestModule implements FileIngestModule {
return ProcessResult.OK; 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)) { if (!EamArtifactUtil.isValidCentralRepoFile(af)) {
return ProcessResult.OK; return ProcessResult.OK;
@ -190,8 +196,16 @@ class IngestModule implements FileIngestModule {
} }
return; 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 // 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)) { && (EamDbPlatformEnum.getSelectedPlatform() == EamDbPlatformEnum.SQLITE)) {
LOGGER.log(Level.SEVERE, "Cannot run correlation engine on a multi-user case with a SQLite central repository."); 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 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 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 throw new IngestModuleException("Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS
} }
Case autopsyCase = Case.getCurrentCase();
try { try {
eamCase = centralRepoDb.getCase(autopsyCase); eamCase = centralRepoDb.getCase(autopsyCase);
} catch (EamDbException ex) { } catch (EamDbException ex) {

View File

@ -58,3 +58,10 @@ ManageCorrelationPropertiesDialog.okButton.text=OK
GlobalSettingsPanel.bnManageProperties.text=Manage Correlation Properties GlobalSettingsPanel.bnManageProperties.text=Manage Correlation Properties
EamDbSettingsDialog.lbDatabaseDesc.text=Database File: EamDbSettingsDialog.lbDatabaseDesc.text=Database File:
EamDbSettingsDialog.lbFullDbPath.text= 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

View File

@ -3,6 +3,9 @@
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties> <Properties>
<Property name="name" type="java.lang.String" value="" noResource="true"/> <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> </Properties>
<AuxValues> <AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
@ -19,352 +22,393 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0"> <Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="tbOops" alignment="1" max="32767" attributes="0"/>
<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"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0"> <Component id="jScrollPane1" alignment="0" pref="488" max="32767" 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"/>
<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"/>
</Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
</Layout> </Layout>
<SubComponents> <SubComponents>
<Container class="javax.swing.JPanel" name="pnDatabaseConfiguration"> <Container class="javax.swing.JScrollPane" name="jScrollPane1">
<Properties> <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="Database Configuration">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.pnDatabaseConfiguration.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Font PropertyName="font" name="Tahoma" size="12" style="0"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="bnDbConfigure" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="lbDbPlatformTypeLabel" max="32767" attributes="0"/>
<Component id="lbDbNameLabel" alignment="0" max="32767" attributes="0"/>
<Component id="lbDbLocationLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="lbDbNameValue" alignment="0" max="32767" attributes="0"/>
<Component id="lbDbPlatformValue" max="32767" attributes="0"/>
<Component id="lbDbLocationValue" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="7" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="lbDbPlatformTypeLabel" max="32767" attributes="0"/>
<Component id="lbDbPlatformValue" min="-2" pref="14" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="lbDbNameLabel" max="32767" attributes="0"/>
<Component id="lbDbNameValue" min="-2" pref="14" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="lbDbLocationLabel" max="32767" attributes="0"/>
<Component id="lbDbLocationValue" min="-2" pref="14" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Component id="bnDbConfigure" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="lbDbPlatformTypeLabel">
<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.lbDbPlatformTypeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lbDbNameLabel">
<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.lbDbNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lbDbLocationLabel">
<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.lbDbLocationLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="bnDbConfigure">
<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.bnDbConfigure.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnDbConfigureActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lbDbPlatformValue">
</Component>
<Component class="javax.swing.JLabel" name="lbDbNameValue">
</Component>
<Component class="javax.swing.JLabel" name="lbDbLocationValue">
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/> <Border info="null"/>
</Property> </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="&lt;GlobalSettingsPanel.pnCorrelationProperties.border.title&gt;">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.pnCorrelationProperties.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Font PropertyName="font" name="Tahoma" size="12" style="0"/>
</TitledBorder>
</Border>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[674, 93]"/> <Dimension value="[1022, 407]"/>
</Property> </Property>
</Properties> </Properties>
<Layout> <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="correlationPropertiesScrollPane" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="bnManageTypes" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="7" max="-2" attributes="0"/>
<Component id="correlationPropertiesScrollPane" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="bnManageTypes" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents> <SubComponents>
<Component class="javax.swing.JButton" name="bnManageTypes"> <Container class="javax.swing.JPanel" name="jPanel1">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.bnManageProperties.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <Dimension value="[0, 0]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[1020, 407]"/>
</Property> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnManageTypesActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="correlationPropertiesScrollPane">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> <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="pnDatabaseConfiguration" alignment="0" max="32767" 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>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" 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 type="unrelated" max="-2" attributes="0"/>
<Component id="pnDatabaseConfiguration" 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> <SubComponents>
<Component class="javax.swing.JTextArea" name="correlationPropertiesTextArea"> <Component class="javax.swing.JLabel" name="lbCentralRepository">
<Properties> <Properties>
<Property name="editable" type="boolean" value="false"/>
<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="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="0"/>
</Property>
<Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="2"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.correlationPropertiesTextArea.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.lbCentralRepository.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="wrapStyleWord" type="boolean" value="true"/>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
</SubComponents> <Component class="javax.swing.JCheckBox" name="cbUseCentralRepo">
</Container> <Properties>
</SubComponents> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
</Container> <ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.cbUseCentralRepo.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Component class="javax.swing.JLabel" name="lbCentralRepository"> </Property>
<Properties> </Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Events>
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.lbCentralRepository.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbUseCentralRepoActionPerformed"/>
</Property> </Events>
</Properties> </Component>
</Component> <Container class="javax.swing.JPanel" name="pnDatabaseConfiguration">
<Container class="javax.swing.JPanel" name="organizationPanel"> <Properties>
<Properties> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> <TitledBorder title="Database Configuration">
<TitledBorder title="&lt;GlobalSettingsPanel.organizationPanel.border.title&gt;"> <ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.pnDatabaseConfiguration.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.organizationPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <Font PropertyName="font" name="Tahoma" size="12" style="0"/>
<Font PropertyName="font" name="Tahoma" size="12" style="0"/> </TitledBorder>
</TitledBorder> </Border>
</Border> </Property>
</Property> </Properties>
</Properties>
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="organizationScrollPane" max="32767" attributes="0"/>
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Component id="manageOrganizationButton" min="-2" max="-2" attributes="0"/> <EmptySpace min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="bnDbConfigure" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="lbDbPlatformTypeLabel" max="32767" attributes="0"/>
<Component id="lbDbNameLabel" alignment="0" max="32767" attributes="0"/>
<Component id="lbDbLocationLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="lbDbNameValue" alignment="0" max="32767" attributes="0"/>
<Component id="lbDbPlatformValue" max="32767" attributes="0"/>
<Component id="lbDbLocationValue" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</Group> </Group>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> </DimensionLayout>
</Group> <DimensionLayout dim="1">
</Group> <Group type="103" groupAlignment="0" attributes="0">
</DimensionLayout> <Group type="102" attributes="0">
<DimensionLayout dim="1"> <EmptySpace min="-2" pref="7" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" max="-2" attributes="0">
<Group type="102" alignment="1" attributes="0"> <Component id="lbDbPlatformTypeLabel" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <Component id="lbDbPlatformValue" min="-2" pref="14" max="-2" attributes="0"/>
<Component id="organizationScrollPane" min="-2" max="-2" attributes="0"/> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="manageOrganizationButton" min="-2" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" max="-2" attributes="0">
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/> <Component id="lbDbNameLabel" max="32767" attributes="0"/>
</Group> <Component id="lbDbNameValue" min="-2" pref="14" max="-2" attributes="0"/>
</Group> </Group>
</DimensionLayout> <EmptySpace max="-2" attributes="0"/>
</Layout> <Group type="103" groupAlignment="0" max="-2" attributes="0">
<SubComponents> <Component id="lbDbLocationLabel" max="32767" attributes="0"/>
<Component class="javax.swing.JButton" name="manageOrganizationButton"> <Component id="lbDbLocationValue" min="-2" pref="14" max="-2" attributes="0"/>
<Properties> </Group>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <EmptySpace max="32767" attributes="0"/>
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.manageOrganizationButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <Component id="bnDbConfigure" min="-2" max="-2" attributes="0"/>
</Property> <EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Properties> </Group>
<Events> </Group>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="manageOrganizationButtonActionPerformed"/> </DimensionLayout>
</Events> </Layout>
</Component> <SubComponents>
<Container class="javax.swing.JScrollPane" name="organizationScrollPane"> <Component class="javax.swing.JLabel" name="lbDbPlatformTypeLabel">
<Properties> <Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<Border info="null"/> <ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.lbDbPlatformTypeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
<AuxValues> </Component>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> <Component class="javax.swing.JLabel" name="lbDbNameLabel">
</AuxValues> <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.lbDbNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lbDbLocationLabel">
<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.lbDbLocationLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="bnDbConfigure">
<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.bnDbConfigure.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnDbConfigureActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lbDbPlatformValue">
</Component>
<Component class="javax.swing.JLabel" name="lbDbNameValue">
</Component>
<Component class="javax.swing.JLabel" name="lbDbLocationValue">
</Component>
</SubComponents>
</Container>
<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="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, &quot;{key}&quot;)"/>
<Font PropertyName="font" name="Tahoma" size="12" style="0"/>
</TitledBorder>
</Border>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[674, 93]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> <Layout>
<SubComponents> <DimensionLayout dim="0">
<Component class="javax.swing.JTextArea" name="organizationTextArea"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="correlationPropertiesScrollPane" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="bnManageTypes" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="7" max="-2" attributes="0"/>
<Component id="correlationPropertiesScrollPane" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="bnManageTypes" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="bnManageTypes">
<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.bnManageProperties.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnManageTypesActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="correlationPropertiesScrollPane">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="correlationPropertiesTextArea">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<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="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="0"/>
</Property>
<Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="2"/>
<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.correlationPropertiesTextArea.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="wrapStyleWord" type="boolean" value="true"/>
<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>
<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="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, &quot;{key}&quot;)"/>
<Font PropertyName="font" name="Tahoma" size="12" style="0"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="organizationScrollPane" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="manageOrganizationButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="organizationScrollPane" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="manageOrganizationButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="manageOrganizationButton">
<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.manageOrganizationButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="manageOrganizationButtonActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="organizationScrollPane">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="organizationTextArea">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<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="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="0"/>
</Property>
<Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="2"/>
<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.organizationTextArea.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="wrapStyleWord" type="boolean" value="true"/>
<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>
<Component class="javax.swing.JTextField" name="tbOops">
<Properties> <Properties>
<Property name="editable" type="boolean" value="false"/> <Property name="editable" type="boolean" value="false"/>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor"> <Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<Color blue="f0" green="f0" red="f0" type="rgb"/> <FontInfo relative="true">
<Font bold="true" component="tbOops" property="font" relativeSize="false" size="12"/>
</FontInfo>
</Property> </Property>
<Property name="columns" type="int" value="20"/>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="0"/>
</Property>
<Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="2"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.organizationTextArea.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.tbOops.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
<Property name="wrapStyleWord" type="boolean" value="true"/>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/> <Border info="null"/>
</Property> </Property>

View File

@ -58,22 +58,8 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
addIngestJobEventsListener(); 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() { private void customizeComponents() {
setName(Bundle.GlobalSettingsPanel_title()); setName(NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnCorrelationProperties.border.title"));
} }
private void addIngestJobEventsListener() { private void addIngestJobEventsListener() {
@ -116,6 +102,10 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() { private void initComponents() {
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(); pnDatabaseConfiguration = new javax.swing.JPanel();
lbDbPlatformTypeLabel = new javax.swing.JLabel(); lbDbPlatformTypeLabel = new javax.swing.JLabel();
lbDbNameLabel = 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(); lbDbPlatformValue = new javax.swing.JLabel();
lbDbNameValue = new javax.swing.JLabel(); lbDbNameValue = new javax.swing.JLabel();
lbDbLocationValue = new javax.swing.JLabel(); lbDbLocationValue = new javax.swing.JLabel();
cbUseCentralRepo = new javax.swing.JCheckBox();
tbOops = new javax.swing.JTextField();
pnCorrelationProperties = new javax.swing.JPanel(); pnCorrelationProperties = new javax.swing.JPanel();
bnManageTypes = new javax.swing.JButton(); bnManageTypes = new javax.swing.JButton();
correlationPropertiesScrollPane = new javax.swing.JScrollPane(); correlationPropertiesScrollPane = new javax.swing.JScrollPane();
correlationPropertiesTextArea = new javax.swing.JTextArea(); correlationPropertiesTextArea = new javax.swing.JTextArea();
lbCentralRepository = new javax.swing.JLabel();
organizationPanel = new javax.swing.JPanel(); organizationPanel = new javax.swing.JPanel();
manageOrganizationButton = new javax.swing.JButton(); manageOrganizationButton = new javax.swing.JButton();
organizationScrollPane = new javax.swing.JScrollPane(); organizationScrollPane = new javax.swing.JScrollPane();
organizationTextArea = new javax.swing.JTextArea(); organizationTextArea = new javax.swing.JTextArea();
tbOops = new javax.swing.JTextField();
setName(""); // NOI18N 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 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)) .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.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)); pnCorrelationProperties.setPreferredSize(new java.awt.Dimension(674, 93));
@ -253,8 +245,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addGap(8, 8, 8)) .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 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 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)) .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); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout); this.setLayout(layout);
layout.setHorizontalGroup( layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.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())))
); );
layout.setVerticalGroup( layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 488, Short.MAX_VALUE)
.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())
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
@ -523,6 +533,8 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
private javax.swing.JCheckBox cbUseCentralRepo; private javax.swing.JCheckBox cbUseCentralRepo;
private javax.swing.JScrollPane correlationPropertiesScrollPane; private javax.swing.JScrollPane correlationPropertiesScrollPane;
private javax.swing.JTextArea correlationPropertiesTextArea; private javax.swing.JTextArea correlationPropertiesTextArea;
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JLabel lbCentralRepository; private javax.swing.JLabel lbCentralRepository;
private javax.swing.JLabel lbDbLocationLabel; private javax.swing.JLabel lbDbLocationLabel;
private javax.swing.JLabel lbDbLocationValue; private javax.swing.JLabel lbDbLocationValue;

View File

@ -25,6 +25,7 @@ import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory; import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children; import org.openide.nodes.Children;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.python.google.common.collect.Iterables;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AccountDeviceInstance; import org.sleuthkit.datamodel.AccountDeviceInstance;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
@ -38,12 +39,16 @@ import org.sleuthkit.datamodel.TskCoreException;
* relationships of all the accounts in this node. * 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()); private final static Logger logger = Logger.getLogger(AccountDetailsNode.class.getName());
AccountDetailsNode(Set<AccountDeviceInstance> accountDeviceInstances, CommunicationsFilter filter, CommunicationsManager commsManager) { AccountDetailsNode(Set<AccountDeviceInstance> accountDeviceInstances, CommunicationsFilter filter, CommunicationsManager commsManager) {
super(Children.create(new AccountRelationshipChildren(accountDeviceInstances, commsManager, filter), true)); super(Children.create(new AccountRelationshipChildren(accountDeviceInstances, commsManager, filter), true));
String displayName = (accountDeviceInstances.size() == 1)
? Iterables.getOnlyElement(accountDeviceInstances).getAccount().getTypeSpecificID()
: accountDeviceInstances.size() + " accounts";
setDisplayName(displayName);
} }
/** /**

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2017 Basis Technology Corp. * Copyright 2017-18 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -18,23 +18,31 @@
*/ */
package org.sleuthkit.autopsy.communications; 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.AccountDeviceInstance;
import org.sleuthkit.datamodel.CommunicationsFilter; import org.sleuthkit.datamodel.CommunicationsFilter;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/** /**
* Key for AccountDeviceInstance node. * 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 AccountDeviceInstance accountDeviceInstance;
private final CommunicationsFilter filter; private final CommunicationsFilter filter;
private final long messageCount; private final long messageCount;
private final String dataSourceName; private final String dataSourceName;
AccountDeviceInstanceKey(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter, long msgCount, String dataSourceName) { AccountDeviceInstanceKey(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter, long msgCount, String dataSourceName) {
this.accountDeviceInstance = accountDeviceInstance; this.accountDeviceInstance = accountDeviceInstance;
this.filter = filter; this.filter = filter;
@ -42,6 +50,13 @@ class AccountDeviceInstanceKey {
this.dataSourceName = dataSourceName; 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() { AccountDeviceInstance getAccountDeviceInstance() {
return accountDeviceInstance; return accountDeviceInstance;
} }
@ -53,8 +68,56 @@ class AccountDeviceInstanceKey {
long getMessageCount() { long getMessageCount() {
return messageCount; return messageCount;
} }
String getDataSourceName() { String getDataSourceName() {
return dataSourceName; 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();
}
} }

View File

@ -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));
}
}
}

View File

@ -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);
}
}

View File

@ -11,30 +11,28 @@
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <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> </AuxValues>
<Layout> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="outlineView" pref="400" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="outlineView" pref="300" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents> <SubComponents>
<Container class="org.openide.explorer.view.OutlineView" name="outlineView"> <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> </Container>
</SubComponents> </SubComponents>
</Form> </Form>

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2017 Basis Technology Corp. * Copyright 2017-18 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -18,7 +18,9 @@
*/ */
package org.sleuthkit.autopsy.communications; package org.sleuthkit.autopsy.communications;
import com.google.common.eventbus.Subscribe;
import java.awt.Component; import java.awt.Component;
import java.util.logging.Level;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.ListSelectionModel; import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
@ -26,21 +28,41 @@ import javax.swing.table.TableCellRenderer;
import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.DefaultOutlineModel;
import org.netbeans.swing.outline.Outline; import org.netbeans.swing.outline.Outline;
import org.openide.explorer.ExplorerManager; 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. * 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 long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(AccountsBrowser.class.getName());
private final Outline outline; private final Outline outline;
private ExplorerManager em;
/** private final ExplorerManager messageBrowserEM = new ExplorerManager();
* Creates new form AccountsBrowser 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() { public AccountsBrowser() {
initComponents(); initComponents();
outline = outlineView.getOutline(); outline = outlineView.getOutline();
@ -54,19 +76,21 @@ public class AccountsBrowser extends JPanel {
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AccountNode_accountName()); ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AccountNode_accountName());
outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
outline.setColumnSorted(3, false, 1); //it would be nice if the column index wasn't hardcoded outline.setColumnSorted(3, false, 1); //it would be nice if the column index wasn't hardcoded
}
@Override accountsTableEM.addPropertyChangeListener(evt -> {
public void addNotify() {
super.addNotify();
em = ExplorerManager.find(this);
em.addPropertyChangeListener(evt -> {
if (ExplorerManager.PROP_ROOT_CONTEXT.equals(evt.getPropertyName())) { if (ExplorerManager.PROP_ROOT_CONTEXT.equals(evt.getPropertyName())) {
SwingUtilities.invokeLater(this::setColumnWidths); SwingUtilities.invokeLater(this::setColumnWidths);
} else if (ExplorerManager.PROP_EXPLORED_CONTEXT.equals(evt.getPropertyName())) { } else if (ExplorerManager.PROP_EXPLORED_CONTEXT.equals(evt.getPropertyName())) {
SwingUtilities.invokeLater(this::setColumnWidths); SwingUtilities.invokeLater(this::setColumnWidths);
} }
}); });
final MessageBrowser messageBrowser = new MessageBrowser(accountsTableEM, messageBrowserEM);
jSplitPane1.setRightComponent(messageBrowser);
proxyLookup = new ProxyLookup(
messageBrowser.getLookup(),
ExplorerUtils.createLookup(accountsTableEM, getActionMap()));
} }
private void setColumnWidths() { 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. * 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 * 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 // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() { private void initComponents() {
jSplitPane1 = new javax.swing.JSplitPane();
outlineView = new org.openide.explorer.view.OutlineView(); outlineView = new org.openide.explorer.view.OutlineView();
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); setLayout(new java.awt.BorderLayout());
this.setLayout(layout);
layout.setHorizontalGroup( jSplitPane1.setLeftComponent(outlineView);
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() add(jSplitPane1, java.awt.BorderLayout.CENTER);
.addGap(0, 0, 0)
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JSplitPane jSplitPane1;
private org.openide.explorer.view.OutlineView outlineView; private org.openide.explorer.view.OutlineView outlineView;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
@Override
public ExplorerManager getExplorerManager() {
return accountsTableEM;
}
@Override
public Lookup getLookup() {
return proxyLookup;
}
} }

View File

@ -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;
}
}
}

View File

@ -15,3 +15,31 @@ FiltersPanel.refreshButton.text=Refresh
FiltersPanel.deviceRequiredLabel.text=Select at least one. FiltersPanel.deviceRequiredLabel.text=Select at least one.
FiltersPanel.accountTypeRequiredLabel.text=Select at least one. FiltersPanel.accountTypeRequiredLabel.text=Select at least one.
FiltersPanel.needsRefreshLabel.text=Displayed data is out of date. Press Refresh. FiltersPanel.needsRefreshLabel.text=Displayed data is out of date. Press Refresh.
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

View 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);
}
}
}

View File

@ -4,7 +4,7 @@
<AuxValues> <AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
@ -18,10 +18,10 @@
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/> <EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Component id="filtersPane" min="-2" max="-2" attributes="0"/> <Component id="filtersPane" min="-2" pref="265" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="splitPane" pref="1277" max="32767" attributes="0"/> <Component id="browseVisualizeTabPane" pref="786" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/> <EmptySpace min="-2" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -29,54 +29,59 @@
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" 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="filtersPane" max="32767" attributes="0"/>
<Component id="splitPane" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/> <EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
</Group> </Group>
<Group type="102" alignment="1" attributes="0">
<Component id="browseVisualizeTabPane" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
</Layout> </Layout>
<SubComponents> <SubComponents>
<Container class="javax.swing.JSplitPane" name="splitPane"> <Container class="javax.swing.JTabbedPane" name="browseVisualizeTabPane">
<Properties> <Properties>
<Property name="dividerLocation" type="int" value="400"/> <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Property name="resizeWeight" type="double" value="0.7"/> <Font name="Tahoma" size="18" style="0"/>
</Property>
</Properties> </Properties>
<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, &quot;{key}&quot;)"/>
</Property>
</AccessibilityProperties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/> <Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
<SubComponents> <SubComponents>
<Container class="javax.swing.JTabbedPane" name="browseVisualizeTabPane"> <Component class="org.sleuthkit.autopsy.communications.AccountsBrowser" name="accountsBrowser">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="18" style="0"/>
</Property>
</Properties>
<Constraints> <Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription"> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<JSplitPaneConstraints position="left"/> <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_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="tabIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/table.png"/>
</Property>
</JTabbedPaneConstraints>
</Constraint> </Constraint>
</Constraints> </Constraints>
</Component>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/> <Component class="org.sleuthkit.autopsy.communications.VisualizationPanel" name="vizPanel">
<SubComponents> <Constraints>
<Component class="org.sleuthkit.autopsy.communications.AccountsBrowser" name="accountsBrowser"> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
<Constraints> <JTabbedPaneConstraints tabName="Visualize">
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription"> <Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<JTabbedPaneConstraints tabName="Browse"> <ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="CVTTopComponent.vizPanel.TabConstraints.tabTitle_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> </Property>
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="CVTTopComponent.accountsBrowser.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <Property name="tabIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
</Property> <Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/emblem-web.png"/>
<Property name="tabIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> </Property>
<Image iconType="3" name="/org/sleuthkit/autopsy/communications/images/table.png"/> </JTabbedPaneConstraints>
</Property> </Constraint>
</JTabbedPaneConstraints> </Constraints>
</Constraint> </Component>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents> </SubComponents>
</Container> </Container>
<Component class="org.sleuthkit.autopsy.communications.FiltersPanel" name="filtersPane"> <Component class="org.sleuthkit.autopsy.communications.FiltersPanel" name="filtersPane">

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2017 Basis Technology Corp. * Copyright 2017-18 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -18,10 +18,16 @@
*/ */
package org.sleuthkit.autopsy.communications; 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.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.openide.explorer.ExplorerManager; import javax.swing.GroupLayout;
import org.openide.explorer.ExplorerUtils; 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.util.NbBundle;
import org.openide.windows.Mode; import org.openide.windows.Mode;
import org.openide.windows.RetainLocation; import org.openide.windows.RetainLocation;
@ -36,33 +42,42 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined;
@TopComponent.Registration(mode = "cvt", openAtStartup = false) @TopComponent.Registration(mode = "cvt", openAtStartup = false)
@RetainLocation("cvt") @RetainLocation("cvt")
@NbBundle.Messages("CVTTopComponent.name= Communications Visualization") @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 static final long serialVersionUID = 1L;
private final ExplorerManager messagesBrowserExplorerManager;
private final ExplorerManager acctsBrowserExplorerManager;
@ThreadConfined(type = ThreadConfined.ThreadType.AWT) @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
public CVTTopComponent() { public CVTTopComponent() {
initComponents(); initComponents();
setName(Bundle.CVTTopComponent_name()); 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 * Associate a Lookup with the GlobalActionContext (GAC) so that
* browser and the message browser so that the browsers can both listen * selections in the sub views can be exposed to context-sensitive
* for explorer manager property events for the outline view of the * actions.
* accounts browser. This provides a mechanism for pushing selected
* Nodes from the accounts browser to the messages browser.
*/ */
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 // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() { private void initComponents() {
splitPane = new javax.swing.JSplitPane(); browseVisualizeTabPane = new JTabbedPane();
browseVisualizeTabPane = new javax.swing.JTabbedPane(); accountsBrowser = new AccountsBrowser();
accountsBrowser = new org.sleuthkit.autopsy.communications.AccountsBrowser(); vizPanel = new VisualizationPanel();
filtersPane = new org.sleuthkit.autopsy.communications.FiltersPanel(); filtersPane = new FiltersPanel();
splitPane.setDividerLocation(400); browseVisualizeTabPane.setFont(new Font("Tahoma", 0, 18)); // NOI18N
splitPane.setResizeWeight(0.7); 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 filtersPane.setMinimumSize(new Dimension(256, 495));
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
splitPane.setLeftComponent(browseVisualizeTabPane); GroupLayout layout = new GroupLayout(this);
filtersPane.setMinimumSize(new java.awt.Dimension(256, 495));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout); this.setLayout(layout);
layout.setHorizontalGroup( layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGap(6, 6, 6) .addGap(6, 6, 6)
.addComponent(filtersPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(filtersPane, GroupLayout.PREFERRED_SIZE, 265, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(splitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1277, Short.MAX_VALUE) .addComponent(browseVisualizeTabPane, GroupLayout.PREFERRED_SIZE, 786, Short.MAX_VALUE)
.addGap(0, 0, 0)) .addContainerGap())
); );
layout.setVerticalGroup( layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGap(6, 6, 6) .addGap(6, 6, 6)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(filtersPane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(filtersPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(splitPane))
.addGap(5, 5, 5)) .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 }// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.communications.AccountsBrowser accountsBrowser; private AccountsBrowser accountsBrowser;
private javax.swing.JTabbedPane browseVisualizeTabPane; private JTabbedPane browseVisualizeTabPane;
private org.sleuthkit.autopsy.communications.FiltersPanel filtersPane; private FiltersPanel filtersPane;
private javax.swing.JSplitPane splitPane; private VisualizationPanel vizPanel;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
@Override @Override
@ -124,11 +136,6 @@ public final class CVTTopComponent extends TopComponent implements ExplorerManag
WindowManager.getDefault().setTopComponentFloating(this, true); WindowManager.getDefault().setTopComponentFloating(this, true);
} }
@Override
public ExplorerManager getExplorerManager() {
return acctsBrowserExplorerManager;
}
@Override @Override
public void open() { public void open() {
super.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... * Re-applying the filters means we will lose the selection...
*/ */
filtersPane.updateAndApplyFilters(); filtersPane.updateAndApplyFilters(true);
} }
@Override @Override

View File

@ -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();
}
}
}
}

View File

@ -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);
}

View File

@ -241,7 +241,7 @@
<Component class="javax.swing.JLabel" name="devicesLabel"> <Component class="javax.swing.JLabel" name="devicesLabel">
<Properties> <Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> <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>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.devicesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="FiltersPanel.devicesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2017 Basis Technology Corp. * Copyright 2017-18 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -30,12 +30,11 @@ import java.util.Map.Entry;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.swing.JCheckBox; import javax.swing.JCheckBox;
import org.openide.explorer.ExplorerManager; import javax.swing.JPanel;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import static org.sleuthkit.autopsy.casemodule.Case.Events.CURRENT_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.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined; 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.AccountTypeFilter;
import org.sleuthkit.datamodel.CommunicationsFilter.DateRangeFilter; import org.sleuthkit.datamodel.CommunicationsFilter.DateRangeFilter;
import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter; import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.DataSource;
import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG; import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG;
import static org.sleuthkit.datamodel.Relationship.Type.MESSAGE; import static org.sleuthkit.datamodel.Relationship.Type.MESSAGE;
@ -56,18 +54,23 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
* Panel that holds the Filter control widgets and translates user filtering * Panel that holds the Filter control widgets and triggers queries against the
* changes into queries against the CommunicationsManager. * 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 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) @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
private final Map<Account.Type, JCheckBox> accountTypeMap = new HashMap<>(); 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) @ThreadConfined(type = ThreadConfined.ThreadType.AWT)
private final Map<String, JCheckBox> devicesMap = new HashMap<>(); 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 * Listens to ingest events to enable refresh button
*/ */
private final PropertyChangeListener ingestListener; 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; private boolean needsRefresh;
/** /**
@ -84,8 +92,15 @@ final public class FiltersPanel extends javax.swing.JPanel {
*/ */
private final ItemListener validationListener; 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() { public FiltersPanel() {
initComponents(); initComponents();
deviceRequiredLabel.setVisible(false); deviceRequiredLabel.setVisible(false);
@ -106,8 +121,7 @@ final public class FiltersPanel extends javax.swing.JPanel {
updateTimeZone(); updateTimeZone();
validationListener = itemEvent -> validateFilters(); validationListener = itemEvent -> validateFilters();
updateFilters(); updateFilters(true);
setAllDevicesSelected(true);
UserPreferences.addChangeListener(preferenceChangeEvent -> { UserPreferences.addChangeListener(preferenceChangeEvent -> {
if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME)) { if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME)) {
updateTimeZone(); updateTimeZone();
@ -119,10 +133,10 @@ final public class FiltersPanel extends javax.swing.JPanel {
if (eventType.equals(DATA_ADDED.toString())) { if (eventType.equals(DATA_ADDED.toString())) {
// Indicate that a refresh may be needed, unless the data added is Keyword or Hashset hits // Indicate that a refresh may be needed, unless the data added is Keyword or Hashset hits
ModuleDataEvent eventData = (ModuleDataEvent) pce.getOldValue(); ModuleDataEvent eventData = (ModuleDataEvent) pce.getOldValue();
if (null != eventData && if (null != eventData
eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() && && eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { && eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
updateFilters(); updateFilters(false);
needsRefresh = true; needsRefresh = true;
validateFilters(); validateFilters();
} }
@ -154,32 +168,29 @@ final public class FiltersPanel extends javax.swing.JPanel {
/** /**
* Update the filter widgets, and apply them. * Update the filter widgets, and apply them.
*/ */
void updateAndApplyFilters() { void updateAndApplyFilters(boolean initialState) {
updateFilters(); updateFilters(initialState);
if (em != null) { applyFilters();
applyFilters();
}
} }
private void updateTimeZone() { private void updateTimeZone() {
dateRangeLabel.setText("Date Range ( " + Utils.getUserPreferredZoneId().toString() + "):"); 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(); updateAccountTypeFilter();
updateDeviceFilter(); updateDeviceFilter(initialState);
} }
@Override @Override
public void addNotify() { public void addNotify() {
super.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); IngestManager.getInstance().addIngestModuleEventListener(ingestListener);
Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> { Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> {
//clear the device filter widget when the case changes.
devicesMap.clear(); devicesMap.clear();
devicesPane.removeAll(); 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 //TODO: something like this commented code could be used to show only
//the account types that are found: //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(); //List<Account.Type> accountTypesInUse = communicationsManager.getAccountTypesInUse();
//accountTypesInUSe.forEach(...) //accountTypesInUSe.forEach(...)
Account.Type.PREDEFINED_ACCOUNT_TYPES.forEach(type -> { Account.Type.PREDEFINED_ACCOUNT_TYPES.forEach(type -> {
if (type.equals(Account.Type.CREDIT_CARD)) { if (type.equals(Account.Type.CREDIT_CARD)) {
//don't show a check box for credit cards //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 { } else {
accountTypeMap.computeIfAbsent(type, t -> { accountTypeMap.computeIfAbsent(type, t -> {
final JCheckBox jCheckBox = new JCheckBox( final JCheckBox jCheckBox = new JCheckBox(
"<html><table cellpadding=0><tr><td><img src=\"" "<html><table cellpadding=0><tr><td><img src=\""
+ FiltersPanel.class.getResource("/org/sleuthkit/autopsy/communications/images/" + FiltersPanel.class.getResource(Utils.getIconFilePath(type))
+ Utils.getIconFileName(type))
+ "\"/></td><td width=" + 3 + "><td>" + type.getDisplayName() + "</td></tr></table></html>", + "\"/></td><td width=" + 3 + "><td>" + type.getDisplayName() + "</td></tr></table></html>",
true true
); );
jCheckBox.addItemListener(validationListener); jCheckBox.addItemListener(validationListener);
accountTypePane.add(jCheckBox); 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; return jCheckBox;
}); });
} }
} });
);
} }
/** /**
* Populate the devices filter widgets * Populate the devices filter widgets
*/ */
private void updateDeviceFilter() { private void updateDeviceFilter(boolean initialState) {
try { try {
final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase(); final SleuthkitCase sleuthkitCase = Case.getOpenCase().getSleuthkitCase();
for (DataSource dataSource : sleuthkitCase.getDataSources()) { for (DataSource dataSource : sleuthkitCase.getDataSources()) {
String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName(); String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName();
//store the device id in the map, but display a datasource name in the UI. //store the device id in the map, but display a datasource name in the UI.
devicesMap.computeIfAbsent(dataSource.getDeviceId(), ds -> { devicesMap.computeIfAbsent(dataSource.getDeviceId(), ds -> {
final JCheckBox jCheckBox = new JCheckBox(dsName, false); final JCheckBox jCheckBox = new JCheckBox(dsName, initialState);
jCheckBox.addItemListener(validationListener); jCheckBox.addItemListener(validationListener);
devicesPane.add(jCheckBox); devicesPane.add(jCheckBox);
return jCheckBox; return jCheckBox;
}); });
}; }
} catch (NoCurrentCaseException ex) {
} catch (IllegalStateException ex) {
logger.log(Level.WARNING, "Communications Visualization Tool opened with no open case.", ex); logger.log(Level.WARNING, "Communications Visualization Tool opened with no open case.", ex);
} catch (TskCoreException tskCoreException) { } catch (TskCoreException tskCoreException) {
logger.log(Level.SEVERE, "There was a error loading the datasources for the case.", 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 devicesLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.devicesLabel.text")); // NOI18N
checkAllDevicesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.checkAllDevicesButton.text")); // NOI18N checkAllDevicesButton.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 }// </editor-fold>//GEN-END:initComponents
/** /**
* Query for accounts using the selected filters, and send the results to * Post an event with the new filters.
* the AccountsBrowser via the ExplorerManager.
*/ */
private void applyFilters() { private void applyFilters() {
CVTEvents.getCVTEventBus().post(new CVTEvents.FilterChangeEvent(getFilter()));
needsRefresh = false;
validateFilters();
}
private CommunicationsFilter getFilter() {
CommunicationsFilter commsFilter = new CommunicationsFilter(); CommunicationsFilter commsFilter = new CommunicationsFilter();
commsFilter.addAndFilter(getDeviceFilter()); commsFilter.addAndFilter(getDeviceFilter());
commsFilter.addAndFilter(getAccountTypeFilter()); commsFilter.addAndFilter(getAccountTypeFilter());
commsFilter.addAndFilter(getDateRangeFilter()); commsFilter.addAndFilter(getDateRangeFilter());
commsFilter.addAndFilter(new CommunicationsFilter.RelationshipTypeFilter( commsFilter.addAndFilter(new CommunicationsFilter.RelationshipTypeFilter(
ImmutableSet.of(CALL_LOG, MESSAGE))); ImmutableSet.of(CALL_LOG, MESSAGE)));
return commsFilter;
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();
} }
/** /**
@ -538,6 +544,11 @@ final public class FiltersPanel extends javax.swing.JPanel {
return accountTypeFilter; return accountTypeFilter;
} }
/**
* Get an DateRangeFilter that matches the state of the UI widgets
*
* @return an DateRangeFilter
*/
private DateRangeFilter getDateRangeFilter() { private DateRangeFilter getDateRangeFilter() {
ZoneId zone = Utils.getUserPreferredZoneId(); ZoneId zone = Utils.getUserPreferredZoneId();
long start = startDatePicker.isEnabled() ? startDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0; 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); 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 * 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) { private void setAllSelected(Map<?, JCheckBox> map, boolean selected) {
map.values().forEach(box -> box.setSelected(selected)); map.values().forEach(box -> box.setSelected(selected));
} }
private void unCheckAllAccountTypesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_unCheckAllAccountTypesButtonActionPerformed private void unCheckAllAccountTypesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_unCheckAllAccountTypesButtonActionPerformed
setAllAccountTypesSelected(false); setAllAccountTypesSelected(false);
}//GEN-LAST:event_unCheckAllAccountTypesButtonActionPerformed }//GEN-LAST:event_unCheckAllAccountTypesButtonActionPerformed

View File

@ -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;
}
}
}

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2017 Basis Technology Corp. * Copyright 2017-18 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -18,96 +18,106 @@
*/ */
package org.sleuthkit.autopsy.communications; 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.Set;
import java.util.stream.Collectors; import javax.swing.JPanel;
import java.util.stream.Stream; import static javax.swing.SwingUtilities.isDescendingFrom;
import org.openide.explorer.ExplorerManager; import org.openide.explorer.ExplorerManager;
import static org.openide.explorer.ExplorerUtils.createLookup;
import org.openide.nodes.Node; 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.DataResultPanel;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
import org.sleuthkit.datamodel.AccountDeviceInstance; 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 * The right hand side of the CVT. Has a DataResultPanel to show a listing of
* other account details, and a ContentViewer to show individual * 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 static final long serialVersionUID = 1L;
private final ExplorerManager tableEM;
private final ExplorerManager gacExplorerManager; private final ExplorerManager gacExplorerManager;
private final DataResultPanel messagesResultPanel; 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 * Constructs the right hand side of the Communications Visualization Tool
* (CVT). * (CVT).
* *
* @param tableEM An explorer manager to listen to as the driver
* of the Message Table.
* @param gacExplorerManager An explorer manager associated with the * @param gacExplorerManager An explorer manager associated with the
* GlobalActionsContext (GAC) so that selections * GlobalActionsContext (GAC) so that selections
* in the messages browser can be exposed to * in the messages browser can be exposed to
* context-sensitive actions. * 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; this.gacExplorerManager = gacExplorerManager;
initComponents(); initComponents();
//create an uninitialized DataResultPanel so we can control the ResultViewers that get added. //create an uninitialized DataResultPanel so we can control the ResultViewers that get added.
messagesResultPanel = DataResultPanel.createInstanceUninitialized("Account", "", Node.EMPTY, 0, messageDataContent); messagesResultPanel = DataResultPanel.createInstanceUninitialized("Account", "", Node.EMPTY, 0, messageDataContent);
splitPane.setTopComponent(messagesResultPanel); splitPane.setTopComponent(messagesResultPanel);
splitPane.setBottomComponent(messageDataContent); splitPane.setBottomComponent(messageDataContent);
} messagesResultPanel.addResultViewer(new DataResultViewerTable(gacExplorerManager,
Bundle.MessageBrowser_DataResultViewerTable_title()));
messagesResultPanel.open();
@Override //add listener that maintains correct selection in the Global Actions Context
public void addNotify() { KeyboardFocusManager.getCurrentKeyboardFocusManager()
super.addNotify(); .addPropertyChangeListener("focusOwner", focusPropertyListener);
ExplorerManager parentExplorerManager = ExplorerManager.find(this);
parentExplorerManager.addPropertyChangeListener(pce -> {
if (pce.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
final Node[] selectedNodes = parentExplorerManager.getSelectedNodes();
messagesResultPanel.setNumMatches(0); this.tableEM.addPropertyChangeListener(new PropertyChangeListener() {
messagesResultPanel.setNode(null); @Override
public void propertyChange(PropertyChangeEvent pce) {
if (selectedNodes.length == 0) { if (pce.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
//reset panel when there is no selection final Node[] selectedNodes = MessageBrowser.this.tableEM.getSelectedNodes();
messagesResultPanel.setNumMatches(0);
messagesResultPanel.setNode(null);
messagesResultPanel.setPath(""); messagesResultPanel.setPath("");
} else { if (selectedNodes.length > 0) {
AccountDeviceInstanceNode adiNode = (AccountDeviceInstanceNode) selectedNodes[0]; Node rootNode;
CommunicationsFilter filter = adiNode.getFilter(); final Node selectedNode = selectedNodes[0];
CommunicationsManager commsManager = adiNode.getCommsManager();
final Set<AccountDeviceInstance> accountDeviceInstances;
if (selectedNodes.length == 1) { if (selectedNode instanceof AccountDeviceInstanceNode) {
final AccountDeviceInstance accountDeviceInstance = adiNode.getAccountDeviceInstance(); rootNode = makeRootNodeFromAccountDeviceInstanceNodes(selectedNodes);
accountDeviceInstances = Collections.singleton(accountDeviceInstance); } else {
messagesResultPanel.setPath(accountDeviceInstance.getAccount().getTypeSpecificID()); rootNode = selectedNode;
} else { }
accountDeviceInstances = Stream.of(selectedNodes) messagesResultPanel.setPath(rootNode.getDisplayName());
.map(node -> (AccountDeviceInstanceNode) node) messagesResultPanel.setNode(new TableFilterNode(new DataResultFilterNode(rootNode, gacExplorerManager), true));
.map(AccountDeviceInstanceNode::getAccountDeviceInstance)
.collect(Collectors.toSet());
messagesResultPanel.setPath(selectedNodes.length + " accounts");
} }
AccountDetailsNode accountDetailsNode
= new AccountDetailsNode(accountDeviceInstances, filter, commsManager);
TableFilterNode wrappedNode
= new TableFilterNode(new DataResultFilterNode(accountDetailsNode, parentExplorerManager), true);
messagesResultPanel.setNode(wrappedNode);
} }
} }
});
//add the required result viewers and THEN open the panel private Node makeRootNodeFromAccountDeviceInstanceNodes(final Node[] selectedNodes) {
if (null == dataResultViewerTable) { //Use lookup here?
dataResultViewerTable = new DataResultViewerTable(gacExplorerManager, "Messages"); final AccountDeviceInstanceNode adiNode = (AccountDeviceInstanceNode) selectedNodes[0];
messagesResultPanel.addResultViewer(dataResultViewerTable);
final Set<AccountDeviceInstance> accountDeviceInstances = new HashSet<>();
for (final Node n : selectedNodes) {
//Use lookup here?
accountDeviceInstances.add(((AccountDeviceInstanceNode) n).getAccountDeviceInstance());
}
return SelectionNode.createFromAccounts(accountDeviceInstances, adiNode.getFilter(), adiNode.getCommsManager());
}
} }
messagesResultPanel.open(); );
} }
@Override @Override
@ -115,6 +125,18 @@ final class MessageBrowser extends javax.swing.JPanel implements ExplorerManager
return gacExplorerManager; 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. * 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 * 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; private javax.swing.JSplitPane splitPane;
// End of variables declaration//GEN-END:variables // 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()));
}
}
}
}
}
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2017 Basis Technology Corp. * Copyright 2017-18 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.communications; package org.sleuthkit.autopsy.communications;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import org.openide.explorer.ExplorerManager;
import org.sleuthkit.autopsy.contentviewers.MessageContentViewer; import org.sleuthkit.autopsy.contentviewers.MessageContentViewer;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent; 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 * Extends MessageContentViewer so that it implements DataContent and can be set
* as the only ContentViewer for a DataResultPanel * 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; private static final long serialVersionUID = 1L;
final private ExplorerManager explorerManager = new ExplorerManager();
@Override @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. throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
} }
@Override
public ExplorerManager getExplorerManager() {
return explorerManager;
}
} }

View File

@ -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);
}
}

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2017 Basis Technology Corp. * Copyright 2017-18 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -19,6 +19,8 @@
package org.sleuthkit.autopsy.communications; package org.sleuthkit.autopsy.communications;
import java.awt.Component; import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.JButton; import javax.swing.JButton;
import org.openide.awt.ActionID; import org.openide.awt.ActionID;
@ -29,9 +31,10 @@ import org.openide.util.HelpCtx;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.openide.util.actions.CallableSystemAction; import org.openide.util.actions.CallableSystemAction;
import org.openide.util.actions.Presenter;
import org.openide.windows.TopComponent; import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager; 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 * 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") id = "org.sleuthkit.autopsy.communicationsVisualization.OpenCVTAction")
@ActionRegistration(displayName = "#CTL_OpenCVTAction", lazy = false) @ActionRegistration(displayName = "#CTL_OpenCVTAction", lazy = false)
@ActionReferences(value = { @ActionReferences(value = {
@ActionReference(path = "Menu/Tools", position = 102)}) @ActionReference(path = "Menu/Tools", position = 102)
,
@ActionReference(path = "Toolbars/Case", position = 102)})
@Messages("CTL_OpenCVTAction=Communications") @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 static final long serialVersionUID = 1L;
private final PropertyChangeListener pcl;
private final JButton toolbarButton = new JButton(getName(), private final JButton toolbarButton = new JButton(getName(),
new ImageIcon(getClass().getResource("images/emblem-web24.png"))); //NON-NLS new ImageIcon(getClass().getResource("images/emblem-web24.png"))); //NON-NLS
public OpenCommVisualizationToolAction() { public OpenCommVisualizationToolAction() {
toolbarButton.addActionListener(actionEvent -> performAction()); toolbarButton.addActionListener(actionEvent -> performAction());
setEnabled(false); //disabled by default. Will be enabled in Case.java when a case is opened. 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 @Override

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2017 Basis Technology Corp. * Copyright 2017-18 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -43,11 +43,11 @@ import org.sleuthkit.datamodel.TskCoreException;
/** /**
* Node for a relationship, as represented by a BlackboardArtifact. * 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()); private static final Logger logger = Logger.getLogger(RelationshipNode.class.getName());
public RelationshipNode(BlackboardArtifact artifact) { RelationshipNode(BlackboardArtifact artifact) {
super(artifact); super(artifact);
final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s"); final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s");
String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message"); String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message");
@ -113,6 +113,9 @@ public class RelationshipNode extends BlackboardArtifactNode {
break; break;
} }
} }
addTagProperty(ss);
return s; 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();
}
} }

View 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.");
}
}
}
}

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.communications;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
import org.sleuthkit.datamodel.Account; 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 * Get the path of the icon for the given Account Type.
* the path but will include the extension.
* *
* @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) { static final String getIconFilePath(Account.Type type) {
if (type.equals(Account.Type.CREDIT_CARD)) { return Accounts.getIconFilePath(type);
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());
}
} }
} }

View File

@ -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>

View File

@ -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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -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();
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 928 B

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013-15 Basis Technology Corp. * Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -59,6 +59,7 @@ import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProvider;
import org.openide.util.lookup.ServiceProviders; import org.openide.util.lookup.ServiceProviders;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.Installer; import org.sleuthkit.autopsy.core.Installer;
import org.sleuthkit.autopsy.corecomponents.FrameCapture; import org.sleuthkit.autopsy.corecomponents.FrameCapture;
import org.sleuthkit.autopsy.corecomponents.VideoFrame; import org.sleuthkit.autopsy.corecomponents.VideoFrame;
@ -136,7 +137,13 @@ public class FXVideoPanel extends MediaViewVideoPanel {
mediaPane.setInfoLabelText(path); mediaPane.setInfoLabelText(path);
mediaPane.setInfoLabelToolTipText(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(); new Thread(mediaPane.new ExtractMedia(currentFile, tempFile)).start();

View File

@ -36,7 +36,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.FileTypeViewer;
/** /**
* Generic Application content viewer * 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 { public class FileViewer extends javax.swing.JPanel implements DataContentViewer {
private static final int CONFIDENCE_LEVEL = 7; private static final int CONFIDENCE_LEVEL = 7;

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013-15 Basis Technology Corp. * Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -55,6 +55,7 @@ import org.netbeans.api.progress.ProgressHandle;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProvider;
import org.openide.util.lookup.ServiceProviders; import org.openide.util.lookup.ServiceProviders;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corecomponents.FrameCapture; import org.sleuthkit.autopsy.corecomponents.FrameCapture;
import org.sleuthkit.autopsy.corecomponents.VideoFrame; import org.sleuthkit.autopsy.corecomponents.VideoFrame;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -181,6 +182,7 @@ public class GstVideoPanel extends MediaViewVideoPanel {
} }
@Override @Override
@NbBundle.Messages ({"GstVideoPanel.noOpenCase.errMsg=No open case available."})
void setupVideo(final AbstractFile file, final Dimension dims) { void setupVideo(final AbstractFile file, final Dimension dims) {
reset(); reset();
infoLabel.setText(""); infoLabel.setText("");
@ -194,6 +196,18 @@ public class GstVideoPanel extends MediaViewVideoPanel {
return; 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 = ""; String path = "";
try { try {
path = file.getUniquePath(); path = file.getUniquePath();
@ -205,7 +219,6 @@ public class GstVideoPanel extends MediaViewVideoPanel {
pauseButton.setEnabled(true); pauseButton.setEnabled(true);
progressSlider.setEnabled(true); progressSlider.setEnabled(true);
java.io.File ioFile = VideoUtils.getTempVideoFile(file);
gstVideoComponent = new VideoComponent(); gstVideoComponent = new VideoComponent();
synchronized (playbinLock) { synchronized (playbinLock) {
@ -537,7 +550,14 @@ public class GstVideoPanel extends MediaViewVideoPanel {
return; return;
} }
} else if (state.equals(State.READY)) { } 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(); new ExtractMedia(currentFile, tempVideoFile).execute();

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2017 Basis Technology Corp. * Copyright 2017-18 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -70,7 +70,7 @@ import org.sleuthkit.datamodel.TskCoreException;
/** /**
* Shows SMS/MMS/EMail messages * 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 { public class MessageContentViewer extends javax.swing.JPanel implements DataContentViewer {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -90,7 +90,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
*/ */
private BlackboardArtifact artifact; private BlackboardArtifact artifact;
private final DataResultPanel drp; private final DataResultPanel drp;
private final ExplorerManager drpExplorerManager; private ExplorerManager drpExplorerManager;
/** /**
* Creates new MessageContentViewer * Creates new MessageContentViewer
@ -108,6 +108,12 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
Utilities.configureTextPaneAsRtf(rtfbodyTextPane); Utilities.configureTextPaneAsRtf(rtfbodyTextPane);
resetComponent(); resetComponent();
}
@Override
public void addNotify() {
super.addNotify(); //To change body of generated methods, choose Tools | Templates.
drp.open(); drp.open();
drpExplorerManager = drp.getExplorerManager(); drpExplorerManager = drp.getExplorerManager();
drpExplorerManager.addPropertyChangeListener(evt -> drpExplorerManager.addPropertyChangeListener(evt ->
@ -706,7 +712,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
private static class AttachmentNode extends FileNode { private static class AttachmentNode extends FileNode {
AttachmentNode(AbstractFile file) { AttachmentNode(AbstractFile file) {
super(file, true); super(file, false);
} }
@Override @Override

View File

@ -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 * 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. * 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 { public class Metadata extends javax.swing.JPanel implements DataContentViewer {
/** /**

View File

@ -35,11 +35,13 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.text.ParseException; import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.ListSelectionModel; import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.TableCellRenderer; import javax.swing.table.TableCellRenderer;
@ -50,7 +52,9 @@ import org.openide.explorer.ExplorerManager;
import org.openide.nodes.AbstractNode; import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children; import org.openide.nodes.Children;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.xml.sax.SAXException; 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 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(); 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")); fileChooser.setFileFilter(new FileNameExtensionFilter("XML file", "xml"));
final int returnVal = fileChooser.showSaveDialog(this); final int returnVal = fileChooser.showSaveDialog(this);
@ -262,35 +279,50 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E
* *
* @return none * @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) { private void processPlist(final AbstractFile plistFile) {
final byte[] plistFileBuf = new byte[(int) plistFile.getSize()]; new SwingWorker<List<PropKeyValue>, Void>() {
try { @Override
plistFile.read(plistFileBuf, 0, plistFile.getSize()); protected List<PropKeyValue> doInBackground() throws TskCoreException, IOException, PropertyListFormatException, ParseException, ParserConfigurationException, SAXException {
} catch (TskCoreException ex) { // Read in and parse the file
LOGGER.log(Level.SEVERE, "Error reading bytes of plist file.", ex); final byte[] plistFileBuf = new byte[(int) plistFile.getSize()];
} plistFile.read(plistFileBuf, 0, plistFile.getSize());
final List<PropKeyValue> plist = parsePList(plistFileBuf);
final List<PropKeyValue> plist;
try { return plist;
plist = parsePList(plistFileBuf); }
new SwingWorker<Void, Void>() {
@Override @Override
protected Void doInBackground() { protected void done() {
super.done();
List<PropKeyValue> plist;
try {
plist = get();
setupTable(plist); setupTable(plist);
return null;
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);
} }
@Override }
protected void done() { }.execute();
super.done();
setColumnWidths();
}
}.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);
}
} }
/** /**

View File

@ -39,9 +39,13 @@ import java.util.TreeMap;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.casemodule.services.Services;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -50,32 +54,27 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.corecomponentinterfaces.FileTypeViewer; 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 { 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"}; 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 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 numRows; // num of rows in the selected table
private int currPage = 0; // curr page of rows being displayed private int currPage = 0; // curr page of rows being displayed
SQLiteTableView selectedTableView = new SQLiteTableView();
private SwingWorker<? extends Object, ? extends Object> worker; private SwingWorker<? extends Object, ? extends Object> worker;
/** /**
* Creates new form SQLiteViewer * Constructs a file content viewer for SQLite database files.
*/ */
public SQLiteViewer() { public SQLiteViewer() {
initComponents(); initComponents();
@ -214,7 +213,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed
currPage++; currPage++;
if (currPage * ROWS_PER_PAGE > numRows) { if (currPage * ROWS_PER_PAGE > numRows) {
nextPageButton.setEnabled(false); nextPageButton.setEnabled(false);
@ -228,7 +226,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
}//GEN-LAST:event_nextPageButtonActionPerformed }//GEN-LAST:event_nextPageButtonActionPerformed
private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed
currPage--; currPage--;
if (currPage == 1) { if (currPage == 1) {
prevPageButton.setEnabled(false); prevPageButton.setEnabled(false);
@ -247,7 +244,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
if (null == tableName) { if (null == tableName) {
return; return;
} }
selectTable(tableName); selectTable(tableName);
}//GEN-LAST:event_tablesDropdownListActionPerformed }//GEN-LAST:event_tablesDropdownListActionPerformed
@ -273,7 +269,8 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
@Override @Override
public void setFile(AbstractFile file) { public void setFile(AbstractFile file) {
processSQLiteFile(file); sqliteDbFile = file;
processSQLiteFile();
} }
@Override @Override
@ -283,9 +280,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
@Override @Override
public void resetComponent() { public void resetComponent() {
dbTablesMap.clear();
tablesDropdownList.setEnabled(true); tablesDropdownList.setEnabled(true);
tablesDropdownList.removeAllItems(); tablesDropdownList.removeAllItems();
numEntriesField.setText(""); numEntriesField.setText("");
@ -296,146 +290,151 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
connection.close(); connection.close();
connection = null; connection = null;
} catch (SQLException ex) { } 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 // delete last temp file
if (null != tmpDBFile) { if (null != tmpDbFile) {
tmpDBFile.delete(); tmpDbFile.delete();
tmpDBFile = null; tmpDbFile = null;
} }
sqliteDbFile = null;
} }
/** /**
* Process the given SQLite DB file * Process the given SQLite DB file.
*
* @param sqliteFile -
*
* @return none
*/ */
private void processSQLiteFile(AbstractFile sqliteFile) { @NbBundle.Messages({
"SQLiteViewer.comboBox.noTableEntry=No tables found",
tablesDropdownList.removeAllItems(); "SQLiteViewer.errorMessage.interrupted=The processing of the file was interrupted.",
"SQLiteViewer.errorMessage.noCurrentCase=The case has been closed.",
new SwingWorker<Boolean, Void>() { "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<Map<String, String>, Void>() {
@Override @Override
protected Boolean doInBackground() throws Exception { protected Map<String, String> doInBackground() throws NoCurrentCaseException, TskCoreException, IOException, SQLException, ClassNotFoundException {
// Copy the file to temp folder
String tmpDBPathName = Case.getOpenCase().getTempDirectory() + File.separator + sqliteDbFile.getName();
tmpDbFile = new File(tmpDBPathName);
ContentUtils.writeToFile(sqliteDbFile, tmpDbFile);
try { // Look for any meta files associated with this DB - WAL, SHM, etc.
// Copy the file to temp folder findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-wal");
tmpDBPathName = Case.getCurrentCase().getTempDirectory() + File.separator + sqliteFile.getName(); findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-shm");
tmpDBFile = new File(tmpDBPathName);
ContentUtils.writeToFile(sqliteFile, tmpDBFile);
// look for any meta files associated with this DB - WAL, SHM // Load the SQLite JDBC driver, if necessary.
findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-wal"); Class.forName("org.sqlite.JDBC"); //NON-NLS
findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-shm"); connection = DriverManager.getConnection("jdbc:sqlite:" + tmpDBPathName); //NON-NLS
// Open copy using JDBC // Query the file for the table names and schemas.
Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver return getTables();
connection = DriverManager.getConnection("jdbc:sqlite:" + tmpDBPathName); //NON-NLS
// Read all table names and schema
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 @Override
protected void done() { protected void done() {
super.done(); super.done();
try { try {
boolean status = get(); Map<String, String> dbTablesMap = get();
if ((status == true) && (dbTablesMap.size() > 0)) { if (dbTablesMap.isEmpty()) {
tablesDropdownList.addItem(Bundle.SQLiteViewer_comboBox_noTableEntry());
tablesDropdownList.setEnabled(false);
} else {
dbTablesMap.keySet().forEach((tableName) -> { dbTablesMap.keySet().forEach((tableName) -> {
tablesDropdownList.addItem(tableName); tablesDropdownList.addItem(tableName);
}); });
} else {
// Populate error message
tablesDropdownList.addItem("No tables found");
tablesDropdownList.setEnabled(false);
} }
} catch (InterruptedException | ExecutionException ex) { } catch (InterruptedException ex) {
LOGGER.log(Level.SEVERE, "Unexpected exception while opening DB file", ex); //NON-NLS 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(); }.execute();
} }
/** /**
* Searches for a meta file associated with the give SQLite db * Searches for a meta file associated with the give SQLite db If found,
* If found, copies the file to the temp folder * copies the file to the temp folder
* *
* @param sqliteFile - SQLIte db file being processed * @param sqliteFile - SQLIte db file being processed
* @param metaFileName name of meta file to look for * @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 ) { private void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException {
Case openCase = Case.getOpenCase();
SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase(); SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase();
Services services = new Services(sleuthkitCase); Services services = new Services(sleuthkitCase);
FileManager fileManager = services.getFileManager(); FileManager fileManager = services.getFileManager();
List<AbstractFile> metaFiles = fileManager.findFiles(sqliteFile.getDataSource(), metaFileName, sqliteFile.getParent().getName());
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;
}
if (metaFiles != null) { if (metaFiles != null) {
for (AbstractFile metaFile: metaFiles) { 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); File tmpMetafile = new File(tmpMetafilePathName);
try { ContentUtils.writeToFile(metaFile, tmpMetafile);
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 { try {
Statement statement = connection.createStatement(); statement = connection.createStatement();
resultSet = statement.executeQuery(
ResultSet resultSet = statement.executeQuery(
"SELECT name, sql FROM sqlite_master " "SELECT name, sql FROM sqlite_master "
+ " WHERE type= 'table' " + " WHERE type= 'table' "
+ " ORDER BY name;"); //NON-NLS + " ORDER BY name;"); //NON-NLS
while (resultSet.next()) { while (resultSet.next()) {
String tableName = resultSet.getString("name"); //NON-NLS String tableName = resultSet.getString("name"); //NON-NLS
String tableSQL = resultSet.getString("sql"); //NON-NLS String tableSQL = resultSet.getString("sql"); //NON-NLS
dbTablesMap.put(tableName, tableSQL); dbTablesMap.put(tableName, tableSQL);
} }
} catch (SQLException e) { } finally {
LOGGER.log(Level.SEVERE, "Error getting table names from the DB", e); //NON-NLS if (null != resultSet) {
resultSet.close();
}
if (null != statement) {
statement.close();
}
} }
return true; return dbTablesMap;
} }
@NbBundle.Messages({"# {0} - tableName",
"SQLiteViewer.selectTable.errorText=Error getting row count for table: {0}"
})
private void selectTable(String tableName) { private void selectTable(String tableName) {
if (worker != null && !worker.isDone()) { if (worker != null && !worker.isDone()) {
worker.cancel(false); worker.cancel(false);
@ -446,17 +445,24 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
@Override @Override
protected Integer doInBackground() throws Exception { protected Integer doInBackground() throws Exception {
Statement statement = null;
ResultSet resultSet = null;
try { try {
Statement statement = connection.createStatement(); statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery( resultSet = statement.executeQuery(
"SELECT count (*) as count FROM " + tableName); //NON-NLS "SELECT count (*) as count FROM " + tableName); //NON-NLS
return resultSet.getInt("count"); return resultSet.getInt("count");
} catch (SQLException ex) { } 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 @Override
@ -473,7 +479,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
prevPageButton.setEnabled(false); prevPageButton.setEnabled(false);
if (numRows > 0) { if (numRows > 0) {
nextPageButton.setEnabled(((numRows > ROWS_PER_PAGE))); nextPageButton.setEnabled(((numRows > ROWS_PER_PAGE)));
readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, 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()); selectedTableView.setupTable(Collections.emptyList());
} }
} catch (InterruptedException | ExecutionException ex) { } catch (InterruptedException ex) {
LOGGER.log(Level.SEVERE, "Unexpected exception while reading table.", ex); //NON-NLS 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(); worker.execute();
} }
@NbBundle.Messages({"# {0} - tableName",
"SQLiteViewer.readTable.errorText=Error getting rows for table: {0}"})
private void readTable(String tableName, int startRow, int numRowsToRead) { private void readTable(String tableName, int startRow, int numRowsToRead) {
if (worker != null && !worker.isDone()) { 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>() { worker = new SwingWorker<ArrayList<Map<String, Object>>, Void>() {
@Override @Override
protected ArrayList<Map<String, Object>> doInBackground() throws Exception { protected ArrayList<Map<String, Object>> doInBackground() throws Exception {
Statement statement = null;
ResultSet resultSet = null;
try { try {
Statement statement = connection.createStatement(); statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery( resultSet = statement.executeQuery(
"SELECT * FROM " + tableName "SELECT * FROM " + tableName
+ " LIMIT " + Integer.toString(numRowsToRead) + " LIMIT " + Integer.toString(numRowsToRead)
+ " OFFSET " + Integer.toString(startRow - 1) + " OFFSET " + Integer.toString(startRow - 1)
@ -510,10 +530,15 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
return resultSetToArrayList(resultSet); return resultSetToArrayList(resultSet);
} catch (SQLException ex) { } 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 @Override
@ -528,11 +553,21 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
ArrayList<Map<String, Object>> rows = get(); ArrayList<Map<String, Object>> rows = get();
if (Objects.nonNull(rows)) { if (Objects.nonNull(rows)) {
selectedTableView.setupTable(rows); selectedTableView.setupTable(rows);
}else{ } else {
selectedTableView.setupTable(Collections.emptyList()); selectedTableView.setupTable(Collections.emptyList());
} }
} catch (InterruptedException | ExecutionException ex) { } catch (InterruptedException ex) {
LOGGER.log(Level.SEVERE, "Unexpected exception while reading table " + tableName, ex); //NON-NLS 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);
} }
} }
}; };

View File

@ -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 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 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()) private static final Set<String> servicesList = Stream.of(ServicesMonitor.Service.values())
.map(Service::toString) .map(Service::toString)
@ -143,7 +143,7 @@ public class ServicesMonitor {
* services. * services.
*/ */
periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build()); 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);
} }
/** /**

Some files were not shown because too many files have changed in this diff Show More