diff --git a/Core/ivy.xml b/Core/ivy.xml index 4250c385a4..601077eb91 100644 --- a/Core/ivy.xml +++ b/Core/ivy.xml @@ -6,6 +6,13 @@ + + + + + + + diff --git a/Core/ivysettings.xml b/Core/ivysettings.xml index c27d905255..7a4d38c65e 100644 --- a/Core/ivysettings.xml +++ b/Core/ivysettings.xml @@ -3,7 +3,8 @@ - + + diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index b8360a3b05..02df4b01bb 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -6,6 +6,7 @@ file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4. file.reference.dd-plist-1.20.jar=release\\modules\\ext\\dd-plist-1.20.jar file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar +file.reference.jgraphx-v3.8.0.jar=release/modules/ext/jgraphx-v3.8.0.jar file.reference.jsoup-1.10.3.jar=release/modules/ext/jsoup-1.10.3.jar file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 36270dd889..0159ec9880 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -15,6 +15,15 @@ 1.27.1.121 + + org.jdesktop.layout + + + + 1 + 1.33.1 + + org.netbeans.api.progress @@ -349,6 +358,14 @@ ext/curator-framework-2.8.0.jar release/modules/ext/curator-framework-2.8.0.jar + + ext/commons-dbcp2-2.1.1.jar + release/modules/ext/commons-dbcp2-2.1.1.jar + + + ext/jgraphx-v3.8.0.jar + release/modules/ext/jgraphx-v3.8.0.jar + ext/commons-compress-1.14.jar release/modules/ext/commons-compress-1.14.jar diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties index 84f64f3190..1cbc4b70b6 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties @@ -36,10 +36,10 @@ GetTagNameDialog.tagNameExistsTskCore.msg=The {0} tag name already exists in the OpenLogFolder.error1=Log File Not Found: {0} OpenLogFolder.CouldNotOpenLogFolder=Could not open log folder CTL_OpenLogFolder=Open Log Folder -CTL_OpenOutputFolder=Open Case Folder -OpenOutputFolder.error1=Case Output Folder Not Found\: {0} -OpenOutputFolder.noCaseOpen=No open case, therefore no current case output folder available. -OpenOutputFolder.CouldNotOpenOutputFolder=Could not open case output folder +CTL_OpenOutputFolder=Open Output Folder +OpenOutputFolder.error1=Output Folder Not Found\: {0} +OpenOutputFolder.noCaseOpen=No open case, therefore no current output folder available. +OpenOutputFolder.CouldNotOpenOutputFolder=Could not open output folder ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot OpenPythonModulesFolderAction.actionName.text=Python Plugins OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python plugins folder not found: {0} diff --git a/Core/src/org/sleuthkit/autopsy/actions/OpenOutputFolderAction.java b/Core/src/org/sleuthkit/autopsy/actions/OpenOutputFolderAction.java index 9e71c29fa9..c79a559b2d 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/OpenOutputFolderAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/OpenOutputFolderAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2018 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; /** - * The action associated with the Tools/Open Case Folder menu item. It opens a + * The action associated with the Tools/Open Output Folder menu item. It opens a * file explorer window for the root output directory for the currently open * case. If the case is a single-user case, this is the case directory. If the * case is a multi-user case, this is a subdirectory of the case directory @@ -46,7 +46,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; * This action should only be invoked in the event dispatch thread (EDT). */ @ActionRegistration(displayName = "#CTL_OpenOutputFolder", iconInMenu = true, lazy = false) -@ActionReference(path = "Menu/Case", position = 302) +@ActionReference(path = "Menu/Tools", position = 1850, separatorBefore = 1849) @ActionID(id = "org.sleuthkit.autopsy.actions.OpenOutputFolderAction", category = "Help") public final class OpenOutputFolderAction extends CallableSystemAction { @@ -63,7 +63,7 @@ public final class OpenOutputFolderAction extends CallableSystemAction { try { Desktop.getDesktop().open(outputDir); } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Failed to open case output folder %s", outputDir), ex); //NON-NLS + logger.log(Level.SEVERE, String.format("Failed to open output folder %s", outputDir), ex); //NON-NLS NotifyDescriptor descriptor = new NotifyDescriptor.Message( NbBundle.getMessage(this.getClass(), "OpenOutputFolder.CouldNotOpenOutputFolder", outputDir.getAbsolutePath()), NotifyDescriptor.ERROR_MESSAGE); DialogDisplayer.getDefault().notify(descriptor); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index f6458e6dd0..21a7bca103 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -107,9 +107,15 @@ class AddImageTask implements Runnable { */ @Override public void run() { + Case currentCase; + try { + currentCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); + return; + } progressMonitor.setIndeterminate(true); progressMonitor.setProgress(0); - Case currentCase = Case.getCurrentCase(); String imageWriterPath = ""; if (imageWriterSettings != null) { imageWriterPath = imageWriterSettings.getPath(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java index 6204d8fb27..e4034d65b3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java @@ -29,6 +29,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.UUID; +import java.util.logging.Level; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; @@ -46,6 +47,7 @@ import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.ShortcutWizardDescriptorPanel; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.autopsy.coreutils.Logger; /** * The final panel of the add image wizard. It displays a progress bar and @@ -331,7 +333,11 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel { cleanupTask.enable(); new Thread(() -> { - Case.getCurrentCase().notifyAddingDataSource(dataSourceId); + try { + Case.getOpenCase().notifyAddingDataSource(dataSourceId); + } catch (NoCurrentCaseException ex) { + Logger.getLogger(AddImageWizardAddingProgressVisual.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + } }).start(); DataSourceProcessorCallback cbObj = new DataSourceProcessorCallback() { @Override @@ -398,10 +404,14 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel { //notify the UI of the new content added to the case new Thread(() -> { - if (!contents.isEmpty()) { - Case.getCurrentCase().notifyDataSourceAdded(contents.get(0), dataSourceId); - } else { - Case.getCurrentCase().notifyFailedAddingDataSource(dataSourceId); + try { + if (!contents.isEmpty()) { + Case.getOpenCase().notifyDataSourceAdded(contents.get(0), 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(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 86c18870f7..8775013512 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -583,6 +583,8 @@ public class Case { } /** + * Deprecated. Use getOpenCase() instead. + * * Gets the current case, if there is one, at the time of the call. * * @return The current case. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java index 357b1f4704..2b333e2bdc 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java @@ -66,7 +66,7 @@ final class CaseDeleteAction extends CallableSystemAction { "# {0} - exception message", "Case.deleteCaseFailureMessageBox.message=Error deleting case: {0}",}) public void actionPerformed(ActionEvent e) { try { - Case currentCase = Case.getCurrentCase(); + Case currentCase = Case.getOpenCase(); String caseName = currentCase.getName(); String caseDirectory = currentCase.getCaseDirectory(); @@ -110,7 +110,7 @@ final class CaseDeleteAction extends CallableSystemAction { } }.execute(); } - } catch (IllegalStateException ex) { + } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Case delete action called with no current case", ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseInformationPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseInformationPanel.java index e3afa329d9..76c280f6b2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseInformationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseInformationPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2018 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,9 +20,11 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.logging.Level; import javax.swing.JDialog; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import org.sleuthkit.autopsy.coreutils.Logger; import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; @@ -51,7 +53,11 @@ class CaseInformationPanel extends javax.swing.JPanel { "CaseInformationPanel.editDetailsDialog.title=Edit Case Details" }) private void customizeComponents() { - propertiesPanel = new CasePropertiesPanel(Case.getCurrentCase()); + try { + propertiesPanel = new CasePropertiesPanel(Case.getOpenCase()); + } catch (NoCurrentCaseException ex) { + Logger.getLogger(CaseInformationPanel.class.getName()).log(Level.INFO, "Exception while getting open case.", ex); + } propertiesPanel.setSize(propertiesPanel.getPreferredSize()); this.tabbedPane.addTab(Bundle.CaseInformationPanel_caseDetails_header(), propertiesPanel); this.tabbedPane.addTab(Bundle.CaseInformationPanel_ingestJobInfo_header(), new IngestJobInfoPanel()); @@ -59,11 +65,6 @@ class CaseInformationPanel extends javax.swing.JPanel { @Override public void stateChanged(ChangeEvent e) { tabbedPane.getSelectedComponent().setSize(tabbedPane.getSelectedComponent().getPreferredSize()); - if (tabbedPane.getSelectedComponent() instanceof CasePropertiesPanel) { - editDetailsButton.setVisible(true); - } else { - editDetailsButton.setVisible(false); - } } }); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.java index 3dfe261302..c020e7b033 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.java @@ -49,7 +49,12 @@ final class CasePropertiesPanel extends javax.swing.JPanel { } void updateCaseInfo() { - theCase = Case.getCurrentCase(); + try { + theCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); + return; + } lbCaseNameText.setText(theCase.getDisplayName()); lbCaseNumberText.setText(theCase.getNumber()); lbExaminerNameText.setText(theCase.getExaminer()); @@ -78,9 +83,9 @@ final class CasePropertiesPanel extends javax.swing.JPanel { try { EamDb dbManager = EamDb.getInstance(); if (dbManager != null) { - CorrelationCase correlationCase = dbManager.getCase(Case.getCurrentCase()); + CorrelationCase correlationCase = dbManager.getCase(theCase); if (null == correlationCase) { - correlationCase = dbManager.newCase(Case.getCurrentCase()); + correlationCase = dbManager.newCase(theCase); } currentOrg = correlationCase.getOrg(); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java b/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java index ab55b67c5b..5758d5d8b5 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java @@ -122,8 +122,8 @@ final class CollaborationMonitor { * 2. Check for stale remote tasks.
*/ periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build()); - periodicTasksExecutor.scheduleAtFixedRate(new HeartbeatTask(), HEARTBEAT_INTERVAL_MINUTES, HEARTBEAT_INTERVAL_MINUTES, TimeUnit.MINUTES); - periodicTasksExecutor.scheduleAtFixedRate(new StaleTaskDetectionTask(), STALE_TASKS_DETECT_INTERVAL_MINS, STALE_TASKS_DETECT_INTERVAL_MINS, TimeUnit.MINUTES); + periodicTasksExecutor.scheduleWithFixedDelay(new HeartbeatTask(), HEARTBEAT_INTERVAL_MINUTES, HEARTBEAT_INTERVAL_MINUTES, TimeUnit.MINUTES); + periodicTasksExecutor.scheduleWithFixedDelay(new StaleTaskDetectionTask(), STALE_TASKS_DETECT_INTERVAL_MINS, STALE_TASKS_DETECT_INTERVAL_MINS, TimeUnit.MINUTES); } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 29ad64e672..6fa73b7ff7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -31,6 +31,7 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.filechooser.FileFilter; import org.apache.commons.lang3.StringUtils; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import static org.sleuthkit.autopsy.casemodule.Bundle.*; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; @@ -306,7 +307,9 @@ public class ImageFilePanel extends JPanel implements DocumentListener { * * @return true if a proper image has been selected, false otherwise */ - @NbBundle.Messages("ImageFilePanel.pathValidation.dataSourceOnCDriveError=Warning: Path to multi-user data source is on \"C:\" drive") + @NbBundle.Messages({"ImageFilePanel.pathValidation.dataSourceOnCDriveError=Warning: Path to multi-user data source is on \"C:\" drive", + "ImageFilePanel.pathValidation.getOpenCase.Error=Warning: Exception while getting open case." + }) public boolean validatePanel() { pathErrorLabel.setVisible(false); String path = getContentPaths(); @@ -315,9 +318,14 @@ public class ImageFilePanel extends JPanel implements DocumentListener { } // Display warning if there is one (but don't disable "next" button) - if (false == PathValidator.isValid(path, Case.getCurrentCase().getCaseType())) { + try { + if (false == PathValidator.isValid(path, Case.getOpenCase().getCaseType())) { + pathErrorLabel.setVisible(true); + pathErrorLabel.setText(Bundle.ImageFilePanel_pathValidation_dataSourceOnCDriveError()); + } + } catch (NoCurrentCaseException ex) { pathErrorLabel.setVisible(true); - pathErrorLabel.setText(Bundle.ImageFilePanel_pathValidation_dataSourceOnCDriveError()); + pathErrorLabel.setText(Bundle.ImageFilePanel_pathValidation_getOpenCase_Error()); } return new File(path).isFile() diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java index 37e4a8fb02..8a496d8fac 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java @@ -75,12 +75,12 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { } private void refresh() { - SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); try { + SleuthkitCase skCase = Case.getOpenCase().getSleuthkitCase(); List ingestJobs = skCase.getIngestJobs(); this.ingestJobs = ingestJobs; this.repaint(); - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Failed to load ingest jobs.", ex); JOptionPane.showMessageDialog(this, Bundle.IngestJobInfoPanel_loadIngestJob_error_text(), Bundle.IngestJobInfoPanel_loadIngestJob_error_title(), JOptionPane.ERROR_MESSAGE); } @@ -114,11 +114,11 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { @Override public Object getValueAt(int rowIndex, int columnIndex) { IngestJobInfo currIngestJob = ingestJobs.get(rowIndex); - SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); if (columnIndex == 0) { try { + SleuthkitCase skCase = Case.getOpenCase().getSleuthkitCase(); return skCase.getContentById(currIngestJob.getObjectId()).getName(); - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Failed to get content from db", ex); return ""; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java index 774a68ffc6..cfba224f1c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java @@ -31,6 +31,7 @@ import javax.swing.JPanel; import javax.swing.filechooser.FileFilter; import org.apache.commons.io.FilenameUtils; import org.openide.modules.InstalledFileLocator; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java index 834cf4295b..b1554eb080 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java @@ -275,17 +275,23 @@ final class LocalFilesPanel extends javax.swing.JPanel { * * @param paths Absolute paths to the selected data source */ + @NbBundle.Messages("LocalFilesPanel.pathValidation.error=WARNING: Exception while gettting opon case.") private void warnIfPathIsInvalid(final List pathsList) { errorLabel.setVisible(false); - final Case.CaseType currentCaseType = Case.getCurrentCase().getCaseType(); + try { + final Case.CaseType currentCaseType = Case.getOpenCase().getCaseType(); - for (String currentPath : pathsList) { - if (!PathValidator.isValid(currentPath, currentCaseType)) { - errorLabel.setVisible(true); - errorLabel.setText(NbBundle.getMessage(this.getClass(), "DataSourceOnCDriveError.text")); - return; + for (String currentPath : pathsList) { + if (!PathValidator.isValid(currentPath, currentCaseType)) { + errorLabel.setVisible(true); + errorLabel.setText(NbBundle.getMessage(this.getClass(), "DataSourceOnCDriveError.text")); + return; + } } + } catch (NoCurrentCaseException ex) { + errorLabel.setVisible(true); + errorLabel.setText(Bundle.LocalFilesPanel_pathValidation_error()); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LogicalEvidenceFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LogicalEvidenceFilePanel.java index 106c5165f0..4e70d4b248 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LogicalEvidenceFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LogicalEvidenceFilePanel.java @@ -32,6 +32,7 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; +import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PathValidator; @@ -178,7 +179,8 @@ final class LogicalEvidenceFilePanel extends javax.swing.JPanel implements Docum */ @Messages({ "LogicalEvidenceFilePanel.validatePanel.nonL01Error.text=Only files with the .l01 file extension are supported here.", - "LogicalEvidenceFilePanel.pathValidation.dataSourceOnCDriveError=Warning: Path to multi-user data source is on \"C:\" drive" + "LogicalEvidenceFilePanel.pathValidation.dataSourceOnCDriveError=Warning: Path to multi-user data source is on \"C:\" drive", + "LogicalEvidenceFilePanel.pathValidation.getOpenCase.Error=Warning: Exception while getting open case." }) boolean validatePanel() { errorLabel.setVisible(false); @@ -188,9 +190,15 @@ final class LogicalEvidenceFilePanel extends javax.swing.JPanel implements Docum return false; } // display warning if there is one (but don't disable "next" button) - if (!PathValidator.isValid(path, Case.getCurrentCase().getCaseType())) { + try { + if (!PathValidator.isValid(path, Case.getOpenCase().getCaseType())) { + errorLabel.setVisible(true); + errorLabel.setText(Bundle.LogicalEvidenceFilePanel_pathValidation_dataSourceOnCDriveError()); + return false; + } + } catch (NoCurrentCaseException ex) { errorLabel.setVisible(true); - errorLabel.setText(Bundle.LogicalEvidenceFilePanel_pathValidation_dataSourceOnCDriveError()); + errorLabel.setText(Bundle.LogicalEvidenceFilePanel_pathValidation_getOpenCase_Error()); return false; } //check the extension incase the path was manually entered diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/OptionalCasePropertiesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/OptionalCasePropertiesPanel.java index 74374c6577..0dae889f5b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/OptionalCasePropertiesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/OptionalCasePropertiesPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -62,12 +62,19 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel { OptionalCasePropertiesPanel(boolean editCurrentCase) { initComponents(); if (editCurrentCase) { - caseDisplayNameTextField.setText(Case.getCurrentCase().getDisplayName()); - caseNumberTextField.setText(Case.getCurrentCase().getNumber()); - examinerTextField.setText(Case.getCurrentCase().getExaminer()); - tfExaminerEmailText.setText(Case.getCurrentCase().getExaminerEmail()); - tfExaminerPhoneText.setText(Case.getCurrentCase().getExaminerPhone()); - taNotesText.setText(Case.getCurrentCase().getCaseNotes()); + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); + return; + } + caseDisplayNameTextField.setText(openCase.getDisplayName()); + caseNumberTextField.setText(openCase.getNumber()); + examinerTextField.setText(openCase.getExaminer()); + tfExaminerEmailText.setText(openCase.getExaminerEmail()); + tfExaminerPhoneText.setText(openCase.getExaminerPhone()); + taNotesText.setText(openCase.getCaseNotes()); setUpCaseDetailsFields(); setUpOrganizationData(); } else { @@ -86,15 +93,18 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel { private void setUpOrganizationData() { if (EamDb.isEnabled()) { - Case currentCase = Case.getCurrentCase(); - if (currentCase != null) { - try { + try { + Case currentCase = Case.getOpenCase(); + if (currentCase != null) { EamDb dbManager = EamDb.getInstance(); selectedOrg = dbManager.getCase(currentCase).getOrg(); - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Unable to get Organization associated with the case from Central Repo", ex); } + } catch (EamDbException ex) { + LOGGER.log(Level.SEVERE, "Unable to get Organization associated with the case from Central Repo", ex); + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); } + if (selectedOrg != null) { setCurrentlySelectedOrganization(selectedOrg.getName()); } @@ -533,7 +543,8 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel { @Messages({ "OptionalCasePropertiesPanel.errorDialog.emptyCaseNameMessage=No case name entered.", - "OptionalCasePropertiesPanel.errorDialog.invalidCaseNameMessage=Case names cannot include the following symbols: \\, /, :, *, ?, \", <, >, |" + "OptionalCasePropertiesPanel.errorDialog.invalidCaseNameMessage=Case names cannot include the following symbols: \\, /, :, *, ?, \", <, >, |", + "OptionalCasePropertiesPanel.errorDialog.noOpenCase.errMsg=Exception while getting open case." }) void saveUpdatedCaseDetails() { if (caseDisplayNameTextField.getText().trim().isEmpty()) { @@ -544,14 +555,19 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel { MessageNotifyUtil.Message.error(Bundle.OptionalCasePropertiesPanel_errorDialog_invalidCaseNameMessage()); return; } - updateCaseDetails(); + try { + updateCaseDetails(); + } catch (NoCurrentCaseException ex) { + MessageNotifyUtil.Message.error(Bundle.OptionalCasePropertiesPanel_errorDialog_noOpenCase_errMsg()); + return; + } updateCorrelationCase(); } - private void updateCaseDetails() { + private void updateCaseDetails() throws NoCurrentCaseException { if (caseDisplayNameTextField.isVisible()) { try { - Case.getCurrentCase().updateCaseDetails(new CaseDetails( + Case.getOpenCase().updateCaseDetails(new CaseDetails( caseDisplayNameTextField.getText(), caseNumberTextField.getText(), examinerTextField.getText(), tfExaminerPhoneText.getText(), tfExaminerEmailText.getText(), taNotesText.getText())); @@ -570,7 +586,7 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel { if (EamDb.isEnabled()) { try { EamDb dbManager = EamDb.getInstance(); - CorrelationCase correlationCase = dbManager.getCase(Case.getCurrentCase()); + CorrelationCase correlationCase = dbManager.getCase(Case.getOpenCase()); if (caseDisplayNameTextField.isVisible()) { correlationCase.setDisplayName(caseDisplayNameTextField.getText()); } @@ -582,7 +598,9 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel { correlationCase.setNotes(taNotesText.getText()); dbManager.updateCase(correlationCase); } 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 { setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/events/BlackBoardArtifactTagAddedEvent.java b/Core/src/org/sleuthkit/autopsy/casemodule/events/BlackBoardArtifactTagAddedEvent.java index 3c3d15aec8..ad08e643fd 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/events/BlackBoardArtifactTagAddedEvent.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/events/BlackBoardArtifactTagAddedEvent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule.events; import java.io.Serializable; import javax.annotation.concurrent.Immutable; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.TskCoreException; @@ -41,11 +42,11 @@ public class BlackBoardArtifactTagAddedEvent extends TagAddedEvent sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule.events; import java.io.Serializable; import javax.annotation.concurrent.Immutable; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TskCoreException; @@ -41,10 +42,10 @@ public class ContentTagAddedEvent extends TagAddedEvent implements S * * @return ContentTag that was added * - * @throws IllegalStateException + * @throws NoCurrentCaseException * @throws TskCoreException */ - ContentTag getTagByID() throws IllegalStateException, TskCoreException { - return Case.getCurrentCase().getServices().getTagsManager().getContentTagByTagID(getTagID()); + ContentTag getTagByID() throws NoCurrentCaseException, TskCoreException { + return Case.getOpenCase().getServices().getTagsManager().getContentTagByTagID(getTagID()); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/events/DataSourceAddedEvent.java b/Core/src/org/sleuthkit/autopsy/casemodule/events/DataSourceAddedEvent.java index aa02c07846..dcf575a5dc 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/events/DataSourceAddedEvent.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/events/DataSourceAddedEvent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +22,7 @@ import java.io.Serializable; import java.util.UUID; import java.util.logging.Level; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.datamodel.Content; @@ -78,9 +79,9 @@ public final class DataSourceAddedEvent extends AutopsyEvent implements Serializ } try { long id = (Long) super.getNewValue(); - dataSource = Case.getCurrentCase().getSleuthkitCase().getContentById(id); + dataSource = Case.getOpenCase().getSleuthkitCase().getContentById(id); return dataSource; - } catch (IllegalStateException | TskCoreException ex) { + } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS return null; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/events/ReportAddedEvent.java b/Core/src/org/sleuthkit/autopsy/casemodule/events/ReportAddedEvent.java index 534f6b646a..2fe152d32e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/events/ReportAddedEvent.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/events/ReportAddedEvent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +22,7 @@ import java.io.Serializable; import java.util.List; import java.util.logging.Level; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.datamodel.Report; @@ -69,7 +70,7 @@ public final class ReportAddedEvent extends AutopsyEvent implements Serializable } try { long id = (Long) super.getNewValue(); - List reports = Case.getCurrentCase().getSleuthkitCase().getAllReports(); + List reports = Case.getOpenCase().getSleuthkitCase().getAllReports(); for (Report thisReport : reports) { if (thisReport.getId() == id) { report = thisReport; @@ -77,7 +78,7 @@ public final class ReportAddedEvent extends AutopsyEvent implements Serializable } } return report; - } catch (IllegalStateException | TskCoreException ex) { + } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS return null; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/events/TagAddedEvent.java b/Core/src/org/sleuthkit/autopsy/casemodule/events/TagAddedEvent.java index 1f679c47a3..6d7ebb4f9c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/events/TagAddedEvent.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/events/TagAddedEvent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.casemodule.events; import java.io.Serializable; import java.util.logging.Level; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.datamodel.Tag; @@ -84,7 +85,7 @@ abstract class TagAddedEvent extends AutopsyEvent implements Seri try { tag = getTagByID(); return tag; - } catch (IllegalStateException | TskCoreException ex) { + } catch (NoCurrentCaseException | TskCoreException ex) { Logger.getLogger(TagAddedEvent.class.getName()).log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS return null; } @@ -98,8 +99,8 @@ abstract class TagAddedEvent extends AutopsyEvent implements Seri * * @return the Tag based on the saved tag id * - * @throws IllegalStateException + * @throws NoCurrentCaseException * @throws TskCoreException */ - abstract T getTagByID() throws IllegalStateException, TskCoreException; + abstract T getTagByID() throws NoCurrentCaseException, TskCoreException; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java index dba0d7aac4..5c978f6378 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,6 +28,7 @@ import java.util.logging.Level; import javax.annotation.concurrent.Immutable; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.datamodel.TagName; @@ -295,9 +296,11 @@ final class TagNameDefinition implements Comparable { setting.append(";"); } setting.append(tagName.toSettingsFormat()); - if (Case.isCaseOpen()) { - SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase(); + try { + SleuthkitCase caseDb = Case.getOpenCase().getSleuthkitCase(); tagName.saveToCase(caseDb); + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); } } ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java index 874bcc77bc..5073f4110b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java @@ -24,6 +24,7 @@ import java.beans.PropertyChangeListener; import java.util.HashSet; import java.util.Set; import java.util.TreeSet; +import java.util.logging.Level; import javax.swing.DefaultListModel; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; @@ -32,10 +33,12 @@ import org.netbeans.spi.options.OptionsPanelController; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.autopsy.coreutils.Logger; /** * A panel to allow the user to create and delete custom tag types. @@ -421,8 +424,10 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { private void sendStatusChangedEvents() { for (String modifiedTagDisplayName : updatedStatusTags) { //if user closes their case after options have been changed but before application of them is complete don't notify - if (Case.isCaseOpen()) { - Case.getCurrentCase().notifyTagDefinitionChanged(modifiedTagDisplayName); + try { + Case.getOpenCase().notifyTagDefinitionChanged(modifiedTagDisplayName); + } catch (NoCurrentCaseException ex) { + Logger.getLogger(TagOptionsPanel.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS } } updatedStatusTags.clear(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 8d7eda2ec4..b38165ef5c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,6 +29,7 @@ import java.util.Set; import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; @@ -98,11 +99,11 @@ public class TagsManager implements Closeable { tagDisplayNames.add(tagType.getDisplayName()); }); try { - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + TagsManager tagsManager = Case.getOpenCase().getServices().getTagsManager(); for (TagName tagName : tagsManager.getAllTagNames()) { tagDisplayNames.add(tagName.getDisplayName()); } - } catch (IllegalStateException ignored) { + } catch (NoCurrentCaseException ignored) { /* * No current case, nothing more to add to the set. */ @@ -339,8 +340,8 @@ public class TagsManager implements Closeable { ContentTag tag; tag = caseDb.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); try { - Case.getCurrentCase().notifyContentTagAdded(tag); - } catch (IllegalStateException ex) { + Case.getOpenCase().notifyContentTagAdded(tag); + } catch (NoCurrentCaseException ex) { throw new TskCoreException("Added a tag to a closed case", ex); } return tag; @@ -357,8 +358,8 @@ public class TagsManager implements Closeable { public void deleteContentTag(ContentTag tag) throws TskCoreException { caseDb.deleteContentTag(tag); try { - Case.getCurrentCase().notifyContentTagDeleted(tag); - } catch (IllegalStateException ex) { + Case.getOpenCase().notifyContentTagDeleted(tag); + } catch (NoCurrentCaseException ex) { throw new TskCoreException("Deleted a tag from a closed case", ex); } } @@ -469,8 +470,8 @@ public class TagsManager implements Closeable { public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { BlackboardArtifactTag tag = caseDb.addBlackboardArtifactTag(artifact, tagName, comment); try { - Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(tag); - } catch (IllegalStateException ex) { + Case.getOpenCase().notifyBlackBoardArtifactTagAdded(tag); + } catch (NoCurrentCaseException ex) { throw new TskCoreException("Added a tag to a closed case", ex); } return tag; @@ -487,8 +488,8 @@ public class TagsManager implements Closeable { public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { caseDb.deleteBlackboardArtifactTag(tag); try { - Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); - } catch (IllegalStateException ex) { + Case.getOpenCase().notifyBlackBoardArtifactTagDeleted(tag); + } catch (NoCurrentCaseException ex) { throw new TskCoreException("Deleted a tag from a closed case", ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index c098112efa..c16d16d70c 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2017 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -46,6 +46,7 @@ import org.openide.nodes.Node; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; @@ -97,7 +98,11 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D } else if (jmi.equals(showCaseDetailsMenuItem)) { showCaseDetails(otherCasesTable.getSelectedRow()); } else if (jmi.equals(exportToCSVMenuItem)) { - saveToCSV(); + try { + saveToCSV(); + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS + } } else if (jmi.equals(showCommonalityMenuItem)) { showCommonalityDetails(); } @@ -159,8 +164,19 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D @Messages({"DataContentViewerOtherCases.caseDetailsDialog.notSelected=No Row Selected", "DataContentViewerOtherCases.caseDetailsDialog.noDetails=No details for this case.", "DataContentViewerOtherCases.caseDetailsDialog.noDetailsReference=No case details for Global reference properties.", - "DataContentViewerOtherCases.caseDetailsDialog.noCaseNameError=Error"}) + "DataContentViewerOtherCases.caseDetailsDialog.noCaseNameError=Error", + "DataContentViewerOtherCases.noOpenCase.errMsg=No open case available."}) private void showCaseDetails(int selectedRowViewIdx) { + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + JOptionPane.showConfirmDialog(showCaseDetailsMenuItem, + Bundle.DataContentViewerOtherCases_noOpenCase_errMsg(), + Bundle.DataContentViewerOtherCases_noOpenCase_errMsg(), + DEFAULT_OPTION, PLAIN_MESSAGE); + return; + } String caseDisplayName = Bundle.DataContentViewerOtherCases_caseDetailsDialog_noCaseNameError(); try { if (-1 != selectedRowViewIdx) { @@ -177,7 +193,7 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D } caseDisplayName = eamCasePartial.getDisplayName(); // query case details - CorrelationCase eamCase = dbManager.getCase(Case.getCurrentCase()); + CorrelationCase eamCase = dbManager.getCase(openCase); if (eamCase == null) { JOptionPane.showConfirmDialog(showCaseDetailsMenuItem, Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(), @@ -205,11 +221,11 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D } } - private void saveToCSV() { + private void saveToCSV() throws NoCurrentCaseException { if (0 != otherCasesTable.getSelectedRowCount()) { Calendar now = Calendar.getInstance(); String fileName = String.format("%1$tY%1$tm%1$te%1$tI%1$tM%1$tS_other_data_sources.csv", now); - CSVFileChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory())); + CSVFileChooser.setCurrentDirectory(new File(Case.getOpenCase().getExportDirectory())); CSVFileChooser.setSelectedFile(new File(fileName)); CSVFileChooser.setFileFilter(new FileNameExtensionFilter("csv file", "csv")); @@ -417,8 +433,8 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D */ private Collection getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) { // @@@ Check exception - String caseUUID = Case.getCurrentCase().getName(); try { + String caseUUID = Case.getOpenCase().getName(); EamDb dbManager = EamDb.getInstance(); Collection artifactInstances = dbManager.getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).stream() .filter(artifactInstance -> !artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID) @@ -428,6 +444,8 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D return artifactInstances; } catch (EamDbException ex) { LOGGER.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS } return Collections.emptyList(); @@ -473,9 +491,9 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D if (af != null) { Content dataSource = af.getDataSource(); dataSourceName = dataSource.getName(); - deviceId = Case.getCurrentCase().getSleuthkitCase().getDataSource(dataSource.getId()).getDeviceId(); + deviceId = Case.getOpenCase().getSleuthkitCase().getDataSource(dataSource.getId()).getDeviceId(); } - } catch (TskException ex) { + } catch (TskException | NoCurrentCaseException ex) { // do nothing. // @@@ Review this behavior } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index 18af7f6c81..b929956b1c 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -2334,7 +2334,7 @@ public abstract class AbstractSqlEamDb implements EamDb { } CorrelationAttributeInstance eamArtifactInstance = new CorrelationAttributeInstance( new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), resultSet.getString("case_name")), - new CorrelationDataSource(resultSet.getInt("case_id"), -1, resultSet.getString("device_id"), resultSet.getString("name")), + new CorrelationDataSource(-1, resultSet.getInt("case_id"), resultSet.getString("device_id"), resultSet.getString("name")), resultSet.getString("file_path"), resultSet.getString("comment"), TskData.FileKnown.valueOf(resultSet.getByte("known_status")) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationDataSource.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationDataSource.java index 9aa9fada32..cba529954e 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationDataSource.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationDataSource.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2017 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.centralrepository.datamodel; import java.io.Serializable; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskDataException; @@ -73,8 +74,8 @@ public class CorrelationDataSource implements Serializable { public static CorrelationDataSource fromTSKDataSource(CorrelationCase correlationCase, Content dataSource) throws EamDbException { Case curCase; try { - curCase = Case.getCurrentCase(); - } catch (IllegalStateException ex) { + curCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { throw new EamDbException("Autopsy case is closed"); } String deviceId; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java index c0810b52d3..43812eeebf 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2017 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,6 +23,7 @@ import java.util.List; import java.util.logging.Level; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -89,7 +90,7 @@ public class EamArtifactUtil { // if they asked for it, add the instance details associated with this occurance. if (!eamArtifacts.isEmpty() && addInstanceDetails) { try { - Case currentCase = Case.getCurrentCase(); + Case currentCase = Case.getOpenCase(); AbstractFile bbSourceFile = currentCase.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID()); if (null == bbSourceFile) { //@@@ Log this @@ -97,9 +98,9 @@ public class EamArtifactUtil { } // make an instance for the BB source file - CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getCurrentCase()); + CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getOpenCase()); if (null == correlationCase) { - correlationCase = EamDb.getInstance().newCase(Case.getCurrentCase()); + correlationCase = EamDb.getInstance().newCase(Case.getOpenCase()); } CorrelationAttributeInstance eamInstance = new CorrelationAttributeInstance( correlationCase, @@ -116,7 +117,7 @@ public class EamArtifactUtil { } catch (TskCoreException | EamDbException ex) { LOGGER.log(Level.SEVERE, "Error creating artifact instance.", ex); // NON-NLS return eamArtifacts; - } catch (IllegalStateException ex) { + } catch (NoCurrentCaseException ex) { LOGGER.log(Level.SEVERE, "Case is closed.", ex); // NON-NLS return eamArtifacts; } @@ -145,7 +146,7 @@ public class EamArtifactUtil { // Get the associated artifact BlackboardAttribute attribute = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); if (attribute != null) { - BlackboardArtifact associatedArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong()); + BlackboardArtifact associatedArtifact = Case.getOpenCase().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong()); return EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(correlationType, associatedArtifact); } @@ -203,6 +204,9 @@ public class EamArtifactUtil { } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS return null; + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS + return null; } if (null != value) { @@ -250,9 +254,9 @@ public class EamArtifactUtil { try { CorrelationAttribute.Type filesType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID); eamArtifact = new CorrelationAttribute(filesType, af.getMd5Hash()); - CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getCurrentCase()); + CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getOpenCase()); if (null == correlationCase) { - correlationCase = EamDb.getInstance().newCase(Case.getCurrentCase()); + correlationCase = EamDb.getInstance().newCase(Case.getOpenCase()); } CorrelationAttributeInstance cei = new CorrelationAttributeInstance( correlationCase, @@ -263,7 +267,7 @@ public class EamArtifactUtil { ); eamArtifact.addInstance(cei); return eamArtifact; - } catch (TskCoreException | EamDbException ex) { + } catch (TskCoreException | EamDbException | NoCurrentCaseException ex) { LOGGER.log(Level.SEVERE, "Error making correlation attribute.", ex); return null; } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index b053d9df17..da11671a08 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2017 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,6 +28,7 @@ import java.util.logging.Level; import java.util.stream.Collectors; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; @@ -162,8 +163,8 @@ final class CaseEventListener implements PropertyChangeListener { try { // Get the remaining tags on the content object - Content content = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID); - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + Content content = Case.getOpenCase().getSleuthkitCase().getContentById(contentID); + TagsManager tagsManager = Case.getOpenCase().getServices().getTagsManager(); List tags = tagsManager.getContentTagsByContent(content); if (tags.stream() @@ -185,7 +186,7 @@ final class CaseEventListener implements PropertyChangeListener { // There's still at least one bad tag, so leave the known status as is return; } - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { LOGGER.log(Level.SEVERE, "Failed to find content", ex); return; } @@ -241,6 +242,13 @@ final class CaseEventListener implements PropertyChangeListener { return; } } else { //BLACKBOARD_ARTIFACT_TAG_DELETED + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); + return; + } // For deleted tags, we want to set the file status to UNKNOWN if: // - The tag that was just removed is notable in central repo // - There are no remaining tags that are notable @@ -256,9 +264,9 @@ final class CaseEventListener implements PropertyChangeListener { try { // Get the remaining tags on the artifact - content = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID); - bbArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(artifactID); - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + content = openCase.getSleuthkitCase().getContentById(contentID); + bbArtifact = openCase.getSleuthkitCase().getBlackboardArtifact(artifactID); + TagsManager tagsManager = openCase.getServices().getTagsManager(); List tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact); if (tags.stream() @@ -319,10 +327,10 @@ final class CaseEventListener implements PropertyChangeListener { * that are tagged with the given tag name. */ try { - TagName tagName = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(modifiedTagName); + TagName tagName = Case.getOpenCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(modifiedTagName); //First update the artifacts //Get all BlackboardArtifactTags with this tag name - List artifactTags = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTagsByTagName(tagName); + List artifactTags = Case.getOpenCase().getSleuthkitCase().getBlackboardArtifactTagsByTagName(tagName); for (BlackboardArtifactTag bbTag : artifactTags) { //start with assumption that none of the other tags applied to this Correlation Attribute will prevent it's status from being changed boolean hasTagWithConflictingKnownStatus = false; @@ -338,7 +346,7 @@ final class CaseEventListener implements PropertyChangeListener { } //Get the BlackboardArtifact which this BlackboardArtifactTag has been applied to. BlackboardArtifact bbArtifact = bbTag.getArtifact(); - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + TagsManager tagsManager = Case.getOpenCase().getServices().getTagsManager(); List tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact); //get all tags which are on this blackboard artifact for (BlackboardArtifactTag t : tags) { @@ -366,7 +374,7 @@ final class CaseEventListener implements PropertyChangeListener { } // Next update the files - List fileTags = Case.getCurrentCase().getSleuthkitCase().getContentTagsByTagName(tagName); + List fileTags = Case.getOpenCase().getSleuthkitCase().getContentTagsByTagName(tagName); //Get all ContentTags with this tag name for (ContentTag contentTag : fileTags) { //start with assumption that none of the other tags applied to this ContentTag will prevent it's status from being changed @@ -376,7 +384,7 @@ final class CaseEventListener implements PropertyChangeListener { // the status of the file in the central repository if (tagName.getKnownStatus() == TskData.FileKnown.UNKNOWN) { Content content = contentTag.getContent(); - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + TagsManager tagsManager = Case.getOpenCase().getServices().getTagsManager(); List tags = tagsManager.getContentTagsByContent(content); //get all tags which are on this file for (ContentTag t : tags) { @@ -405,6 +413,8 @@ final class CaseEventListener implements PropertyChangeListener { LOGGER.log(Level.SEVERE, "Cannot update known status in central repository for tag: " + modifiedTagName, ex); //NON-NLS } catch (EamDbException ex) { LOGGER.log(Level.SEVERE, "Cannot get central repository for tag: " + modifiedTagName, ex); //NON-NLS + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS } } //TAG_STATUS_CHANGED } @@ -424,15 +434,22 @@ final class CaseEventListener implements PropertyChangeListener { if (!EamDb.isEnabled()) { return; } + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); + return; + } final DataSourceAddedEvent dataSourceAddedEvent = (DataSourceAddedEvent) event; Content newDataSource = dataSourceAddedEvent.getDataSource(); try { - String deviceId = Case.getCurrentCase().getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId(); - CorrelationCase correlationCase = dbManager.getCase(Case.getCurrentCase()); + String deviceId = openCase.getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId(); + CorrelationCase correlationCase = dbManager.getCase(openCase); if (null == correlationCase) { - correlationCase = dbManager.newCase(Case.getCurrentCase()); + correlationCase = dbManager.newCase(openCase); } if (null == dbManager.getDataSource(correlationCase, deviceId)) { dbManager.newDataSource(CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource)); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 0877bc1685..258cb13dcf 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2017 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,6 +32,7 @@ import java.util.logging.Level; import java.util.stream.Collectors; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -144,9 +145,9 @@ public class IngestEventsListener { tifArtifact.addAttributes(attributes); try { // index the artifact for keyword search - Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard(); + Blackboard blackboard = Case.getOpenCase().getServices().getBlackboard(); blackboard.indexArtifact(tifArtifact); - } catch (Blackboard.BlackboardException ex) { + } catch (Blackboard.BlackboardException | NoCurrentCaseException ex) { LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index 09f3c63449..9657cdcd19 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,6 +26,7 @@ import java.util.stream.Collectors; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -79,7 +80,12 @@ class IngestModule implements FileIngestModule { return ProcessResult.OK; } - blackboard = Case.getCurrentCase().getServices().getBlackboard(); + try { + blackboard = Case.getOpenCase().getServices().getBlackboard(); + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); + return ProcessResult.ERROR; + } if (!EamArtifactUtil.isValidCentralRepoFile(af)) { return ProcessResult.OK; @@ -190,8 +196,16 @@ class IngestModule implements FileIngestModule { } return; } + Case autopsyCase; + try { + autopsyCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); + throw new IngestModuleException("Exception while getting open case.", ex); + } + // Don't allow sqlite central repo databases to be used for multi user cases - if ((Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) + if ((autopsyCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) && (EamDbPlatformEnum.getSelectedPlatform() == EamDbPlatformEnum.SQLITE)) { LOGGER.log(Level.SEVERE, "Cannot run correlation engine on a multi-user case with a SQLite central repository."); throw new IngestModuleException("Cannot run on a multi-user case with a SQLite central repository."); // NON-NLS @@ -212,7 +226,7 @@ class IngestModule implements FileIngestModule { LOGGER.log(Level.SEVERE, "Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS throw new IngestModuleException("Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS } - Case autopsyCase = Case.getCurrentCase(); + try { eamCase = centralRepoDb.getCase(autopsyCase); } catch (EamDbException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties index 9faba7a7b3..0106566831 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties @@ -58,3 +58,10 @@ ManageCorrelationPropertiesDialog.okButton.text=OK GlobalSettingsPanel.bnManageProperties.text=Manage Correlation Properties EamDbSettingsDialog.lbDatabaseDesc.text=Database File: EamDbSettingsDialog.lbFullDbPath.text= +GlobalSettingsPanel.cbUseCentralRepo.text=Use a central repository +GlobalSettingsPanel.correlationPropertiesTextArea.text=Choose which file and result properties to store in the central repository for later correlation.\n +GlobalSettingsPanel.organizationTextArea.text=Organization information can be tracked in the central repository. +GlobalSettingsPanel.manageOrganizationButton.text=Manage Organizations +GlobalSettingsPanel.lbCentralRepository.text=A central repository allows you to correlate files and results between cases. +GlobalSettingsPanel.pnCorrelationProperties.border.title=Correlation Properties +GlobalSettingsPanel.organizationPanel.border.title=Organizations diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form index c53942cc0c..788fef4660 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form @@ -3,6 +3,9 @@
+ + + @@ -19,352 +22,393 @@ - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - + + - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + - - - - - - - + - diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java index 8b0a1b6b93..28a34d6777 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java @@ -58,22 +58,8 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i addIngestJobEventsListener(); } - @Messages({"GlobalSettingsPanel.title=Central Repository Settings", - "GlobalSettingsPanel.cbUseCentralRepo.text=Use a central repository", - "GlobalSettingsPanel.pnTagManagement.border.title=Tags", - "GlobalSettingsPanel.pnCorrelationProperties.border.title=Correlation Properties", - "GlobalSettingsPanel.lbCentralRepository.text=A central repository allows you to correlate files and results between cases.", - "GlobalSettingsPanel.manageTagsTextArea.text=Configure which tag names are associated with notable items. " - + "When these tags are used, the file or result will be recorded in the central repository. " - + "If that file or result is seen again in future cases, it will be flagged.", - "GlobalSettingsPanel.correlationPropertiesTextArea.text=Choose which file and result properties to store in the central repository for later correlation.", - "GlobalSettingsPanel.organizationPanel.border.title=Organizations", - "GlobalSettingsPanel.manageOrganizationButton.text=Manage Organizations", - "GlobalSettingsPanel.organizationTextArea.text=Organization information can be tracked in the central repository" - }) - private void customizeComponents() { - setName(Bundle.GlobalSettingsPanel_title()); + setName(NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnCorrelationProperties.border.title")); } private void addIngestJobEventsListener() { @@ -116,6 +102,10 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i // //GEN-BEGIN:initComponents private void initComponents() { + jScrollPane1 = new javax.swing.JScrollPane(); + jPanel1 = new javax.swing.JPanel(); + lbCentralRepository = new javax.swing.JLabel(); + cbUseCentralRepo = new javax.swing.JCheckBox(); pnDatabaseConfiguration = new javax.swing.JPanel(); lbDbPlatformTypeLabel = new javax.swing.JLabel(); lbDbNameLabel = new javax.swing.JLabel(); @@ -124,19 +114,33 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i lbDbPlatformValue = new javax.swing.JLabel(); lbDbNameValue = new javax.swing.JLabel(); lbDbLocationValue = new javax.swing.JLabel(); - cbUseCentralRepo = new javax.swing.JCheckBox(); - tbOops = new javax.swing.JTextField(); pnCorrelationProperties = new javax.swing.JPanel(); bnManageTypes = new javax.swing.JButton(); correlationPropertiesScrollPane = new javax.swing.JScrollPane(); correlationPropertiesTextArea = new javax.swing.JTextArea(); - lbCentralRepository = new javax.swing.JLabel(); organizationPanel = new javax.swing.JPanel(); manageOrganizationButton = new javax.swing.JButton(); organizationScrollPane = new javax.swing.JScrollPane(); organizationTextArea = new javax.swing.JTextArea(); + tbOops = new javax.swing.JTextField(); setName(""); // NOI18N + setPreferredSize(new java.awt.Dimension(1022, 488)); + + jScrollPane1.setBorder(null); + jScrollPane1.setPreferredSize(new java.awt.Dimension(1022, 407)); + + jPanel1.setMinimumSize(new java.awt.Dimension(0, 0)); + jPanel1.setPreferredSize(new java.awt.Dimension(1020, 407)); + + org.openide.awt.Mnemonics.setLocalizedText(lbCentralRepository, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.lbCentralRepository.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(cbUseCentralRepo, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.cbUseCentralRepo.text")); // NOI18N + cbUseCentralRepo.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cbUseCentralRepoActionPerformed(evt); + } + }); pnDatabaseConfiguration.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnDatabaseConfiguration.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N @@ -194,18 +198,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i .addGap(8, 8, 8)) ); - org.openide.awt.Mnemonics.setLocalizedText(cbUseCentralRepo, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.cbUseCentralRepo.text")); // NOI18N - cbUseCentralRepo.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - cbUseCentralRepoActionPerformed(evt); - } - }); - - tbOops.setEditable(false); - tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12)); - tbOops.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.tbOops.text")); // NOI18N - tbOops.setBorder(null); - pnCorrelationProperties.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnCorrelationProperties.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N pnCorrelationProperties.setPreferredSize(new java.awt.Dimension(674, 93)); @@ -253,8 +245,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i .addGap(8, 8, 8)) ); - org.openide.awt.Mnemonics.setLocalizedText(lbCentralRepository, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.lbCentralRepository.text")); // NOI18N - organizationPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.organizationPanel.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(manageOrganizationButton, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.manageOrganizationButton.text")); // NOI18N @@ -300,38 +290,58 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i .addGap(8, 8, 8)) ); + tbOops.setEditable(false); + tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12)); + tbOops.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.tbOops.text")); // NOI18N + tbOops.setBorder(null); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbCentralRepository, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(cbUseCentralRepo) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 974, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(36, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pnCorrelationProperties, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 1012, Short.MAX_VALUE) + .addComponent(organizationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(lbCentralRepository) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cbUseCentralRepo) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pnCorrelationProperties, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(organizationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 92, Short.MAX_VALUE)) + ); + + jScrollPane1.setViewportView(jPanel1); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(tbOops, javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(organizationPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addComponent(lbCentralRepository, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(pnCorrelationProperties, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 349, Short.MAX_VALUE) - .addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(cbUseCentralRepo, javax.swing.GroupLayout.Alignment.LEADING)) - .addContainerGap()))) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(lbCentralRepository) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cbUseCentralRepo) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(pnCorrelationProperties, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(organizationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 488, Short.MAX_VALUE) ); }// //GEN-END:initComponents @@ -523,6 +533,8 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i private javax.swing.JCheckBox cbUseCentralRepo; private javax.swing.JScrollPane correlationPropertiesScrollPane; private javax.swing.JTextArea correlationPropertiesTextArea; + private javax.swing.JPanel jPanel1; + private javax.swing.JScrollPane jScrollPane1; private javax.swing.JLabel lbCentralRepository; private javax.swing.JLabel lbDbLocationLabel; private javax.swing.JLabel lbDbLocationValue; diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountDetailsNode.java b/Core/src/org/sleuthkit/autopsy/communications/AccountDetailsNode.java index 88470e87e0..39eae2b9f3 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountDetailsNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountDetailsNode.java @@ -25,6 +25,7 @@ import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; +import org.python.google.common.collect.Iterables; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AccountDeviceInstance; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -38,12 +39,16 @@ import org.sleuthkit.datamodel.TskCoreException; * relationships of all the accounts in this node. * */ -class AccountDetailsNode extends AbstractNode { +final class AccountDetailsNode extends AbstractNode { private final static Logger logger = Logger.getLogger(AccountDetailsNode.class.getName()); AccountDetailsNode(Set accountDeviceInstances, CommunicationsFilter filter, CommunicationsManager commsManager) { super(Children.create(new AccountRelationshipChildren(accountDeviceInstances, commsManager, filter), true)); + String displayName = (accountDeviceInstances.size() == 1) + ? Iterables.getOnlyElement(accountDeviceInstances).getAccount().getTypeSpecificID() + : accountDeviceInstances.size() + " accounts"; + setDisplayName(displayName); } /** diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceKey.java b/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceKey.java index fbc2c17feb..0e89e3a1b6 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceKey.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceKey.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017 Basis Technology Corp. + * Copyright 2017-18 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,23 +18,31 @@ */ package org.sleuthkit.autopsy.communications; +import java.util.Objects; +import java.util.logging.Level; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AccountDeviceInstance; import org.sleuthkit.datamodel.CommunicationsFilter; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; /** * Key for AccountDeviceInstance node. * - * Encapsulates a AccountDeviceInstance, and CommunicationsFilter. + * Encapsulates a AccountDeviceInstanc,some meta data about it, and + * CommunicationsFilter. */ -class AccountDeviceInstanceKey { +final class AccountDeviceInstanceKey { + + private static final Logger logger = Logger.getLogger(AccountDeviceInstanceKey.class.getName()); private final AccountDeviceInstance accountDeviceInstance; private final CommunicationsFilter filter; private final long messageCount; private final String dataSourceName; - - AccountDeviceInstanceKey(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter, long msgCount, String dataSourceName) { this.accountDeviceInstance = accountDeviceInstance; this.filter = filter; @@ -42,6 +50,13 @@ class AccountDeviceInstanceKey { this.dataSourceName = dataSourceName; } + AccountDeviceInstanceKey(AccountDeviceInstance accountDeviceInstance, CommunicationsFilter filter, long msgCount) { + this.accountDeviceInstance = accountDeviceInstance; + this.filter = filter; + this.messageCount = msgCount; + this.dataSourceName = getDataSourceName(accountDeviceInstance, Case.getCurrentCase().getSleuthkitCase()); + } + AccountDeviceInstance getAccountDeviceInstance() { return accountDeviceInstance; } @@ -53,8 +68,56 @@ class AccountDeviceInstanceKey { long getMessageCount() { return messageCount; } - + String getDataSourceName() { return dataSourceName; } + + @Override + public String toString() { + return accountDeviceInstance.getAccount().getTypeSpecificID(); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 37 * hash + Objects.hashCode(this.accountDeviceInstance); + hash = 37 * hash + (int) (this.messageCount ^ (this.messageCount >>> 32)); + hash = 37 * hash + Objects.hashCode(this.dataSourceName); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final AccountDeviceInstanceKey other = (AccountDeviceInstanceKey) obj; + if (this.messageCount != other.messageCount) { + return false; + } + if (!Objects.equals(this.dataSourceName, other.dataSourceName)) { + return false; + } + return Objects.equals(this.accountDeviceInstance, other.accountDeviceInstance); + } + + private static String getDataSourceName(AccountDeviceInstance accountDeviceInstance, SleuthkitCase db) { + try { + for (DataSource dataSource : db.getDataSources()) { + if (dataSource.getDeviceId().equals(accountDeviceInstance.getDeviceId())) { + return db.getContentById(dataSource.getId()).getName(); + } + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error getting datasource name, falling back on device ID.", ex); + } + return accountDeviceInstance.getDeviceId(); + } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java b/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java new file mode 100644 index 0000000000..40cb15d27d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNode.java @@ -0,0 +1,159 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017-18 Basis Technology Corp. + * Contact: carrier sleuthkit 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 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 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 lookupAll = + Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstanceKey.class); + CVTEvents.getCVTEventBus().post(new CVTEvents.PinAccountsEvent(lookupAll, true)); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNodeFactory.java new file mode 100644 index 0000000000..49ae86d62b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountDeviceInstanceNodeFactory.java @@ -0,0 +1,75 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017-18 Basis Technology Corp. + * Contact: carrier sleuthkit 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 { + + 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 list) { + List accountDeviceInstanceKeys = new ArrayList<>(); + try { + final List 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); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.form b/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.form index 83a3e75e9a..8642d90664 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.form +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.form @@ -11,30 +11,28 @@ + - - - - - - - - - - - - - - - - - - - - + - + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java index 8e418d65fb..9827b4bec3 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AccountsBrowser.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017 Basis Technology Corp. + * Copyright 2017-18 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,9 @@ */ package org.sleuthkit.autopsy.communications; +import com.google.common.eventbus.Subscribe; import java.awt.Component; +import java.util.logging.Level; import javax.swing.JPanel; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; @@ -26,21 +28,41 @@ import javax.swing.table.TableCellRenderer; import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; +import org.openide.explorer.ExplorerUtils; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.util.Lookup; +import org.openide.util.lookup.ProxyLookup; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.CommunicationsManager; +import org.sleuthkit.datamodel.TskCoreException; /** * A panel that goes in the Browse tab of the Communications Visualization Tool. - * Hosts an OutlineView that shows information about Accounts. + * Hosts an OutlineView that shows information about Accounts, and a + * MessageBrowser for viewing details of communications. + * + * The Lookup provided by getLookup will be proxied by the lookup of the + * CVTTopComponent when this tab is active allowing for context sensitive + * actions to work correctly. */ -public class AccountsBrowser extends JPanel { +public final class AccountsBrowser extends JPanel implements ExplorerManager.Provider, Lookup.Provider { private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(AccountsBrowser.class.getName()); private final Outline outline; - private ExplorerManager em; - /** - * Creates new form AccountsBrowser + private final ExplorerManager messageBrowserEM = new ExplorerManager(); + private final ExplorerManager accountsTableEM = new ExplorerManager(); + + /* + * This lookup proxies the selection lookup of both he accounts table and + * the messages table. */ + private final ProxyLookup proxyLookup; + public AccountsBrowser() { initComponents(); outline = outlineView.getOutline(); @@ -54,19 +76,21 @@ public class AccountsBrowser extends JPanel { ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AccountNode_accountName()); outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); outline.setColumnSorted(3, false, 1); //it would be nice if the column index wasn't hardcoded - } - @Override - public void addNotify() { - super.addNotify(); - em = ExplorerManager.find(this); - em.addPropertyChangeListener(evt -> { + accountsTableEM.addPropertyChangeListener(evt -> { if (ExplorerManager.PROP_ROOT_CONTEXT.equals(evt.getPropertyName())) { SwingUtilities.invokeLater(this::setColumnWidths); } else if (ExplorerManager.PROP_EXPLORED_CONTEXT.equals(evt.getPropertyName())) { SwingUtilities.invokeLater(this::setColumnWidths); } }); + final MessageBrowser messageBrowser = new MessageBrowser(accountsTableEM, messageBrowserEM); + + jSplitPane1.setRightComponent(messageBrowser); + + proxyLookup = new ProxyLookup( + messageBrowser.getLookup(), + ExplorerUtils.createLookup(accountsTableEM, getActionMap())); } private void setColumnWidths() { @@ -93,6 +117,16 @@ public class AccountsBrowser extends JPanel { } } + @Subscribe + public void handleFilterEvent(CVTEvents.FilterChangeEvent filterChangeEvent) { + try { + final CommunicationsManager commsManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager(); + accountsTableEM.setRootContext(new AbstractNode(Children.create(new AccountDeviceInstanceNodeFactory(commsManager, filterChangeEvent.getNewFilter()), true))); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "There was an error getting the CommunicationsManager for the current case.", ex); + } + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -102,28 +136,29 @@ public class AccountsBrowser extends JPanel { // //GEN-BEGIN:initComponents private void initComponents() { + jSplitPane1 = new javax.swing.JSplitPane(); outlineView = new org.openide.explorer.view.OutlineView(); - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 0, 0) - .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE) - .addGap(0, 0, 0)) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 0, 0) - .addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE) - .addGap(0, 0, 0)) - ); + setLayout(new java.awt.BorderLayout()); + + jSplitPane1.setLeftComponent(outlineView); + + add(jSplitPane1, java.awt.BorderLayout.CENTER); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JSplitPane jSplitPane1; private org.openide.explorer.view.OutlineView outlineView; // End of variables declaration//GEN-END:variables + + @Override + public ExplorerManager getExplorerManager() { + return accountsTableEM; + } + + @Override + public Lookup getLookup() { + return proxyLookup; + } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/AccountsRootChildren.java b/Core/src/org/sleuthkit/autopsy/communications/AccountsRootChildren.java deleted file mode 100644 index 63e1e17d82..0000000000 --- a/Core/src/org/sleuthkit/autopsy/communications/AccountsRootChildren.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2017 Basis Technology Corp. - * Contact: carrier sleuthkit 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 { - - 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 list) { - List 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; - } - } -} diff --git a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties index 0f1b490d78..96d76fe34a 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/communications/Bundle.properties @@ -15,3 +15,31 @@ FiltersPanel.refreshButton.text=Refresh FiltersPanel.deviceRequiredLabel.text=Select at least one. FiltersPanel.accountTypeRequiredLabel.text=Select at least one. FiltersPanel.needsRefreshLabel.text=Displayed data is out of date. Press Refresh. +VisualizationPanel.jButton1.text=Fast Organic +CVTTopComponent.vizPanel.TabConstraints.tabTitle=Visualize +CVTTopComponent.accountsBrowser.TabConstraints.tabTitle_1=Browse +CVTTopComponent.browseVisualizeTabPane.AccessibleContext.accessibleName=Visualize +CVTTopComponent.vizPanel.TabConstraints.tabTitle_1=Visualize +VisualizationPanel.jButton6.text=Hierarchy +VisualizationPanel.jButton7.text=Circle +VisualizationPanel.jButton8.text=Organic +VisualizationPanel.fitGraphButton.text= +VisualizationPanel.zoomOutButton.text= +# To change this license header, choose License Headers in Project Properties. +# To change this template file, choose Tools | Templates +# and open the template in the editor. +VisualizationPanel.circleLayoutButton.text=Circle +VisualizationPanel.organicLayoutButton.text=Organic +VisualizationPanel.fastOrganicLayoutButton.text=Fast Organic +VisualizationPanel.hierarchyLayoutButton.text=Hierarchy +VisualizationPanel.zoomLabel.text=100% +VisualizationPanel.jLabel1.text=Layouts: +VisualizationPanel.jLabel2.text=Zoom: +VisualizationPanel.fitZoomButton.toolTipText=fit visualization +VisualizationPanel.fitZoomButton.text= +VisualizationPanel.jTextArea1.text=Right-click an account in the Browse Accounts table, and select 'Visualize' to begin. +VisualizationPanel.zoomActualButton.toolTipText=reset zoom +VisualizationPanel.zoomActualButton.text= +VisualizationPanel.zoomInButton.toolTipText=Zoom in +VisualizationPanel.zoomInButton.text= +VisualizationPanel.zoomOutButton.toolTipText=Zoom out diff --git a/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java b/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java new file mode 100644 index 0000000000..e0f945bb69 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java @@ -0,0 +1,86 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017-18 Basis Technology Corp. + * Contact: carrier sleuthkit 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 accountDeviceInstances; + private final boolean replace; + + public boolean isReplace() { + return replace; + } + + ImmutableSet getAccountDeviceInstances() { + return accountDeviceInstances; + } + + PinAccountsEvent(Collection accountDeviceInstances, boolean replace) { + this.accountDeviceInstances = ImmutableSet.copyOf(accountDeviceInstances); + this.replace = replace; + } + } + + static final class UnpinAccountsEvent { + + private final ImmutableSet accountDeviceInstances; + + public ImmutableSet getAccountDeviceInstances() { + return accountDeviceInstances; + } + + public UnpinAccountsEvent(Set accountDeviceInstances) { + this.accountDeviceInstances = ImmutableSet.copyOf(accountDeviceInstances); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.form b/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.form index 5e8450d171..055719c488 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.form +++ b/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.form @@ -4,7 +4,7 @@ - + @@ -18,10 +18,10 @@ - - - - + + + + @@ -29,54 +29,59 @@ - - - - + + + + + - + - - + + + + + + + + - + - - - - - - + - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.java b/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.java index ab240e6687..09052d9d9e 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CVTTopComponent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017 Basis Technology Corp. + * Copyright 2017-18 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,10 +18,16 @@ */ package org.sleuthkit.autopsy.communications; +import com.google.common.eventbus.Subscribe; +import java.awt.Dimension; +import java.awt.Font; import java.util.List; import java.util.stream.Collectors; -import org.openide.explorer.ExplorerManager; -import org.openide.explorer.ExplorerUtils; +import javax.swing.GroupLayout; +import javax.swing.ImageIcon; +import javax.swing.JTabbedPane; +import javax.swing.LayoutStyle; +import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.windows.Mode; import org.openide.windows.RetainLocation; @@ -36,33 +42,42 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; @TopComponent.Registration(mode = "cvt", openAtStartup = false) @RetainLocation("cvt") @NbBundle.Messages("CVTTopComponent.name= Communications Visualization") -public final class CVTTopComponent extends TopComponent implements ExplorerManager.Provider { +public final class CVTTopComponent extends TopComponent { private static final long serialVersionUID = 1L; - private final ExplorerManager messagesBrowserExplorerManager; - private final ExplorerManager acctsBrowserExplorerManager; @ThreadConfined(type = ThreadConfined.ThreadType.AWT) public CVTTopComponent() { initComponents(); setName(Bundle.CVTTopComponent_name()); - /* - * Associate an explorer manager with the GlobalActionContext (GAC) for - * use by the messages browser so that selections in the messages - * browser can be exposed to context-sensitive actions. - */ - messagesBrowserExplorerManager = new ExplorerManager(); - associateLookup(ExplorerUtils.createLookup(messagesBrowserExplorerManager, getActionMap())); - splitPane.setRightComponent(new MessageBrowser(messagesBrowserExplorerManager)); /* - * Create a second explorer manager to be discovered by the accounts - * browser and the message browser so that the browsers can both listen - * for explorer manager property events for the outline view of the - * accounts browser. This provides a mechanism for pushing selected - * Nodes from the accounts browser to the messages browser. + * Associate a Lookup with the GlobalActionContext (GAC) so that + * selections in the sub views can be exposed to context-sensitive + * actions. */ - acctsBrowserExplorerManager = new ExplorerManager(); + final ModifiableProxyLookup proxyLookup = new ModifiableProxyLookup(accountsBrowser.getLookup()); + associateLookup(proxyLookup); + // Make sure the Global Actions Context is proxying the selection of the active tab. + browseVisualizeTabPane.addChangeListener(changeEvent -> { + Lookup.Provider selectedComponent = (Lookup.Provider) browseVisualizeTabPane.getSelectedComponent(); + proxyLookup.setNewLookups(selectedComponent.getLookup()); + filtersPane.setDeviceAccountTypeEnabled(browseVisualizeTabPane.getSelectedIndex() != 0); + }); + + + /* + * Connect the filtersPane to the accountsBrowser and visualizaionPanel + * via an Eventbus + */ + CVTEvents.getCVTEventBus().register(this); + CVTEvents.getCVTEventBus().register(vizPanel); + CVTEvents.getCVTEventBus().register(accountsBrowser); + } + + @Subscribe + void pinAccount(CVTEvents.PinAccountsEvent pinEvent) { + browseVisualizeTabPane.setSelectedIndex(1); } /** @@ -73,49 +88,46 @@ public final class CVTTopComponent extends TopComponent implements ExplorerManag // //GEN-BEGIN:initComponents private void initComponents() { - splitPane = new javax.swing.JSplitPane(); - browseVisualizeTabPane = new javax.swing.JTabbedPane(); - accountsBrowser = new org.sleuthkit.autopsy.communications.AccountsBrowser(); - filtersPane = new org.sleuthkit.autopsy.communications.FiltersPanel(); + browseVisualizeTabPane = new JTabbedPane(); + accountsBrowser = new AccountsBrowser(); + vizPanel = new VisualizationPanel(); + filtersPane = new FiltersPanel(); - splitPane.setDividerLocation(400); - splitPane.setResizeWeight(0.7); + browseVisualizeTabPane.setFont(new Font("Tahoma", 0, 18)); // NOI18N + browseVisualizeTabPane.addTab(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.accountsBrowser.TabConstraints.tabTitle_1"), new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/table.png")), accountsBrowser); // NOI18N + browseVisualizeTabPane.addTab(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.vizPanel.TabConstraints.tabTitle_1"), new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/emblem-web.png")), vizPanel); // NOI18N - browseVisualizeTabPane.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N - browseVisualizeTabPane.addTab(org.openide.util.NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.accountsBrowser.TabConstraints.tabTitle"), new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/table.png")), accountsBrowser); // NOI18N + filtersPane.setMinimumSize(new Dimension(256, 495)); - splitPane.setLeftComponent(browseVisualizeTabPane); - - filtersPane.setMinimumSize(new java.awt.Dimension(256, 495)); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + GroupLayout layout = new GroupLayout(this); this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(6, 6, 6) - .addComponent(filtersPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(splitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1277, Short.MAX_VALUE) - .addGap(0, 0, 0)) + .addComponent(filtersPane, GroupLayout.PREFERRED_SIZE, 265, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseVisualizeTabPane, GroupLayout.PREFERRED_SIZE, 786, Short.MAX_VALUE) + .addContainerGap()) ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(6, 6, 6) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(filtersPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(splitPane)) + .addComponent(filtersPane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGap(5, 5, 5)) + .addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(browseVisualizeTabPane) + .addContainerGap()) ); + + browseVisualizeTabPane.getAccessibleContext().setAccessibleName(NbBundle.getMessage(CVTTopComponent.class, "CVTTopComponent.browseVisualizeTabPane.AccessibleContext.accessibleName")); // NOI18N }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private org.sleuthkit.autopsy.communications.AccountsBrowser accountsBrowser; - private javax.swing.JTabbedPane browseVisualizeTabPane; - private org.sleuthkit.autopsy.communications.FiltersPanel filtersPane; - private javax.swing.JSplitPane splitPane; + private AccountsBrowser accountsBrowser; + private JTabbedPane browseVisualizeTabPane; + private FiltersPanel filtersPane; + private VisualizationPanel vizPanel; // End of variables declaration//GEN-END:variables @Override @@ -124,11 +136,6 @@ public final class CVTTopComponent extends TopComponent implements ExplorerManag WindowManager.getDefault().setTopComponentFloating(this, true); } - @Override - public ExplorerManager getExplorerManager() { - return acctsBrowserExplorerManager; - } - @Override public void open() { super.open(); @@ -138,7 +145,7 @@ public final class CVTTopComponent extends TopComponent implements ExplorerManag * * Re-applying the filters means we will lose the selection... */ - filtersPane.updateAndApplyFilters(); + filtersPane.updateAndApplyFilters(true); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java new file mode 100644 index 0000000000..49c3627e08 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java @@ -0,0 +1,333 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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 nodeMap = new HashMap<>(); + + /* Map from relationship source (Content) to mxCell (edge). */ + private final Multimap 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 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 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 "" + edge.getId() + "
" + count + (count == 1 ? " relationship" : " relationships") + ""; + } + } + + 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 { + + 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 relatedAccounts = new HashMap<>(); + for (final AccountDeviceInstanceKey adiKey : pinnedAccountModel.getPinnedAccounts()) { + if (isCancelled()) { + break; + } + final List 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 accounts = relatedAccounts.keySet(); + + Map relationshipCounts = commsManager.getRelationshipCountsPairwise(accounts, currentFilter); + + int total = relationshipCounts.size(); + int k = 0; + progress.switchToDeterminate("", 0, total); + for (Map.Entry 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(); + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/EventHandler.java b/Core/src/org/sleuthkit/autopsy/communications/EventHandler.java new file mode 100644 index 0000000000..f1acedf1cf --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/EventHandler.java @@ -0,0 +1,28 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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 { + + void handle(T event); +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form index e7fa50618f..c19b57ea69 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form @@ -241,7 +241,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java index 5a0de52701..c3d69ed28d 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017 Basis Technology Corp. + * Copyright 2017-18 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,12 +30,11 @@ import java.util.Map.Entry; import java.util.logging.Level; import java.util.stream.Collectors; import javax.swing.JCheckBox; -import org.openide.explorer.ExplorerManager; -import org.openide.nodes.AbstractNode; -import org.openide.nodes.Children; +import javax.swing.JPanel; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import static org.sleuthkit.autopsy.casemodule.Case.Events.CURRENT_CASE; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; @@ -48,7 +47,6 @@ import org.sleuthkit.datamodel.CommunicationsFilter; import org.sleuthkit.datamodel.CommunicationsFilter.AccountTypeFilter; import org.sleuthkit.datamodel.CommunicationsFilter.DateRangeFilter; import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter; -import org.sleuthkit.datamodel.CommunicationsManager; import org.sleuthkit.datamodel.DataSource; import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG; import static org.sleuthkit.datamodel.Relationship.Type.MESSAGE; @@ -56,18 +54,23 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; /** - * Panel that holds the Filter control widgets and translates user filtering - * changes into queries against the CommunicationsManager. + * Panel that holds the Filter control widgets and triggers queries against the + * CommunicationsManager on user filtering changes. */ -final public class FiltersPanel extends javax.swing.JPanel { +final public class FiltersPanel extends JPanel { - private static final Logger logger = Logger.getLogger(FiltersPanel.class.getName()); private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(FiltersPanel.class.getName()); - private ExplorerManager em; - + /** + * Map from Account.Type to the checkbox for that account type's filter. + */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) private final Map accountTypeMap = new HashMap<>(); + + /** + * Map from datasource device id to the checkbox for that datasource. + */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) private final Map devicesMap = new HashMap<>(); @@ -75,6 +78,11 @@ final public class FiltersPanel extends javax.swing.JPanel { * Listens to ingest events to enable refresh button */ private final PropertyChangeListener ingestListener; + + /** + * Flag that indicates the UI is not up-sto-date with respect to the case DB + * and it should be refreshed (by reapplying the filters). + */ private boolean needsRefresh; /** @@ -84,8 +92,15 @@ final public class FiltersPanel extends javax.swing.JPanel { */ private final ItemListener validationListener; - @NbBundle.Messages({"refreshText=Refresh Results", - "applyText=Apply"}) + /** + * Is the device account type filter enabled or not. It should be enabled + * when the Table/Brows mode is active and disabled when the visualization + * is active. Initially false since the browse/table mode is active + * initially. + */ + private boolean deviceAccountTypeEnabled; + + @NbBundle.Messages({"refreshText=Refresh Results", "applyText=Apply"}) public FiltersPanel() { initComponents(); deviceRequiredLabel.setVisible(false); @@ -106,8 +121,7 @@ final public class FiltersPanel extends javax.swing.JPanel { updateTimeZone(); validationListener = itemEvent -> validateFilters(); - updateFilters(); - setAllDevicesSelected(true); + updateFilters(true); UserPreferences.addChangeListener(preferenceChangeEvent -> { if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME)) { updateTimeZone(); @@ -119,10 +133,10 @@ final public class FiltersPanel extends javax.swing.JPanel { if (eventType.equals(DATA_ADDED.toString())) { // Indicate that a refresh may be needed, unless the data added is Keyword or Hashset hits ModuleDataEvent eventData = (ModuleDataEvent) pce.getOldValue(); - if (null != eventData && - eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() && - eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { - updateFilters(); + if (null != eventData + && eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + && eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { + updateFilters(false); needsRefresh = true; validateFilters(); } @@ -154,32 +168,29 @@ final public class FiltersPanel extends javax.swing.JPanel { /** * Update the filter widgets, and apply them. */ - void updateAndApplyFilters() { - updateFilters(); - if (em != null) { - applyFilters(); - } + void updateAndApplyFilters(boolean initialState) { + updateFilters(initialState); + applyFilters(); } private void updateTimeZone() { dateRangeLabel.setText("Date Range ( " + Utils.getUserPreferredZoneId().toString() + "):"); } - private void updateFilters() { + /** + * Updates the filter widgets to reflect he data sources/types in the case. + */ + private void updateFilters(boolean initialState) { updateAccountTypeFilter(); - updateDeviceFilter(); + updateDeviceFilter(initialState); } @Override public void addNotify() { super.addNotify(); - /* - * Since we get the exploreremanager from the parent JComponenet, wait - * till this FiltersPanel is actaully added to a parent. - */ - em = ExplorerManager.find(this); IngestManager.getInstance().addIngestModuleEventListener(ingestListener); Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> { + //clear the device filter widget when the case changes. devicesMap.clear(); devicesPane.removeAll(); }); @@ -198,51 +209,50 @@ final public class FiltersPanel extends javax.swing.JPanel { //TODO: something like this commented code could be used to show only //the account types that are found: - //final CommunicationsManager communicationsManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager(); + //final CommunicationsManager communicationsManager = Case.getOpenCase().getSleuthkitCase().getCommunicationsManager(); //List accountTypesInUse = communicationsManager.getAccountTypesInUse(); //accountTypesInUSe.forEach(...) Account.Type.PREDEFINED_ACCOUNT_TYPES.forEach(type -> { if (type.equals(Account.Type.CREDIT_CARD)) { //don't show a check box for credit cards - } else if (type.equals(Account.Type.DEVICE)) { - //don't show a check box fro device } else { accountTypeMap.computeIfAbsent(type, t -> { final JCheckBox jCheckBox = new JCheckBox( "
" + type.getDisplayName() + "
", true ); jCheckBox.addItemListener(validationListener); accountTypePane.add(jCheckBox); + if (t.equals(Account.Type.DEVICE)) { + //Deveice type filter is enabled based on whether we are in table or graph view. + jCheckBox.setEnabled(deviceAccountTypeEnabled); + } return jCheckBox; }); } - } - ); + }); } /** * Populate the devices filter widgets */ - private void updateDeviceFilter() { + private void updateDeviceFilter(boolean initialState) { try { - final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase(); + final SleuthkitCase sleuthkitCase = Case.getOpenCase().getSleuthkitCase(); for (DataSource dataSource : sleuthkitCase.getDataSources()) { String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName(); //store the device id in the map, but display a datasource name in the UI. devicesMap.computeIfAbsent(dataSource.getDeviceId(), ds -> { - final JCheckBox jCheckBox = new JCheckBox(dsName, false); + final JCheckBox jCheckBox = new JCheckBox(dsName, initialState); jCheckBox.addItemListener(validationListener); devicesPane.add(jCheckBox); return jCheckBox; }); - }; - - } catch (IllegalStateException ex) { + } + } catch (NoCurrentCaseException ex) { logger.log(Level.WARNING, "Communications Visualization Tool opened with no open case.", ex); } catch (TskCoreException tskCoreException) { logger.log(Level.SEVERE, "There was a error loading the datasources for the case.", tskCoreException); @@ -332,7 +342,7 @@ final public class FiltersPanel extends javax.swing.JPanel { } }); - devicesLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/image.png"))); // NOI18N + devicesLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/image.png"))); // NOI18N devicesLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.devicesLabel.text")); // NOI18N checkAllDevicesButton.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.checkAllDevicesButton.text")); // NOI18N @@ -488,26 +498,22 @@ final public class FiltersPanel extends javax.swing.JPanel { }// //GEN-END:initComponents /** - * Query for accounts using the selected filters, and send the results to - * the AccountsBrowser via the ExplorerManager. + * Post an event with the new filters. */ private void applyFilters() { + CVTEvents.getCVTEventBus().post(new CVTEvents.FilterChangeEvent(getFilter())); + needsRefresh = false; + validateFilters(); + } + + private CommunicationsFilter getFilter() { CommunicationsFilter commsFilter = new CommunicationsFilter(); commsFilter.addAndFilter(getDeviceFilter()); commsFilter.addAndFilter(getAccountTypeFilter()); commsFilter.addAndFilter(getDateRangeFilter()); commsFilter.addAndFilter(new CommunicationsFilter.RelationshipTypeFilter( ImmutableSet.of(CALL_LOG, MESSAGE))); - - try { - final CommunicationsManager commsManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager(); - em.setRootContext(new AbstractNode(Children.create(new AccountsRootChildren(commsManager, commsFilter), true))); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "There was an error getting the CommunicationsManager for the current case.", ex); - } - - needsRefresh = false; - validateFilters(); + return commsFilter; } /** @@ -538,6 +544,11 @@ final public class FiltersPanel extends javax.swing.JPanel { return accountTypeFilter; } + /** + * Get an DateRangeFilter that matches the state of the UI widgets + * + * @return an DateRangeFilter + */ private DateRangeFilter getDateRangeFilter() { ZoneId zone = Utils.getUserPreferredZoneId(); long start = startDatePicker.isEnabled() ? startDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0; @@ -545,6 +556,21 @@ final public class FiltersPanel extends javax.swing.JPanel { return new DateRangeFilter(start, end); } + /** + * Enable or disable the device account type filter. The filter should be + * disabled for the browse/table mode and enabled for the visualization. + * + * @param enable True to enable the device account type filter, False to + * disable it. + */ + void setDeviceAccountTypeEnabled(boolean enable) { + deviceAccountTypeEnabled = enable; + JCheckBox deviceCheckbox = accountTypeMap.get(Account.Type.DEVICE); + if (deviceCheckbox != null) { + deviceCheckbox.setEnabled(deviceAccountTypeEnabled); + } + } + /** * Set the selection state of all the account type check boxes * @@ -576,6 +602,7 @@ final public class FiltersPanel extends javax.swing.JPanel { private void setAllSelected(Map map, boolean selected) { map.values().forEach(box -> box.setSelected(selected)); } + private void unCheckAllAccountTypesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_unCheckAllAccountTypesButtonActionPerformed setAllAccountTypesSelected(false); }//GEN-LAST:event_unCheckAllAccountTypesButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java new file mode 100644 index 0000000000..f26e9515b3 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/LockedVertexModel.java @@ -0,0 +1,98 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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 handler) { + eventBus.register(handler); + } + + void unregisterhandler(EventHandler 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 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; + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java index e7628e71f9..94d96c4456 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessageBrowser.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017 Basis Technology Corp. + * Copyright 2017-18 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,96 +18,106 @@ */ package org.sleuthkit.autopsy.communications; -import java.util.Collections; +import java.awt.Component; +import java.awt.KeyboardFocusManager; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.HashSet; import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import javax.swing.JPanel; +import static javax.swing.SwingUtilities.isDescendingFrom; import org.openide.explorer.ExplorerManager; +import static org.openide.explorer.ExplorerUtils.createLookup; import org.openide.nodes.Node; -import org.sleuthkit.autopsy.communications.AccountsRootChildren.AccountDeviceInstanceNode; +import org.openide.util.Lookup; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.DataResultPanel; import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; import org.sleuthkit.datamodel.AccountDeviceInstance; -import org.sleuthkit.datamodel.CommunicationsFilter; -import org.sleuthkit.datamodel.CommunicationsManager; /** - * The right hand side of the CVT. Has a DataResultPanel to show messages and - * other account details, and a ContentViewer to show individual + * The right hand side of the CVT. Has a DataResultPanel to show a listing of + * messages and other account details, and a ContentViewer to show individual + * messages. */ -final class MessageBrowser extends javax.swing.JPanel implements ExplorerManager.Provider { +public final class MessageBrowser extends JPanel implements ExplorerManager.Provider, Lookup.Provider { private static final long serialVersionUID = 1L; + private final ExplorerManager tableEM; private final ExplorerManager gacExplorerManager; private final DataResultPanel messagesResultPanel; - private DataResultViewerTable dataResultViewerTable; + /* lookup that will be exposed through the (Global Actions Context) */ + private final ModifiableProxyLookup proxyLookup = new ModifiableProxyLookup(); + /* Listener that keeps the proxyLookup in sync with the focused area of the + * UI. */ + private final FocusPropertyListener focusPropertyListener = new FocusPropertyListener(); /** * Constructs the right hand side of the Communications Visualization Tool * (CVT). * + * @param tableEM An explorer manager to listen to as the driver + * of the Message Table. * @param gacExplorerManager An explorer manager associated with the * GlobalActionsContext (GAC) so that selections * in the messages browser can be exposed to * context-sensitive actions. */ - MessageBrowser(ExplorerManager gacExplorerManager) { + @NbBundle.Messages({"MessageBrowser.DataResultViewerTable.title=Messages"}) + MessageBrowser(final ExplorerManager tableEM, final ExplorerManager gacExplorerManager) { + this.tableEM = tableEM; this.gacExplorerManager = gacExplorerManager; initComponents(); //create an uninitialized DataResultPanel so we can control the ResultViewers that get added. messagesResultPanel = DataResultPanel.createInstanceUninitialized("Account", "", Node.EMPTY, 0, messageDataContent); splitPane.setTopComponent(messagesResultPanel); splitPane.setBottomComponent(messageDataContent); - } + messagesResultPanel.addResultViewer(new DataResultViewerTable(gacExplorerManager, + Bundle.MessageBrowser_DataResultViewerTable_title())); + messagesResultPanel.open(); - @Override - public void addNotify() { - super.addNotify(); - ExplorerManager parentExplorerManager = ExplorerManager.find(this); - parentExplorerManager.addPropertyChangeListener(pce -> { - if (pce.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) { - final Node[] selectedNodes = parentExplorerManager.getSelectedNodes(); + //add listener that maintains correct selection in the Global Actions Context + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .addPropertyChangeListener("focusOwner", focusPropertyListener); - messagesResultPanel.setNumMatches(0); - messagesResultPanel.setNode(null); - - if (selectedNodes.length == 0) { - //reset panel when there is no selection + this.tableEM.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent pce) { + if (pce.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) { + final Node[] selectedNodes = MessageBrowser.this.tableEM.getSelectedNodes(); + messagesResultPanel.setNumMatches(0); + messagesResultPanel.setNode(null); messagesResultPanel.setPath(""); - } else { - AccountDeviceInstanceNode adiNode = (AccountDeviceInstanceNode) selectedNodes[0]; - CommunicationsFilter filter = adiNode.getFilter(); - CommunicationsManager commsManager = adiNode.getCommsManager(); - final Set accountDeviceInstances; + if (selectedNodes.length > 0) { + Node rootNode; + final Node selectedNode = selectedNodes[0]; - if (selectedNodes.length == 1) { - final AccountDeviceInstance accountDeviceInstance = adiNode.getAccountDeviceInstance(); - accountDeviceInstances = Collections.singleton(accountDeviceInstance); - messagesResultPanel.setPath(accountDeviceInstance.getAccount().getTypeSpecificID()); - } else { - accountDeviceInstances = Stream.of(selectedNodes) - .map(node -> (AccountDeviceInstanceNode) node) - .map(AccountDeviceInstanceNode::getAccountDeviceInstance) - .collect(Collectors.toSet()); - messagesResultPanel.setPath(selectedNodes.length + " accounts"); + if (selectedNode instanceof AccountDeviceInstanceNode) { + rootNode = makeRootNodeFromAccountDeviceInstanceNodes(selectedNodes); + } else { + rootNode = selectedNode; + } + messagesResultPanel.setPath(rootNode.getDisplayName()); + messagesResultPanel.setNode(new TableFilterNode(new DataResultFilterNode(rootNode, gacExplorerManager), true)); } - AccountDetailsNode accountDetailsNode - = new AccountDetailsNode(accountDeviceInstances, filter, commsManager); - TableFilterNode wrappedNode - = new TableFilterNode(new DataResultFilterNode(accountDetailsNode, parentExplorerManager), true); - messagesResultPanel.setNode(wrappedNode); } } - }); - //add the required result viewers and THEN open the panel - if (null == dataResultViewerTable) { - dataResultViewerTable = new DataResultViewerTable(gacExplorerManager, "Messages"); - messagesResultPanel.addResultViewer(dataResultViewerTable); + private Node makeRootNodeFromAccountDeviceInstanceNodes(final Node[] selectedNodes) { + //Use lookup here? + final AccountDeviceInstanceNode adiNode = (AccountDeviceInstanceNode) selectedNodes[0]; + + final Set 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 @@ -115,6 +125,18 @@ final class MessageBrowser extends javax.swing.JPanel implements ExplorerManager return gacExplorerManager; } + @Override + public Lookup getLookup() { + return proxyLookup; + } + + @Override + public void removeNotify() { + super.removeNotify(); + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .removePropertyChangeListener("focusOwner", focusPropertyListener); + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -156,4 +178,38 @@ final class MessageBrowser extends javax.swing.JPanel implements ExplorerManager private javax.swing.JSplitPane splitPane; // End of variables declaration//GEN-END:variables + /** + * Since the embedded MessageContentViewer (attachments panel) is not in its + * own TopComponenet, its selection does not get proxied into the Global + * Actions Context (GAC), and many of the available actions don't work on + * it. Further, we can't put the selection from both the Messages table and + * the Attachments table in the GAC because they could include have + * AbstractFiles, muddling the selection seen by the actions. Instead, + * depending on where the focus is in the window, we want to put different + * Content in the Global Actions Context to be picked up by, e.g., the + * tagging actions. The best way I could figure to do this was to listen to + * all focus events and swap out what is in the lookup appropriately. An + * alternative to this would be to investigate using the ContextAwareAction + * interface. + */ + private class FocusPropertyListener implements PropertyChangeListener { + + @Override + public void propertyChange(final PropertyChangeEvent focusEvent) { + + if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) { + final Component newFocusOwner = (Component) focusEvent.getNewValue(); + + if (newFocusOwner != null) { + if (isDescendingFrom(newFocusOwner, messageDataContent)) { + //if the focus owner is within the MessageContentViewer ( the attachments table) + proxyLookup.setNewLookups(createLookup(messageDataContent.getExplorerManager(), getActionMap())); + } else if (isDescendingFrom(newFocusOwner, messagesResultPanel)) { + //... or if it is within the Messages table. + proxyLookup.setNewLookups(createLookup(gacExplorerManager, getActionMap())); + } + } + } + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/MessageDataContent.java b/Core/src/org/sleuthkit/autopsy/communications/MessageDataContent.java index 1c4ea0f7b4..ad7229157d 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/MessageDataContent.java +++ b/Core/src/org/sleuthkit/autopsy/communications/MessageDataContent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017 Basis Technology Corp. + * Copyright 2017-18 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.communications; import java.beans.PropertyChangeEvent; +import org.openide.explorer.ExplorerManager; import org.sleuthkit.autopsy.contentviewers.MessageContentViewer; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent; @@ -26,12 +27,18 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent; * Extends MessageContentViewer so that it implements DataContent and can be set * as the only ContentViewer for a DataResultPanel */ -public class MessageDataContent extends MessageContentViewer implements DataContent { +final class MessageDataContent extends MessageContentViewer implements DataContent, ExplorerManager.Provider { private static final long serialVersionUID = 1L; + final private ExplorerManager explorerManager = new ExplorerManager(); @Override - public void propertyChange(PropertyChangeEvent evt) { + public void propertyChange(final PropertyChangeEvent evt) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } + + @Override + public ExplorerManager getExplorerManager() { + return explorerManager; + } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/ModifiableProxyLookup.java b/Core/src/org/sleuthkit/autopsy/communications/ModifiableProxyLookup.java new file mode 100644 index 0000000000..cc8657d638 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/ModifiableProxyLookup.java @@ -0,0 +1,44 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/OpenCommVisualizationToolAction.java b/Core/src/org/sleuthkit/autopsy/communications/OpenCommVisualizationToolAction.java index fdccf56af7..e3dc552bab 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/OpenCommVisualizationToolAction.java +++ b/Core/src/org/sleuthkit/autopsy/communications/OpenCommVisualizationToolAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017 Basis Technology Corp. + * Copyright 2017-18 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,6 +19,8 @@ package org.sleuthkit.autopsy.communications; import java.awt.Component; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import javax.swing.ImageIcon; import javax.swing.JButton; import org.openide.awt.ActionID; @@ -29,9 +31,10 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; -import org.openide.util.actions.Presenter; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.core.RuntimeProperties; /** * Action that opens the CVT. Available through the Tools menu and the main @@ -41,18 +44,27 @@ import org.openide.windows.WindowManager; id = "org.sleuthkit.autopsy.communicationsVisualization.OpenCVTAction") @ActionRegistration(displayName = "#CTL_OpenCVTAction", lazy = false) @ActionReferences(value = { - @ActionReference(path = "Menu/Tools", position = 102)}) + @ActionReference(path = "Menu/Tools", position = 102) + , + @ActionReference(path = "Toolbars/Case", position = 102)}) @Messages("CTL_OpenCVTAction=Communications") -public final class OpenCommVisualizationToolAction extends CallableSystemAction implements Presenter.Toolbar { +public final class OpenCommVisualizationToolAction extends CallableSystemAction { private static final long serialVersionUID = 1L; - + private final PropertyChangeListener pcl; private final JButton toolbarButton = new JButton(getName(), new ImageIcon(getClass().getResource("images/emblem-web24.png"))); //NON-NLS public OpenCommVisualizationToolAction() { toolbarButton.addActionListener(actionEvent -> performAction()); setEnabled(false); //disabled by default. Will be enabled in Case.java when a case is opened. + pcl = (PropertyChangeEvent evt) -> { + if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) { + setEnabled(RuntimeProperties.runningWithGUI() && evt.getNewValue() != null); + } + }; + Case.addPropertyChangeListener(pcl); + } @Override diff --git a/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java b/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java new file mode 100644 index 0000000000..d5f7a7cc03 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java @@ -0,0 +1,84 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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 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 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 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 getPinnedAccounts() { + return ImmutableSet.copyOf(pinnedAccountDevices); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/RelaionshipSetNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/RelaionshipSetNodeFactory.java new file mode 100644 index 0000000000..b147ea9537 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/RelaionshipSetNodeFactory.java @@ -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 { + + private final Collection artifacts; + + public RelaionshipSetNodeFactory(Collection artifacts) { + this.artifacts = artifacts; + } + + @Override + protected boolean createKeys(List list) { + list.addAll(artifacts); + return true; + } + + @Override + protected Node createNodeForKey(BlackboardArtifact key) { + return new RelationshipNode(key); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/RelationshipNode.java b/Core/src/org/sleuthkit/autopsy/communications/RelationshipNode.java index 73fa033240..d83eaa4fa3 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/RelationshipNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/RelationshipNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017 Basis Technology Corp. + * Copyright 2017-18 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -43,11 +43,11 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Node for a relationship, as represented by a BlackboardArtifact. */ -public class RelationshipNode extends BlackboardArtifactNode { +final class RelationshipNode extends BlackboardArtifactNode { private static final Logger logger = Logger.getLogger(RelationshipNode.class.getName()); - - public RelationshipNode(BlackboardArtifact artifact) { + + RelationshipNode(BlackboardArtifact artifact) { super(artifact); final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s"); String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message"); @@ -113,6 +113,9 @@ public class RelationshipNode extends BlackboardArtifactNode { break; } } + + addTagProperty(ss); + return s; } @@ -144,4 +147,14 @@ public class RelationshipNode extends BlackboardArtifactNode { } } + /** + * Circumvent DataResultFilterNode's slightly odd delegation to + * BlackboardArtifactNode.getSourceName(). + * + * @return the displayName of this Node, which is the type. + */ + @Override + public String getSourceName() { + return getDisplayName(); + } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/SelectionNode.java b/Core/src/org/sleuthkit/autopsy/communications/SelectionNode.java new file mode 100644 index 0000000000..40739b49cc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/SelectionNode.java @@ -0,0 +1,133 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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 edgeRelationshipArtifacts, + Set 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 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 { + + static final private Logger logger = Logger.getLogger(RelationshipChildren.class.getName()); + + private final Set edgeRelationshipArtifacts; + + private final Set accountDeviceInstances; + + private final CommunicationsManager commsManager; + private final CommunicationsFilter filter; + + private RelationshipChildren(Set selectedEdgeRelationshipSources, Set selecedAccountDeviceInstances, CommunicationsManager commsManager, CommunicationsFilter filter) { + this.edgeRelationshipArtifacts = selectedEdgeRelationshipSources; + this.accountDeviceInstances = selecedAccountDeviceInstances; + this.commsManager = commsManager; + this.filter = filter; + } + + @Override + protected boolean createKeys(List list) { + try { + final Set 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."); + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/Utils.java b/Core/src/org/sleuthkit/autopsy/communications/Utils.java index 91ee1e9fdf..b155e3b4b4 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/Utils.java +++ b/Core/src/org/sleuthkit/autopsy/communications/Utils.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.communications; import java.time.ZoneId; import java.time.ZoneOffset; import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.datamodel.Account; /** @@ -37,36 +38,12 @@ class Utils { } /** - * The file name of the icon for the given Account Type. Will not include - * the path but will include the extension. + * Get the path of the icon for the given Account Type. * - * @return The file name of the icon for the given Account Type. + * @return The path of the icon for the given Account Type. */ - static final String getIconFileName(Account.Type type) { - if (type.equals(Account.Type.CREDIT_CARD)) { - return "credit-card.png"; - } else if (type.equals(Account.Type.DEVICE)) { - return "image.png"; - } else if (type.equals(Account.Type.EMAIL)) { - return "email.png"; - } else if (type.equals(Account.Type.FACEBOOK)) { - return "facebook.png"; - } else if (type.equals(Account.Type.INSTAGRAM)) { - return "instagram.png"; - } else if (type.equals(Account.Type.MESSAGING_APP)) { - return "messaging.png"; - } else if (type.equals(Account.Type.PHONE)) { - return "phone.png"; - } else if (type.equals(Account.Type.TWITTER)) { - return "twitter.png"; - } else if (type.equals(Account.Type.WEBSITE)) { - return "web-file.png"; - } else if (type.equals(Account.Type.WHATSAPP)) { - return "WhatsApp.png"; - } else { - //there could be a default icon instead... - throw new IllegalArgumentException("Unknown Account.Type: " + type.getTypeName()); - } + static final String getIconFilePath(Account.Type type) { + return Accounts.getIconFilePath(type); } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/Vertex_Label_template.html b/Core/src/org/sleuthkit/autopsy/communications/Vertex_Label_template.html new file mode 100644 index 0000000000..4b6d3db580 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/Vertex_Label_template.html @@ -0,0 +1,3 @@ + +
{{#pinned}}{{/pinned}}{{#locked}}{{/locked}}{{accountName}} {{#device_id}}
data source: {{device_id}}{{/device_id}}
+ \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form new file mode 100644 index 0000000000..d73c5e907c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.form @@ -0,0 +1,305 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java new file mode 100644 index 0000000000..cd56e93393 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -0,0 +1,866 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017-18 Basis Technology Corp. + * Contact: carrier sleuthkit 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") + // //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); + }// //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 morphWorker = new SwingWorker() { + @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 relationshipSources = new HashSet<>(); + HashSet 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 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(); + } + + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/calllog.png b/Core/src/org/sleuthkit/autopsy/communications/images/calllog.png deleted file mode 100644 index 83eb9c448d..0000000000 Binary files a/Core/src/org/sleuthkit/autopsy/communications/images/calllog.png and /dev/null differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/credit-card.png b/Core/src/org/sleuthkit/autopsy/communications/images/credit-card.png deleted file mode 100644 index e8d6624d76..0000000000 Binary files a/Core/src/org/sleuthkit/autopsy/communications/images/credit-card.png and /dev/null differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/icons8-mind-map-16.png b/Core/src/org/sleuthkit/autopsy/communications/images/icons8-mind-map-16.png new file mode 100644 index 0000000000..4d9188c245 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/icons8-mind-map-16.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/icons8-neural-network.png b/Core/src/org/sleuthkit/autopsy/communications/images/icons8-neural-network.png new file mode 100644 index 0000000000..331be05231 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/icons8-neural-network.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/image.png b/Core/src/org/sleuthkit/autopsy/communications/images/image.png deleted file mode 100644 index a0fbfcfb79..0000000000 Binary files a/Core/src/org/sleuthkit/autopsy/communications/images/image.png and /dev/null differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/lock_large_locked.png b/Core/src/org/sleuthkit/autopsy/communications/images/lock_large_locked.png new file mode 100644 index 0000000000..527a774296 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/lock_large_locked.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/lock_large_unlocked.png b/Core/src/org/sleuthkit/autopsy/communications/images/lock_large_unlocked.png new file mode 100644 index 0000000000..9df763fb96 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/lock_large_unlocked.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-left.png b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-left.png new file mode 100644 index 0000000000..f865c5787f Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-left.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual-equal.png b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual-equal.png new file mode 100644 index 0000000000..52972052c5 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual-equal.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png new file mode 100644 index 0000000000..bf0137c5b4 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png new file mode 100644 index 0000000000..e29d971045 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png new file mode 100644 index 0000000000..53bb613f8c Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in.png b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in.png new file mode 100644 index 0000000000..281af0cde1 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out-red.png b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out-red.png new file mode 100644 index 0000000000..04446b048c Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out-red.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out.png b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out.png new file mode 100644 index 0000000000..c11249f528 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom.png b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom.png new file mode 100644 index 0000000000..a705d33d92 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier-zoom.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/magnifier.png b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier.png new file mode 100644 index 0000000000..cf3d97f75e Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/magnifier_zoom_in.png b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier_zoom_in.png new file mode 100644 index 0000000000..af4fe07477 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier_zoom_in.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/magnifier_zoom_out.png b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier_zoom_out.png new file mode 100644 index 0000000000..81f28199ac Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/magnifier_zoom_out.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/marker--arrow.png b/Core/src/org/sleuthkit/autopsy/communications/images/marker--arrow.png new file mode 100644 index 0000000000..e9c33c570f Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/marker--arrow.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/marker--exclamation.png b/Core/src/org/sleuthkit/autopsy/communications/images/marker--exclamation.png new file mode 100644 index 0000000000..b225a567b3 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/marker--exclamation.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/marker--minus.png b/Core/src/org/sleuthkit/autopsy/communications/images/marker--minus.png new file mode 100644 index 0000000000..2f1fda8b33 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/marker--minus.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/marker--pencil.png b/Core/src/org/sleuthkit/autopsy/communications/images/marker--pencil.png new file mode 100644 index 0000000000..c18784e7cf Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/marker--pencil.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/marker--pin.png b/Core/src/org/sleuthkit/autopsy/communications/images/marker--pin.png new file mode 100644 index 0000000000..d0e6a6a6bb Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/marker--pin.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/marker--plus.png b/Core/src/org/sleuthkit/autopsy/communications/images/marker--plus.png new file mode 100644 index 0000000000..cb98edc78a Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/marker--plus.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/marker.png b/Core/src/org/sleuthkit/autopsy/communications/images/marker.png new file mode 100644 index 0000000000..74c3b91434 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/marker.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/web-file.png b/Core/src/org/sleuthkit/autopsy/communications/images/web-file.png deleted file mode 100644 index ac5957ad62..0000000000 Binary files a/Core/src/org/sleuthkit/autopsy/communications/images/web-file.png and /dev/null differ diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/FXVideoPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/FXVideoPanel.java index 64203d674b..ef6acc1fd4 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/FXVideoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/FXVideoPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-15 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -59,6 +59,7 @@ import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.Installer; import org.sleuthkit.autopsy.corecomponents.FrameCapture; import org.sleuthkit.autopsy.corecomponents.VideoFrame; @@ -136,7 +137,13 @@ public class FXVideoPanel extends MediaViewVideoPanel { mediaPane.setInfoLabelText(path); mediaPane.setInfoLabelToolTipText(path); - final File tempFile = VideoUtils.getTempVideoFile(currentFile); + final File tempFile; + try { + tempFile = VideoUtils.getTempVideoFile(currentFile); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return; + } new Thread(mediaPane.new ExtractMedia(currentFile, tempFile)).start(); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java index 395f2aa7e5..1d2a1a2a5b 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java @@ -36,7 +36,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.FileTypeViewer; /** * Generic Application content viewer */ -@ServiceProvider(service = DataContentViewer.class, position = 5) +@ServiceProvider(service = DataContentViewer.class, position = 3) public class FileViewer extends javax.swing.JPanel implements DataContentViewer { private static final int CONFIDENCE_LEVEL = 7; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/GstVideoPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/GstVideoPanel.java index e32c551d65..c686471a41 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/GstVideoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/GstVideoPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-15 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -55,6 +55,7 @@ import org.netbeans.api.progress.ProgressHandle; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponents.FrameCapture; import org.sleuthkit.autopsy.corecomponents.VideoFrame; import org.sleuthkit.autopsy.coreutils.Logger; @@ -181,6 +182,7 @@ public class GstVideoPanel extends MediaViewVideoPanel { } @Override + @NbBundle.Messages ({"GstVideoPanel.noOpenCase.errMsg=No open case available."}) void setupVideo(final AbstractFile file, final Dimension dims) { reset(); infoLabel.setText(""); @@ -194,6 +196,18 @@ public class GstVideoPanel extends MediaViewVideoPanel { return; } + java.io.File ioFile; + try { + ioFile = VideoUtils.getTempVideoFile(file); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + infoLabel.setText(Bundle.GstVideoPanel_noOpenCase_errMsg()); + pauseButton.setEnabled(false); + progressSlider.setEnabled(false); + + return; + } + String path = ""; try { path = file.getUniquePath(); @@ -205,7 +219,6 @@ public class GstVideoPanel extends MediaViewVideoPanel { pauseButton.setEnabled(true); progressSlider.setEnabled(true); - java.io.File ioFile = VideoUtils.getTempVideoFile(file); gstVideoComponent = new VideoComponent(); synchronized (playbinLock) { @@ -537,7 +550,14 @@ public class GstVideoPanel extends MediaViewVideoPanel { return; } } else if (state.equals(State.READY)) { - final File tempVideoFile = VideoUtils.getTempVideoFile(currentFile); + final File tempVideoFile; + try { + tempVideoFile = VideoUtils.getTempVideoFile(currentFile); + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Exception while getting open case."); //NON-NLS + infoLabel.setText(MEDIA_PLAYER_ERROR_STRING); + return; + } new ExtractMedia(currentFile, tempVideoFile).execute(); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java index 228dc09c13..e99cae34f6 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017 Basis Technology Corp. + * Copyright 2017-18 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -70,7 +70,7 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Shows SMS/MMS/EMail messages */ -@ServiceProvider(service = DataContentViewer.class, position = 4) +@ServiceProvider(service = DataContentViewer.class, position = 5) public class MessageContentViewer extends javax.swing.JPanel implements DataContentViewer { private static final long serialVersionUID = 1L; @@ -90,7 +90,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont */ private BlackboardArtifact artifact; private final DataResultPanel drp; - private final ExplorerManager drpExplorerManager; + private ExplorerManager drpExplorerManager; /** * Creates new MessageContentViewer @@ -108,6 +108,12 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont Utilities.configureTextPaneAsRtf(rtfbodyTextPane); resetComponent(); + } + + @Override + public void addNotify() { + super.addNotify(); //To change body of generated methods, choose Tools | Templates. + drp.open(); drpExplorerManager = drp.getExplorerManager(); drpExplorerManager.addPropertyChangeListener(evt -> @@ -706,7 +712,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont private static class AttachmentNode extends FileNode { AttachmentNode(AbstractFile file) { - super(file, true); + super(file, false); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java index df1db76507..060280ed08 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java @@ -35,7 +35,7 @@ import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; * shows the same data that can also be found in the ResultViewer table, just a * different order and allows the full path to be visible in the bottom area. */ -@ServiceProvider(service = DataContentViewer.class, position = 3) +@ServiceProvider(service = DataContentViewer.class, position = 6) public class Metadata extends javax.swing.JPanel implements DataContentViewer { /** diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index 8ad6fccd22..f3d630eaf3 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -35,11 +35,13 @@ import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; +import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.TableCellRenderer; @@ -50,7 +52,9 @@ import org.openide.explorer.ExplorerManager; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.util.NbBundle; +import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskCoreException; import org.xml.sax.SAXException; @@ -186,8 +190,21 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E */ private void exportButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportButtonActionPerformed + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + JOptionPane.showMessageDialog(this, + "Failed to export plist file.", + Bundle.PListViewer_ExportFailed_message(), + JOptionPane.ERROR_MESSAGE); + + LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); + return; + } + final JFileChooser fileChooser = new JFileChooser(); - fileChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory())); + fileChooser.setCurrentDirectory(new File(openCase.getExportDirectory())); fileChooser.setFileFilter(new FileNameExtensionFilter("XML file", "xml")); final int returnVal = fileChooser.showSaveDialog(this); @@ -262,35 +279,50 @@ public class PListViewer extends javax.swing.JPanel implements FileTypeViewer, E * * @return none */ + @NbBundle.Messages({"PListViewer.processPlist.interruptedMessage=Interrupted while parsing/displaying plist file.", + "PListViewer.processPlist.errorMessage=Error while parsing/displaying plist file."}) private void processPlist(final AbstractFile plistFile) { - final byte[] plistFileBuf = new byte[(int) plistFile.getSize()]; - try { - plistFile.read(plistFileBuf, 0, plistFile.getSize()); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error reading bytes of plist file.", ex); - } - - final List plist; - try { - plist = parsePList(plistFileBuf); - new SwingWorker() { - @Override - protected Void doInBackground() { + new SwingWorker, Void>() { + @Override + protected List doInBackground() throws TskCoreException, IOException, PropertyListFormatException, ParseException, ParserConfigurationException, SAXException { + // Read in and parse the file + final byte[] plistFileBuf = new byte[(int) plistFile.getSize()]; + plistFile.read(plistFileBuf, 0, plistFile.getSize()); + final List plist = parsePList(plistFileBuf); + + return plist; + } + + @Override + protected void done() { + super.done(); + List plist; + try { + plist = get(); 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() { - 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); - } + + } + }.execute(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java index 56afb99828..b9e71ccdf8 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java @@ -39,9 +39,13 @@ import java.util.TreeMap; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.JComboBox; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.openide.util.NbBundle; +import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.coreutils.Logger; @@ -50,32 +54,27 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.corecomponentinterfaces.FileTypeViewer; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; /** - * A file content viewer for SQLITE db files. - * + * A file content viewer for SQLite database files. */ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { + private static final long serialVersionUID = 1L; public static final String[] SUPPORTED_MIMETYPES = new String[]{"application/x-sqlite3"}; - private static final Logger LOGGER = Logger.getLogger(FileViewer.class.getName()); - private Connection connection = null; - - private String tmpDBPathName = null; - private File tmpDBFile = null; - - private final Map dbTablesMap = new TreeMap<>(); - private static final int ROWS_PER_PAGE = 100; + private static final Logger logger = Logger.getLogger(FileViewer.class.getName()); + private final SQLiteTableView selectedTableView = new SQLiteTableView(); + private AbstractFile sqliteDbFile; + private File tmpDbFile; + private Connection connection; private int numRows; // num of rows in the selected table private int currPage = 0; // curr page of rows being displayed - - SQLiteTableView selectedTableView = new SQLiteTableView(); private SwingWorker worker; - /** - * Creates new form SQLiteViewer + * Constructs a file content viewer for SQLite database files. */ public SQLiteViewer() { initComponents(); @@ -214,7 +213,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { }// //GEN-END:initComponents private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed - currPage++; if (currPage * ROWS_PER_PAGE > numRows) { nextPageButton.setEnabled(false); @@ -228,7 +226,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { }//GEN-LAST:event_nextPageButtonActionPerformed private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed - currPage--; if (currPage == 1) { prevPageButton.setEnabled(false); @@ -247,7 +244,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { if (null == tableName) { return; } - selectTable(tableName); }//GEN-LAST:event_tablesDropdownListActionPerformed @@ -273,7 +269,8 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { @Override public void setFile(AbstractFile file) { - processSQLiteFile(file); + sqliteDbFile = file; + processSQLiteFile(); } @Override @@ -283,9 +280,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { @Override public void resetComponent() { - - dbTablesMap.clear(); - tablesDropdownList.setEnabled(true); tablesDropdownList.removeAllItems(); numEntriesField.setText(""); @@ -296,146 +290,151 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { connection.close(); connection = null; } catch (SQLException ex) { - LOGGER.log(Level.SEVERE, "Failed to close DB connection to file.", ex); //NON-NLS + logger.log(Level.SEVERE, "Failed to close DB connection to file.", ex); //NON-NLS } } // delete last temp file - if (null != tmpDBFile) { - tmpDBFile.delete(); - tmpDBFile = null; + if (null != tmpDbFile) { + tmpDbFile.delete(); + tmpDbFile = null; } + + sqliteDbFile = null; } /** - * Process the given SQLite DB file - * - * @param sqliteFile - - * - * @return none + * Process the given SQLite DB file. */ - private void processSQLiteFile(AbstractFile sqliteFile) { - - tablesDropdownList.removeAllItems(); - - new SwingWorker() { + @NbBundle.Messages({ + "SQLiteViewer.comboBox.noTableEntry=No tables found", + "SQLiteViewer.errorMessage.interrupted=The processing of the file was interrupted.", + "SQLiteViewer.errorMessage.noCurrentCase=The case has been closed.", + "SQLiteViewer.errorMessage.failedToExtractFile=The file could not be extracted from the data source.", + "SQLiteViewer.errorMessage.failedToQueryDatabase=The database tables in the file could not be read.", + "SQLiteViewer.errorMessage.failedToinitJDBCDriver=The JDBC driver for SQLite could not be loaded.", + "# {0} - exception message", "SQLiteViewer.errorMessage.unexpectedError=An unexpected error occurred:\n{0).",}) + private void processSQLiteFile() { + SwingUtilities.invokeLater(() -> { + tablesDropdownList.removeAllItems(); + }); + new SwingWorker, Void>() { @Override - protected Boolean doInBackground() throws Exception { + protected Map 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 { - // Copy the file to temp folder - tmpDBPathName = Case.getCurrentCase().getTempDirectory() + File.separator + sqliteFile.getName(); - tmpDBFile = new File(tmpDBPathName); - ContentUtils.writeToFile(sqliteFile, tmpDBFile); + // Look for any meta files associated with this DB - WAL, SHM, etc. + findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-wal"); + findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-shm"); - // look for any meta files associated with this DB - WAL, SHM - findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-wal"); - findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-shm"); - - // Open copy using JDBC - Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver - 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; + // Load the SQLite JDBC driver, if necessary. + Class.forName("org.sqlite.JDBC"); //NON-NLS + connection = DriverManager.getConnection("jdbc:sqlite:" + tmpDBPathName); //NON-NLS + + // Query the file for the table names and schemas. + return getTables(); } @Override protected void done() { super.done(); try { - boolean status = get(); - if ((status == true) && (dbTablesMap.size() > 0)) { + Map dbTablesMap = get(); + if (dbTablesMap.isEmpty()) { + tablesDropdownList.addItem(Bundle.SQLiteViewer_comboBox_noTableEntry()); + tablesDropdownList.setEnabled(false); + } else { dbTablesMap.keySet().forEach((tableName) -> { tablesDropdownList.addItem(tableName); }); - } else { - // Populate error message - tablesDropdownList.addItem("No tables found"); - tablesDropdownList.setEnabled(false); } - } catch (InterruptedException | ExecutionException ex) { - LOGGER.log(Level.SEVERE, "Unexpected exception while opening DB file", ex); //NON-NLS + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, String.format("Interrupted while opening SQLite database file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS + MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_interrupted()); + } catch (ExecutionException ex) { + String errorMessage; + Throwable cause = ex.getCause(); + if (cause instanceof NoCurrentCaseException) { + logger.log(Level.SEVERE, "Current case has been closed", ex); //NON-NLS + errorMessage = Bundle.SQLiteViewer_errorMessage_noCurrentCase(); + } else if (cause instanceof TskCoreException || cause instanceof IOException) { + logger.log(Level.SEVERE, String.format("Failed to create temp copy of DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS + errorMessage = Bundle.SQLiteViewer_errorMessage_failedToExtractFile(); + } else if (cause instanceof SQLException) { + logger.log(Level.SEVERE, String.format("Failed to get tables from DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS + errorMessage = Bundle.SQLiteViewer_errorMessage_failedToQueryDatabase(); + } else if (cause instanceof ClassNotFoundException) { + logger.log(Level.SEVERE, String.format("Failed to initialize JDBC SQLite '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS + errorMessage = Bundle.SQLiteViewer_errorMessage_failedToinitJDBCDriver(); + } else { + logger.log(Level.SEVERE, String.format("Unexpected exception while processing DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS + errorMessage = Bundle.SQLiteViewer_errorMessage_unexpectedError(cause.getLocalizedMessage()); + } + MessageNotifyUtil.Message.error(errorMessage); } } }.execute(); - } /** - * Searches for a meta file associated with the give SQLite db - * If found, copies the file to the temp folder + * Searches for a meta file associated with the give SQLite db If found, + * copies the file to the temp folder * - * @param sqliteFile - SQLIte db file being processed + * @param sqliteFile - SQLIte db file being processed * @param metaFileName name of meta file to look for - * - * @return true if the meta file is found and copied successfully, false otherwise */ - private boolean findAndCopySQLiteMetaFile(AbstractFile sqliteFile, String metaFileName ) { - - SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase(); + private void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException { + Case openCase = Case.getOpenCase(); + SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase(); Services services = new Services(sleuthkitCase); FileManager fileManager = services.getFileManager(); - - List metaFiles = null; - try { - metaFiles = fileManager.findFiles(sqliteFile.getDataSource(), metaFileName, sqliteFile.getParent().getName() ); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Unexpected exception while searching SQLite meta file = " + metaFileName , ex); //NON-NLS - return false; - } - + List metaFiles = fileManager.findFiles(sqliteFile.getDataSource(), metaFileName, sqliteFile.getParent().getName()); if (metaFiles != null) { - for (AbstractFile metaFile: metaFiles) { - String tmpMetafilePathName = Case.getCurrentCase().getTempDirectory() + File.separator + metaFile.getName(); - + for (AbstractFile metaFile : metaFiles) { + String tmpMetafilePathName = openCase.getTempDirectory() + File.separator + metaFile.getName(); File tmpMetafile = new File(tmpMetafilePathName); - try { - ContentUtils.writeToFile(metaFile, tmpMetafile); - } catch (IOException ex) { - LOGGER.log(Level.SEVERE, "Unexpected exception while copying SQLite meta file = " + metaFileName , ex); //NON-NLS - return false; - } + ContentUtils.writeToFile(metaFile, tmpMetafile); } } - - 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 getTables() throws SQLException { + Map dbTablesMap = new TreeMap<>(); + Statement statement = null; + ResultSet resultSet = null; try { - Statement statement = connection.createStatement(); - - ResultSet resultSet = statement.executeQuery( + statement = connection.createStatement(); + resultSet = statement.executeQuery( "SELECT name, sql FROM sqlite_master " + " WHERE type= 'table' " + " ORDER BY name;"); //NON-NLS - while (resultSet.next()) { String tableName = resultSet.getString("name"); //NON-NLS String tableSQL = resultSet.getString("sql"); //NON-NLS - dbTablesMap.put(tableName, tableSQL); } - } catch (SQLException e) { - LOGGER.log(Level.SEVERE, "Error getting table names from the DB", e); //NON-NLS + } finally { + if (null != resultSet) { + resultSet.close(); + } + 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) { if (worker != null && !worker.isDone()) { worker.cancel(false); @@ -446,17 +445,24 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { @Override protected Integer doInBackground() throws Exception { + Statement statement = null; + ResultSet resultSet = null; try { - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery( + statement = connection.createStatement(); + resultSet = statement.executeQuery( "SELECT count (*) as count FROM " + tableName); //NON-NLS return resultSet.getInt("count"); } catch (SQLException ex) { - LOGGER.log(Level.SEVERE, "Failed to get data for table.", ex); //NON-NLS + throw ex; + } finally { + if (null != resultSet) { + resultSet.close(); + } + if (null != statement) { + statement.close(); + } } - //NON-NLS - return 0; } @Override @@ -473,7 +479,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { prevPageButton.setEnabled(false); - if (numRows > 0) { nextPageButton.setEnabled(((numRows > ROWS_PER_PAGE))); readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE); @@ -482,14 +487,26 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { selectedTableView.setupTable(Collections.emptyList()); } - } catch (InterruptedException | ExecutionException ex) { - LOGGER.log(Level.SEVERE, "Unexpected exception while reading table.", ex); //NON-NLS + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, "Interrupted while getting row count from table " + tableName, ex); //NON-NLS + JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), + ex.getMessage(), + Bundle.SQLiteViewer_selectTable_errorText(tableName), + JOptionPane.ERROR_MESSAGE); + } catch (ExecutionException ex) { + logger.log(Level.SEVERE, "Unexpected exception while getting row count from table " + tableName, ex); //NON-NLS + JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), + ex.getCause().getMessage(), + Bundle.SQLiteViewer_selectTable_errorText(tableName), + JOptionPane.ERROR_MESSAGE); } } }; worker.execute(); } + @NbBundle.Messages({"# {0} - tableName", + "SQLiteViewer.readTable.errorText=Error getting rows for table: {0}"}) private void readTable(String tableName, int startRow, int numRowsToRead) { if (worker != null && !worker.isDone()) { @@ -500,9 +517,12 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { worker = new SwingWorker>, Void>() { @Override protected ArrayList> doInBackground() throws Exception { + + Statement statement = null; + ResultSet resultSet = null; try { - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery( + statement = connection.createStatement(); + resultSet = statement.executeQuery( "SELECT * FROM " + tableName + " LIMIT " + Integer.toString(numRowsToRead) + " OFFSET " + Integer.toString(startRow - 1) @@ -510,10 +530,15 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { return resultSetToArrayList(resultSet); } catch (SQLException ex) { - LOGGER.log(Level.SEVERE, "Failed to get data for table " + tableName, ex); //NON-NLS + throw ex; + } finally { + if (null != resultSet) { + resultSet.close(); + } + if (null != statement) { + statement.close(); + } } - //NON-NLS - return null; } @Override @@ -528,11 +553,21 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { ArrayList> rows = get(); if (Objects.nonNull(rows)) { selectedTableView.setupTable(rows); - }else{ + } else { selectedTableView.setupTable(Collections.emptyList()); } - } catch (InterruptedException | ExecutionException ex) { - LOGGER.log(Level.SEVERE, "Unexpected exception while reading table " + tableName, ex); //NON-NLS + } catch (InterruptedException ex) { + logger.log(Level.SEVERE, "Interrupted while reading table " + tableName, ex); //NON-NLS + JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), + ex.getMessage(), + Bundle.SQLiteViewer_readTable_errorText(tableName), + JOptionPane.ERROR_MESSAGE); + } catch (ExecutionException ex) { + logger.log(Level.SEVERE, "Unexpected exception while reading table " + tableName, ex); //NON-NLS + JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), + ex.getCause().getMessage(), + Bundle.SQLiteViewer_readTable_errorText(tableName), + JOptionPane.ERROR_MESSAGE); } } }; diff --git a/Core/src/org/sleuthkit/autopsy/core/ServicesMonitor.java b/Core/src/org/sleuthkit/autopsy/core/ServicesMonitor.java index 142731a9ab..861c17ac9a 100644 --- a/Core/src/org/sleuthkit/autopsy/core/ServicesMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/core/ServicesMonitor.java @@ -54,7 +54,7 @@ public class ServicesMonitor { private static final String PERIODIC_TASK_THREAD_NAME = "services-monitor-periodic-task-%d"; //NON-NLS private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 1; - private static final long CRASH_DETECTION_INTERVAL_MINUTES = 2; + private static final long CRASH_DETECTION_INTERVAL_MINUTES = 15; private static final Set servicesList = Stream.of(ServicesMonitor.Service.values()) .map(Service::toString) @@ -143,7 +143,7 @@ public class ServicesMonitor { * services. */ periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build()); - periodicTasksExecutor.scheduleAtFixedRate(new CrashDetectionTask(), CRASH_DETECTION_INTERVAL_MINUTES, CRASH_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES); + periodicTasksExecutor.scheduleWithFixedDelay(new CrashDetectionTask(), CRASH_DETECTION_INTERVAL_MINUTES, CRASH_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES); } /** diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index fa78fe5485..465529fa9f 100644 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -198,10 +198,10 @@ - + - + @@ -213,7 +213,7 @@ --> - + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form index 0ee7b6314e..a9ead822e7 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form @@ -9,6 +9,11 @@ + + + + + @@ -24,12 +29,15 @@ - + - + + + + @@ -39,6 +47,9 @@ + + +
@@ -46,7 +57,7 @@ - + @@ -56,7 +67,7 @@ - + @@ -87,11 +98,14 @@ - + + + + @@ -222,7 +236,7 @@ - + @@ -435,7 +449,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java index 51a374260a..de9a8b8e69 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java @@ -50,16 +50,9 @@ import org.sleuthkit.autopsy.report.ReportBranding; /** * Options panel that allow users to set application preferences. */ -@Messages({"AutopsyOptionsPanel.agencyLogoPreview.text=
No logo
selected
", - "AutopsyOptionsPanel.logoPanel.border.title=Logo", - "AutopsyOptionsPanel.viewPanel.border.title=View", +@Messages({ "AutopsyOptionsPanel.invalidImageFile.msg=The selected file was not able to be used as an agency logo.", "AutopsyOptionsPanel.invalidImageFile.title=Invalid Image File", - "AutopsyOptionsPanel.restartNecessaryWarning.text=A restart is necessary for any changes to max memory to take effect.", - "AutopsyOptionsPanel.totalMemoryLabel.text=Total System Memory:", - "AutopsyOptionsPanel.maxMemoryLabel.text=Maximum JVM Memory:", - "AutopsyOptionsPanel.maxMemoryUnitsLabel.text=GB", - "AutopsyOptionsPanel.runtimePanel.border.title=Runtime", "AutopsyOptionsPanel.memFieldValidationLabel.not64BitInstall.text=JVM memory settings only enabled for 64 bit version", "AutopsyOptionsPanel.memFieldValidationLabel.noValueEntered.text=No value entered", "AutopsyOptionsPanel.memFieldValidationLabel.invalidCharacters.text=Invalid characters, value must be a positive integer", @@ -68,13 +61,9 @@ import org.sleuthkit.autopsy.report.ReportBranding; "# {0} - systemMemory", "AutopsyOptionsPanel.memFieldValidationLabel.overMaxMemory.text=Value must be less than the total system memory of {0}GB", "AutopsyOptionsPanel.memFieldValidationLabel.developerMode.text=Memory settings are not available while running in developer mode", - "AutopsyOptionsPanel.defaultLogoRB.text=Use default", - "AutopsyOptionsPanel.specifyLogoRB.text=Specify a logo", - "AutopsyOptionsPanel.browseLogosButton.text=Browse", "AutopsyOptionsPanel.agencyLogoPathFieldValidationLabel.invalidPath.text=Path is not valid.", "AutopsyOptionsPanel.agencyLogoPathFieldValidationLabel.invalidImageSpecified.text=Invalid image file specified.", "AutopsyOptionsPanel.agencyLogoPathFieldValidationLabel.pathNotSet.text=Agency logo path must be set.", - "AutopsyOptionsPanel.maxLogFileCount.text=Maximum Log Files:", "AutopsyOptionsPanel.logNumAlert.invalidInput.text=A positive integer is required here." }) @@ -341,7 +330,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { private void updateAgencyLogo(String path) throws IOException { agencyLogoPathField.setText(path); ImageIcon agencyLogoIcon = new ImageIcon(); - agencyLogoPreview.setText(Bundle.AutopsyOptionsPanel_agencyLogoPreview_text()); + agencyLogoPreview.setText(NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoPreview.text")); if (!agencyLogoPathField.getText().isEmpty()) { File file = new File(agencyLogoPathField.getText()); if (file.exists()) { @@ -572,11 +561,15 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { logFileCount = new javax.swing.JTextField(); logNumAlert = new javax.swing.JTextField(); - jScrollPane1.setBorder(null); + setPreferredSize(new java.awt.Dimension(1022, 488)); - jPanel1.setPreferredSize(new java.awt.Dimension(671, 488)); + jScrollPane1.setBorder(null); + jScrollPane1.setPreferredSize(new java.awt.Dimension(1022, 407)); + + jPanel1.setPreferredSize(new java.awt.Dimension(1022, 407)); logoPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.logoPanel.border.title"))); // NOI18N + logoPanel.setPreferredSize(new java.awt.Dimension(533, 87)); agencyLogoPathField.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoPathField.text")); // NOI18N @@ -894,7 +887,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(logoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(logoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1010, Short.MAX_VALUE) .addGroup(jPanel1Layout.createSequentialGroup() .addComponent(viewPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) @@ -919,11 +912,13 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 1010, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createSequentialGroup() + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 479, Short.MAX_VALUE) + .addGap(0, 0, Short.MAX_VALUE)) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 3976f755f0..535c88ce61 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -169,3 +169,15 @@ CriterionChooser.removeButton.text=Remove CriterionChooser.descendingRadio.text=\u25bc Descending AutopsyOptionsPanel.agencyLogoPathFieldValidationLabel.text= AutopsyOptionsPanel.logNumAlert.text= +AutopsyOptionsPanel.totalMemoryLabel.text=Total System Memory: +AutopsyOptionsPanel.maxMemoryLabel.text=Maximum JVM Memory: +AutopsyOptionsPanel.maxLogFileCount.text=Maximum Log Files: +AutopsyOptionsPanel.maxMemoryUnitsLabel.text=GB +AutopsyOptionsPanel.restartNecessaryWarning.text=A restart is necessary for any changes to max memory to take effect. +AutopsyOptionsPanel.browseLogosButton.text=Browse +AutopsyOptionsPanel.defaultLogoRB.text=Use default +AutopsyOptionsPanel.specifyLogoRB.text=Specify a logo +AutopsyOptionsPanel.agencyLogoPreview.text=
No logo
selected
+AutopsyOptionsPanel.logoPanel.border.title=Logo +AutopsyOptionsPanel.runtimePanel.border.title=Runtime +AutopsyOptionsPanel.viewPanel.border.title=View diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentTopComponent.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentTopComponent.java index 6f7c87ad0b..b5dd60c395 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentTopComponent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,11 +23,14 @@ import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import javax.swing.JTabbedPane; +import org.openide.explorer.ExplorerManager; +import org.openide.explorer.ExplorerUtils; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent; import org.sleuthkit.autopsy.coreutils.Logger; @@ -40,7 +43,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; //@TopComponent.Description(preferredID = "DataContentTopComponent") //@TopComponent.Registration(mode = "output", openAtStartup = true) //@TopComponent.OpenActionRegistration(displayName = "#CTL_DataContentAction", preferredID = "DataContentTopComponent") -public final class DataContentTopComponent extends TopComponent implements DataContent { +public final class DataContentTopComponent extends TopComponent implements DataContent, ExplorerManager.Provider { private static final Logger logger = Logger.getLogger(DataContentTopComponent.class.getName()); @@ -51,6 +54,7 @@ public final class DataContentTopComponent extends TopComponent implements DataC private final boolean isDefault; // the content panel holding tabs with content viewers private final DataContentPanel dataContentPanel; + private final ExplorerManager explorerManager = new ExplorerManager(); // contains a list of the undocked TCs private static final ArrayList newWindowList = new ArrayList<>(); @@ -68,6 +72,8 @@ public final class DataContentTopComponent extends TopComponent implements DataC dataContentPanel = new DataContentPanel(isDefault); add(dataContentPanel); + associateLookup(ExplorerUtils.createLookup(explorerManager, getActionMap())); + putClientProperty(TopComponent.PROP_CLOSING_DISABLED, isDefault); // prevent option to close compoment in GUI logger.log(Level.INFO, "Created DataContentTopComponent instance: {0}", this); //NON-NLS } @@ -128,6 +134,11 @@ public final class DataContentTopComponent extends TopComponent implements DataC return getDefault(); } + @Override + public ExplorerManager getExplorerManager() { + return explorerManager; + } + @Override public int getPersistenceType() { return TopComponent.PERSISTENCE_NEVER; @@ -168,7 +179,13 @@ public final class DataContentTopComponent extends TopComponent implements DataC * the main window, only it to be closed when there's no case opened or * no data sources in the open case. */ - return (!this.isDefault) || !Case.isCaseOpen() || Case.getCurrentCase().hasData() == false; + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + return true; + } + return (!this.isDefault) || openCase.hasData() == false; } @Override diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java index f57827e4f0..d0c5b860a3 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java @@ -62,7 +62,7 @@ import org.netbeans.swing.etable.ETable; * Content represented by a Node. Each BlackboardArtifact is rendered displayed * in a JTable representation of its BlackboardAttributes. */ -@ServiceProvider(service = DataContentViewer.class, position = 3) +@ServiceProvider(service = DataContentViewer.class, position = 7) public class DataContentViewerArtifact extends javax.swing.JPanel implements DataContentViewer { @NbBundle.Messages({ diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java index e89d677ad8..9751bb024a 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,6 +37,7 @@ import org.openide.nodes.NodeReorderEvent; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResult; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; @@ -486,7 +487,13 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C * If this is the "main" panel, only allow it to be closed when no case * is open or no there are no data sources in the current case. */ - return (!this.isMain) || !Case.isCaseOpen() || Case.getCurrentCase().hasData() == false; + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + return true; + } + return (!this.isMain) || openCase.hasData() == false; } /** @@ -528,8 +535,8 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C @Override public void propertyChange(PropertyChangeEvent evt) { try { - Case.getCurrentCase(); - } catch (IllegalStateException ex) { + Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { return; } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java index eb9f8dad5b..8ec9886f53 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java @@ -33,6 +33,7 @@ import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.actions.AddBookmarkTagAction; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResult; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; import org.sleuthkit.autopsy.coreutils.Logger; @@ -334,7 +335,13 @@ public class DataResultTopComponent extends TopComponent implements DataResult, * window, only allow it to be closed when there's no case opened or no * data sources in the open case. */ - return (!this.isMain) || !Case.isCaseOpen() || Case.getCurrentCase().hasData() == false; + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + return true; + } + return (!this.isMain) || openCase.hasData() == false; } /** diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index 206ebb3dea..2e517db0bb 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-17 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com @@ -62,6 +62,7 @@ import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.opencv.core.Core; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corelibs.ScalrWrapper; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector.FileTypeDetectorInitException; @@ -384,9 +385,9 @@ public class ImageUtils { private static File getCachedThumbnailLocation(long fileID) { return cacheFileMap.computeIfAbsent(fileID, id -> { try { - String cacheDirectory = Case.getCurrentCase().getCacheDirectory(); + String cacheDirectory = Case.getOpenCase().getCacheDirectory(); return Paths.get(cacheDirectory, "thumbnails", fileID + ".png").toFile(); //NON-NLS - } catch (IllegalStateException e) { + } catch (NoCurrentCaseException e) { LOGGER.log(Level.WARNING, "Could not get cached thumbnail location. No case is open."); //NON-NLS return null; } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java index 81670a878c..59d16ac5f3 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015-16 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,6 +34,7 @@ import org.opencv.core.Mat; import org.opencv.highgui.VideoCapture; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corelibs.ScalrWrapper; import static org.sleuthkit.autopsy.coreutils.ImageUtils.isMediaThumbnailSupported; import org.sleuthkit.autopsy.datamodel.ContentUtils; @@ -90,8 +91,8 @@ public class VideoUtils { private VideoUtils() { } - public static File getTempVideoFile(AbstractFile file) { - return Paths.get(Case.getCurrentCase().getTempDirectory(), "videos", file.getId() + "." + file.getNameExtension()).toFile(); //NON-NLS + public static File getTempVideoFile(AbstractFile file) throws NoCurrentCaseException { + return Paths.get(Case.getOpenCase().getTempDirectory(), "videos", file.getId() + "." + file.getNameExtension()).toFile(); //NON-NLS } public static boolean isVideoThumbnailSupported(AbstractFile file) { @@ -101,7 +102,13 @@ public class VideoUtils { @NbBundle.Messages({"# {0} - file name", "VideoUtils.genVideoThumb.progress.text=extracting temporary file {0}"}) static BufferedImage generateVideoThumbnail(AbstractFile file, int iconSize) { - java.io.File tempFile = getTempVideoFile(file); + java.io.File tempFile; + try { + tempFile = getTempVideoFile(file); + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.WARNING, "Exception while getting open case.", ex); //NON-NLS + return null; + } if (tempFile.exists() == false || tempFile.length() < file.getSize()) { ProgressHandle progress = ProgressHandle.createHandle(Bundle.VideoUtils_genVideoThumb_progress_text(file.getName())); progress.start(100); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index df2d3dfdc4..1404ca4950 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,6 +33,7 @@ import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.WeakListeners; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.coreutils.Logger; @@ -263,8 +264,8 @@ public abstract class AbstractAbstractFileNode extends A protected void addTagProperty(Sheet.Set ss) { List tags = new ArrayList<>(); try { - tags.addAll(Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(content)); - } catch (TskCoreException ex) { + tags.addAll(Case.getOpenCase().getServices().getTagsManager().getContentTagsByContent(content)); + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Failed to get tags for content " + content.getName(), ex); } ss.put(new NodeProperty<>("Tags", AbstractAbstractFileNode_tagsProperty_displayName(), diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java index 66355c2661..8750d57f30 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,6 +26,7 @@ import java.util.logging.Level; import org.openide.util.lookup.Lookups; import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.Content; @@ -119,12 +120,12 @@ public abstract class AbstractContentNode extends ContentNode + " AND type = " + TskData.ObjectType.ABSTRACTFILE.getObjectType() + ") AS OBJECT_IDS"; //NON-NLS; - try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(query)) { + try (SleuthkitCase.CaseDbQuery dbQuery = Case.getOpenCase().getSleuthkitCase().executeQuery(query)) { ResultSet resultSet = dbQuery.getResultSet(); if(resultSet.next()){ return (0 < resultSet.getInt("count")); } - } catch (TskCoreException | SQLException ex) { + } catch (TskCoreException | SQLException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Error checking if the node has children, for content: " + c, ex); //NON-NLS } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 6479c21cf9..020c133ef4 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,6 +29,7 @@ import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.MissingResourceException; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -42,6 +43,7 @@ import org.openide.util.NbBundle; import org.openide.util.WeakListeners; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; @@ -79,8 +81,12 @@ public class BlackboardArtifactNode extends AbstractContentNode> customProperties; + private final static String NO_DESCR = NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.noDesc.text"); + + /* * Artifact types which should have the full unique path of the associated * content as a property. @@ -260,7 +266,7 @@ public class BlackboardArtifactNode extends AbstractContentNode map = new LinkedHashMap<>(); fillPropertyMap(map, artifact); @@ -327,7 +332,7 @@ public class BlackboardArtifactNode extends AbstractContentNode(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.name"), NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.displayName"), NO_DESCR, @@ -337,7 +342,7 @@ public class BlackboardArtifactNode extends AbstractContentNode tags = new ArrayList<>(); try { - tags.addAll(Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact)); - tags.addAll(Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(associated)); - } catch (TskCoreException ex) { + tags.addAll(Case.getOpenCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact)); + tags.addAll(Case.getOpenCase().getServices().getTagsManager().getContentTagsByContent(associated)); + } catch (TskCoreException | NoCurrentCaseException ex) { LOGGER.log(Level.SEVERE, "Failed to get tags for artifact " + artifact.getDisplayName(), ex); } - ss.put(new NodeProperty<>("Tags", NbBundle.getMessage(AbstractAbstractFileNode.class, "BlackboardArtifactNode.createSheet.tags.displayName"), + ss.put(new NodeProperty<>("Tags", Bundle.BlackboardArtifactNode_createSheet_tags_displayName(), NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", ")))); - - return s; } private void updateSheet() { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index 7063656562..733c49e8b7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -207,8 +207,6 @@ DeleteReportAction.actionDisplayName.multipleReports=Delete Reports DeleteReportAction.actionPerformed.showConfirmDialog.title=Confirm Deletion DeleteReportAction.actionPerformed.showConfirmDialog.single.msg=Do you want to delete 1 report from the case? DeleteReportAction.actionPerformed.showConfirmDialog.multiple.msg=Do you want to delete {0} reports from the case? -BlackboardArtifactNode.createSheet.tags.name=Tags -BlackboardArtifactNode.createSheet.tags.displayName=Tags FileTypeExtensionFilters.tskImgFilter.text=Images FileTypeExtensionFilters.tskVideoFilter.text=Videos FileTypeExtensionFilters.tskAudioFilter.text=Audio diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index 43ddd069a3..0833b87b43 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,6 +29,7 @@ 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.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; @@ -102,9 +103,9 @@ public class DataSourcesNode extends DisplayableItemNode { private void reloadKeys() { try { - currentKeys = Case.getCurrentCase().getDataSources(); + currentKeys = Case.getOpenCase().getDataSources(); setKeys(currentKeys); - } catch (TskCoreException | IllegalStateException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Error getting data sources: {0}", ex.getMessage()); // NON-NLS setKeys(Collections.emptySet()); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index 9b6f36a56b..816105d080 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,6 +39,7 @@ import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import static org.sleuthkit.autopsy.datamodel.Bundle.*; @@ -206,11 +207,11 @@ public class DeletedContent implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); // new file was added // @@@ COULD CHECK If the new file is deleted before notifying... update(); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ @@ -225,9 +226,9 @@ public class DeletedContent implements AutopsyVisitableItem { * received for a case that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); update(); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 7ffcfc077c..935aec9c62 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012-2017 Basis Technology Corp. + * Copyright 2012-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,6 +39,7 @@ 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.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -240,7 +241,7 @@ public class EmailExtracted implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); /** * Even with the check above, it is still possible that * the case will be closed in a different thread before @@ -251,7 +252,7 @@ public class EmailExtracted implements AutopsyVisitableItem { if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) { emailResults.update(); } - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ @@ -265,9 +266,9 @@ public class EmailExtracted implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); emailResults.update(); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 9a7334f423..3e001b097d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,6 +34,7 @@ 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.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -210,7 +211,7 @@ public class ExtractedContent implements AutopsyVisitableItem { * may be received for a case that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); /** * Due to some unresolved issues with how cases are closed, * it is possible for the event to have a null oldValue if @@ -220,7 +221,7 @@ public class ExtractedContent implements AutopsyVisitableItem { if (null != event && !(this.doNotShow.contains(event.getBlackboardArtifactType()))) { refresh(true); } - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ @@ -233,9 +234,9 @@ public class ExtractedContent implements AutopsyVisitableItem { * may be received for a case that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); refresh(true); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ @@ -401,7 +402,7 @@ public class ExtractedContent implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); /** * Even with the check above, it is still possible that * the case will be closed in a different thread before @@ -412,7 +413,7 @@ public class ExtractedContent implements AutopsyVisitableItem { if (null != event && event.getBlackboardArtifactType().equals(type)) { refresh(true); } - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ @@ -426,9 +427,9 @@ public class ExtractedContent implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); refresh(true); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java index 007c59ad41..0a9321e4d5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2017 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,6 +36,7 @@ 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.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -201,9 +202,9 @@ public class FileSize implements AutopsyVisitableItem { try { // new file was added // @@@ could check the size here and only fire off updates if we know the file meets the min size criteria - Case.getCurrentCase(); + Case.getOpenCase(); update(); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ @@ -218,9 +219,9 @@ public class FileSize implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); update(); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index 2341fff12c..2d8cc564d2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,6 +37,7 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey; @@ -93,10 +94,10 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); typesRoot.updateShowCounts(); update(); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java index 9fe183a8a8..e7af90fab7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -41,6 +41,7 @@ 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.casemodule.NoCurrentCaseException; import static org.sleuthkit.autopsy.core.UserPreferences.hideKnownFilesInViewsTree; import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTree; import org.sleuthkit.autopsy.coreutils.Logger; @@ -163,10 +164,10 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi * already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); typesRoot.updateShowCounts(); populateHashMap(); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index df3d239aef..a1b9cf9963 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -41,6 +41,7 @@ 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.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -208,7 +209,7 @@ public class HashsetHits implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); /** * Due to some unresolved issues with how cases are * closed, it is possible for the event to have a null @@ -218,7 +219,7 @@ public class HashsetHits implements AutopsyVisitableItem { if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { hashsetResults.update(); } - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ @@ -232,9 +233,9 @@ public class HashsetHits implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); hashsetResults.update(); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index 4efe1db364..7c06fb7afb 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,6 +33,7 @@ import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor; import org.sleuthkit.autopsy.directorytree.FileSearchAction; @@ -170,7 +171,7 @@ public class ImageNode extends AbstractContentNode { Bundle.ImageNode_createSheet_timezone_desc(), this.content.getTimeZone())); - try (CaseDbQuery query = Case.getCurrentCase().getSleuthkitCase().executeQuery("SELECT device_id FROM data_source_info WHERE obj_id = " + this.content.getId());) { + try (CaseDbQuery query = Case.getOpenCase().getSleuthkitCase().executeQuery("SELECT device_id FROM data_source_info WHERE obj_id = " + this.content.getId());) { ResultSet deviceIdSet = query.getResultSet(); if (deviceIdSet.next()) { ss.put(new NodeProperty<>(Bundle.ImageNode_createSheet_deviceId_name(), @@ -178,7 +179,7 @@ public class ImageNode extends AbstractContentNode { Bundle.ImageNode_createSheet_deviceId_desc(), deviceIdSet.getString("device_id"))); } - } catch (SQLException | TskCoreException ex) { + } catch (SQLException | TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Failed to get device id for the following image: " + this.content.getId(), ex); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 7a0b6b9ad9..435fa75023 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -41,6 +41,7 @@ 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.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -199,7 +200,7 @@ public class InterestingHits implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); /** * Even with the check above, it is still possible that * the case will be closed in a different thread before @@ -211,7 +212,7 @@ public class InterestingHits implements AutopsyVisitableItem { || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID())) { interestingResults.update(); } - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ @@ -225,9 +226,9 @@ public class InterestingHits implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); interestingResults.update(); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 75873d135e..dbe3dc371b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -43,6 +43,7 @@ import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import static org.sleuthkit.autopsy.datamodel.Bundle.*; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -411,7 +412,7 @@ public class KeywordHits implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); /** * Even with the check above, it is still possible that * the case will be closed in a different thread before @@ -422,7 +423,7 @@ public class KeywordHits implements AutopsyVisitableItem { if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { keywordResults.update(); } - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { // Case is closed, do nothing. } } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) @@ -434,9 +435,9 @@ public class KeywordHits implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); keywordResults.update(); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { // Case is closed, do nothing. } } else if (eventType.equals(Case.Events.CURRENT_CASE.toString()) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java b/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java index a09f518780..9c6d9f1829 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java @@ -40,6 +40,7 @@ import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; @@ -114,9 +115,9 @@ public final class Reports implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); ReportNodeFactory.this.refresh(true); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ @@ -128,8 +129,8 @@ public final class Reports implements AutopsyVisitableItem { @Override protected boolean createKeys(List keys) { try { - keys.addAll(Case.getCurrentCase().getAllReports()); - } catch (TskCoreException ex) { + keys.addAll(Case.getOpenCase().getAllReports()); + } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(Reports.ReportNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get reports", ex); //NON-NLS } return true; @@ -265,8 +266,8 @@ public final class Reports implements AutopsyVisitableItem { NbBundle.getMessage(Reports.class, "DeleteReportAction.actionPerformed.showConfirmDialog.title"), JOptionPane.YES_NO_OPTION)) { try { - Case.getCurrentCase().deleteReports(selectedReportsCollection); - } catch (TskCoreException | IllegalStateException ex) { + Case.getOpenCase().deleteReports(selectedReportsCollection); + } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(DeleteReportAction.class.getName()).log(Level.SEVERE, "Error deleting reports", ex); // NON-NLS MessageNotifyUtil.Message.error(Bundle.DeleteReportAction_showConfirmDialog_errorMsg()); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 64b77ac245..57fd35beba 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,6 +34,7 @@ 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.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -141,10 +142,10 @@ public class Tags implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); refresh(true); tagResults.update(); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ @@ -158,10 +159,10 @@ public class Tags implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); refresh(true); tagResults.update(); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ @@ -195,10 +196,10 @@ public class Tags implements AutopsyVisitableItem { @Override protected boolean createKeys(List keys) { try { - List tagNamesInUse = Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse(); + List tagNamesInUse = Case.getOpenCase().getServices().getTagsManager().getTagNamesInUse(); Collections.sort(tagNamesInUse); keys.addAll(tagNamesInUse); - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(TagNameNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } return true; @@ -242,10 +243,10 @@ public class Tags implements AutopsyVisitableItem { private void updateDisplayName() { long tagsCount = 0; try { - TagsManager tm = Case.getCurrentCase().getServices().getTagsManager(); + TagsManager tm = Case.getOpenCase().getServices().getTagsManager(); tagsCount = tm.getContentTagsCountByTagName(tagName); tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName); - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS } setDisplayName(tagName.getDisplayName() + " \u200E(\u200E" + tagsCount + ")\u200E"); @@ -347,8 +348,8 @@ public class Tags implements AutopsyVisitableItem { private void updateDisplayName() { long tagsCount = 0; try { - tagsCount = Case.getCurrentCase().getServices().getTagsManager().getContentTagsCountByTagName(tagName); - } catch (TskCoreException ex) { + tagsCount = Case.getOpenCase().getServices().getTagsManager().getContentTagsCountByTagName(tagName); + } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(ContentTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get content tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS } super.setDisplayName(CONTENT_DISPLAY_NAME + " (" + tagsCount + ")"); @@ -402,8 +403,8 @@ public class Tags implements AutopsyVisitableItem { protected boolean createKeys(List keys) { // Use the content tags bearing the specified tag name as the keys. try { - keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName)); - } catch (TskCoreException ex) { + keys.addAll(Case.getOpenCase().getServices().getTagsManager().getContentTagsByTagName(tagName)); + } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(ContentTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } return true; @@ -446,8 +447,8 @@ public class Tags implements AutopsyVisitableItem { private void updateDisplayName() { long tagsCount = 0; try { - tagsCount = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName); - } catch (TskCoreException ex) { + tagsCount = Case.getOpenCase().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName); + } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(BlackboardArtifactTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS } super.setDisplayName(ARTIFACT_DISPLAY_NAME + " (" + tagsCount + ")"); @@ -501,8 +502,8 @@ public class Tags implements AutopsyVisitableItem { protected boolean createKeys(List keys) { try { // Use the blackboard artifact tags bearing the specified tag name as the keys. - keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName)); - } catch (TskCoreException ex) { + keys.addAll(Case.getOpenCase().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName)); + } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(BlackboardArtifactTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } return true; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 3d78d3f13d..312e6a8da0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,6 +26,7 @@ import java.util.logging.Level; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -105,7 +106,7 @@ public class VirtualDirectoryNode extends SpecialDirectoryNode { Bundle.VirtualDirectoryNode_createSheet_size_displayName(), Bundle.VirtualDirectoryNode_createSheet_size_desc(), this.content.getSize())); - try (SleuthkitCase.CaseDbQuery query = Case.getCurrentCase().getSleuthkitCase().executeQuery("SELECT time_zone FROM data_source_info WHERE obj_id = " + this.content.getId())) { + try (SleuthkitCase.CaseDbQuery query = Case.getOpenCase().getSleuthkitCase().executeQuery("SELECT time_zone FROM data_source_info WHERE obj_id = " + this.content.getId())) { ResultSet timeZoneSet = query.getResultSet(); if (timeZoneSet.next()) { ss.put(new NodeProperty<>(Bundle.VirtualDirectoryNode_createSheet_timezone_name(), @@ -113,10 +114,10 @@ public class VirtualDirectoryNode extends SpecialDirectoryNode { Bundle.VirtualDirectoryNode_createSheet_timezone_desc(), timeZoneSet.getString("time_zone"))); } - } catch (SQLException | TskCoreException ex) { + } catch (SQLException | TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Failed to get time zone for the following image: " + this.content.getId(), ex); } - try (SleuthkitCase.CaseDbQuery query = Case.getCurrentCase().getSleuthkitCase().executeQuery("SELECT device_id FROM data_source_info WHERE obj_id = " + this.content.getId());) { + try (SleuthkitCase.CaseDbQuery query = Case.getOpenCase().getSleuthkitCase().executeQuery("SELECT device_id FROM data_source_info WHERE obj_id = " + this.content.getId());) { ResultSet deviceIdSet = query.getResultSet(); if (deviceIdSet.next()) { ss.put(new NodeProperty<>(Bundle.VirtualDirectoryNode_createSheet_deviceId_name(), @@ -124,7 +125,7 @@ public class VirtualDirectoryNode extends SpecialDirectoryNode { Bundle.VirtualDirectoryNode_createSheet_deviceId_desc(), deviceIdSet.getString("device_id"))); } - } catch (SQLException | TskCoreException ex) { + } catch (SQLException | TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Failed to get device id for the following image: " + this.content.getId(), ex); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index b3e8a9a1b1..f25541839c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -54,11 +54,11 @@ import org.openide.nodes.Node; import org.openide.nodes.NodeNotFoundException; import org.openide.nodes.NodeOp; import org.openide.nodes.Sheet; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.datamodel.AutopsyItemVisitor; import org.sleuthkit.autopsy.datamodel.AutopsyVisitableItem; @@ -73,7 +73,6 @@ import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; -import org.sleuthkit.datamodel.AccountFileInstance; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -89,6 +88,7 @@ import org.sleuthkit.datamodel.TskData.DbType; final public class Accounts implements AutopsyVisitableItem { private static final Logger LOGGER = Logger.getLogger(Accounts.class.getName()); + private static final String iconBasePath = "/org/sleuthkit/autopsy/images/"; //NON-NLS @NbBundle.Messages("AccountsRootNode.name=Accounts") final public static String NAME = Bundle.AccountsRootNode_name(); @@ -126,7 +126,7 @@ final public class Accounts implements AutopsyVisitableItem { * results from db queries. * * @return A clause that will or will not filter out rejected artifacts - * based on the state of showRejected. + * based on the state of showRejected. */ private String getRejectedArtifactFilterClause() { return showRejected ? " " : " AND blackboard_artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() + " "; //NON-NLS @@ -137,7 +137,7 @@ final public class Accounts implements AutopsyVisitableItem { * or off. * * @return An Action that will toggle whether rejected artifacts are shown - * in the tree rooted by this Accounts instance. + * in the tree rooted by this Accounts instance. */ public Action newToggleShowRejectedAction() { return new ToggleShowRejected(); @@ -225,8 +225,8 @@ final public class Accounts implements AutopsyVisitableItem { private class AccountTypeFactory extends ObservingChildren { /* - * The pcl is in this class because it has the easiest mechanisms to - * add and remove itself during its life cycles. + * The pcl is in this class because it has the easiest mechanisms to add + * and remove itself during its life cycles. */ private final PropertyChangeListener pcl = new PropertyChangeListener() { @Override @@ -240,7 +240,7 @@ final public class Accounts implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); /** * Even with the check above, it is still possible that * the case will be closed in a different thread before @@ -252,7 +252,7 @@ final public class Accounts implements AutopsyVisitableItem { && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { reviewStatusBus.post(eventData); } - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { // Case is closed, do nothing. } } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) @@ -264,9 +264,9 @@ final public class Accounts implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); refresh(true); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { // Case is closed, do nothing. } } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { @@ -310,23 +310,21 @@ final public class Accounts implements AutopsyVisitableItem { } @Override - protected Node[] createNodesForKey(String key) { + protected Node[] createNodesForKey(String acountTypeName) { - String accountType = key; - if (accountType.equals(Account.Type.CREDIT_CARD.getTypeName())) { + if (Account.Type.CREDIT_CARD.getTypeName().equals(acountTypeName)) { return new Node[]{new CreditCardNumberAccountTypeNode()}; } else { - String accountTypeDisplayname; + try { - accountTypeDisplayname = skCase.getCommunicationsManager().getAccountType(accountType).getDisplayName(); + Account.Type accountType = skCase.getCommunicationsManager().getAccountType(acountTypeName); + return new Node[]{new DefaultAccountTypeNode(accountType)}; } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error getting display name for account type. ", ex); - accountTypeDisplayname = accountType; } - return new Node[]{new DefaultAccountTypeNode(key, accountTypeDisplayname)}; + return new Node[]{}; } - } @Override @@ -350,10 +348,10 @@ final public class Accounts implements AutopsyVisitableItem { final private class DefaultAccountFactory extends ObservingChildren { - private final String accountTypeName; + private final Account.Type accountType; - private DefaultAccountFactory(String accountTypeName) { - this.accountTypeName = accountTypeName; + private DefaultAccountFactory(Account.Type accountType) { + this.accountType = accountType; } private final PropertyChangeListener pcl = new PropertyChangeListener() { @@ -368,7 +366,7 @@ final public class Accounts implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); /** * Even with the check above, it is still possible that * the case will be closed in a different thread before @@ -380,7 +378,7 @@ final public class Accounts implements AutopsyVisitableItem { && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { reviewStatusBus.post(eventData); } - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { // Case is closed, do nothing. } } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) @@ -392,10 +390,10 @@ final public class Accounts implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); refresh(true); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { // Case is closed, do nothing. } } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { @@ -424,13 +422,13 @@ final public class Accounts implements AutopsyVisitableItem { @Override protected boolean createKeys(List list) { - String query - = "SELECT blackboard_artifacts.artifact_id " //NON-NLS + String query = + "SELECT blackboard_artifacts.artifact_id " //NON-NLS + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS - + " AND blackboard_attributes.value_text = '" + accountTypeName + "'" //NON-NLS + + " AND blackboard_attributes.value_text = '" + accountType.getTypeName() + "'" //NON-NLS + getRejectedArtifactFilterClause(); //NON-NLS try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); ResultSet rs = results.getResultSet();) { @@ -473,10 +471,10 @@ final public class Accounts implements AutopsyVisitableItem { */ final public class DefaultAccountTypeNode extends DisplayableItemNode { - private DefaultAccountTypeNode(String accountTypeName, String accountTypeDisplayName) { - super(Children.create(new DefaultAccountFactory(accountTypeName), true), Lookups.singleton(accountTypeDisplayName)); - setName(accountTypeDisplayName); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS + private DefaultAccountTypeNode(Account.Type accountType) { + super(Children.create(new DefaultAccountFactory(accountType), true), Lookups.singleton(accountType)); + setName(accountType.getDisplayName()); + this.setIconBaseWithExtension(getIconFilePath(accountType)); //NON-NLS } @Override @@ -517,7 +515,7 @@ final public class Accounts implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); /** * Even with the check above, it is still possible that * the case will be closed in a different thread before @@ -529,7 +527,7 @@ final public class Accounts implements AutopsyVisitableItem { && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { reviewStatusBus.post(eventData); } - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { // Case is closed, do nothing. } } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) @@ -541,10 +539,10 @@ final public class Accounts implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); refresh(true); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { // Case is closed, do nothing. } } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { @@ -651,7 +649,7 @@ final public class Accounts implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); /** * Even with the check above, it is still possible that * the case will be closed in a different thread before @@ -663,7 +661,7 @@ final public class Accounts implements AutopsyVisitableItem { && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { reviewStatusBus.post(eventData); } - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { // Case is closed, do nothing. } } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) @@ -675,10 +673,10 @@ final public class Accounts implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); refresh(true); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { // Case is closed, do nothing. } } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { @@ -862,7 +860,7 @@ final public class Accounts implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); /** * Even with the check above, it is still possible that * the case will be closed in a different thread before @@ -874,7 +872,7 @@ final public class Accounts implements AutopsyVisitableItem { && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { reviewStatusBus.post(eventData); } - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { // Case is closed, do nothing. } } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) @@ -886,10 +884,10 @@ final public class Accounts implements AutopsyVisitableItem { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); refresh(true); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { // Case is closed, do nothing. } } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { @@ -1161,13 +1159,13 @@ final public class Accounts implements AutopsyVisitableItem { * take the result of a group_concat SQLite operation and split it into a * set of X using the mapper to to convert from string to X * - * @param the type of elements to return + * @param the type of elements to return * @param groupConcat a string containing the group_concat result ( a comma - * separated list) - * @param mapper a function from String to X + * separated list) + * @param mapper a function from String to X * * @return a Set of X, each element mapped from one element of the original - * comma delimited string + * comma delimited string */ static List unGroupConcat(String groupConcat, Function mapper) { return StringUtils.isBlank(groupConcat) ? Collections.emptyList() @@ -1187,8 +1185,8 @@ final public class Accounts implements AutopsyVisitableItem { /** * Constructor * - * @param key The FileWithCCN that backs this node. - * @param content The Content object the key represents. + * @param key The FileWithCCN that backs this node. + * @param content The Content object the key represents. * @param lookupContents The contents of this Node's lookup. It should * contain the content object and the account artifacts. */ @@ -1465,11 +1463,11 @@ final public class Accounts implements AutopsyVisitableItem { } return sheet; } - + private void updateSheet() { this.setSheet(createSheet()); } - + } /** @@ -1601,7 +1599,7 @@ final public class Accounts implements AutopsyVisitableItem { super(artifact, "org/sleuthkit/autopsy/images/credit-card.png"); //NON-NLS this.artifact = artifact; setName("" + this.artifact.getArtifactID()); - + reviewStatusBus.register(this); } @@ -1628,13 +1626,13 @@ final public class Accounts implements AutopsyVisitableItem { Bundle.Accounts_FileWithCCNNode_statusProperty_displayName(), Bundle.Accounts_FileWithCCNNode_noDescription(), artifact.getReviewStatus().getDisplayName())); - + return sheet; } - + @Subscribe void handleReviewStatusChange(ReviewStatusChangeEvent event) { - + // Update the node if event includes this artifact event.artifacts.stream().filter((art) -> (art.getArtifactID() == this.artifact.getArtifactID())).map((_item) -> { return _item; @@ -1642,11 +1640,11 @@ final public class Accounts implements AutopsyVisitableItem { updateSheet(); }); } - + private void updateSheet() { this.setSheet(createSheet()); } - + } private final class ToggleShowRejected extends AbstractAction { @@ -1755,14 +1753,47 @@ final public class Accounts implements AutopsyVisitableItem { } } - private class ReviewStatusChangeEvent { + static private class ReviewStatusChangeEvent { Collection artifacts; BlackboardArtifact.ReviewStatus newReviewStatus; - public ReviewStatusChangeEvent(Collection artifacts, BlackboardArtifact.ReviewStatus newReviewStatus) { + ReviewStatusChangeEvent(Collection artifacts, BlackboardArtifact.ReviewStatus newReviewStatus) { this.artifacts = artifacts; this.newReviewStatus = newReviewStatus; } } + + /** + * Get the path of the icon for the given Account Type. + * + * @return The path of the icon for the given Account Type. + */ + public static String getIconFilePath(Account.Type type) { + + if (type.equals(Account.Type.CREDIT_CARD)) { + return iconBasePath + "credit-card.png"; + } else if (type.equals(Account.Type.DEVICE)) { + return iconBasePath + "image.png"; + } else if (type.equals(Account.Type.EMAIL)) { + return iconBasePath + "email.png"; + } else if (type.equals(Account.Type.FACEBOOK)) { + return iconBasePath + "facebook.png"; + } else if (type.equals(Account.Type.INSTAGRAM)) { + return iconBasePath + "instagram.png"; + } else if (type.equals(Account.Type.MESSAGING_APP)) { + return iconBasePath + "messaging.png"; + } else if (type.equals(Account.Type.PHONE)) { + return iconBasePath + "phone.png"; + } else if (type.equals(Account.Type.TWITTER)) { + return iconBasePath + "twitter.png"; + } else if (type.equals(Account.Type.WEBSITE)) { + return iconBasePath + "web-file.png"; + } else if (type.equals(Account.Type.WHATSAPP)) { + return iconBasePath + "WhatsApp.png"; + } else { + //there could be a default icon instead... + throw new IllegalArgumentException("Unknown Account.Type: " + type.getTypeName()); + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AddRawImageTask.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AddRawImageTask.java index 3d576eebf0..a65e32c8a6 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AddRawImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AddRawImageTask.java @@ -3,7 +3,7 @@ package org.sleuthkit.autopsy.datasourceprocessors; /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,6 +35,7 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskFileRange; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /* * A runnable that adds a raw data source to a case database. @@ -121,11 +122,20 @@ final class AddRawImageTask implements Runnable { "AddRawImageTask.image.critical.error.adding=Critical error adding ", "AddRawImageTask.for.device=for device ", "AddRawImageTask.image.notExisting=is not existing.", - "AddRawImageTask.image.noncritical.error.adding=Non-critical error adding "}) + "AddRawImageTask.image.noncritical.error.adding=Non-critical error adding ", + "AddRawImageTask.noOpenCase.errMsg=No open case available."}) private void addImageToCase(List dataSources, List errorMessages) { + SleuthkitCase caseDatabase; + try { + caseDatabase = Case.getOpenCase().getSleuthkitCase(); + } catch (NoCurrentCaseException ex) { + errorMessages.add(Bundle.AddRawImageTask_noOpenCase_errMsg()); + logger.log(Level.SEVERE, Bundle.AddRawImageTask_noOpenCase_errMsg(), ex); + criticalErrorOccurred = true; + return; + } progressMonitor.setProgressText(Bundle.AddRawImageTask_progress_add_text() + imageFilePath); List imageFilePaths = new ArrayList<>(); - SleuthkitCase caseDatabase = Case.getCurrentCase().getSleuthkitCase(); File imageFile = Paths.get(imageFilePath).toFile(); if (!imageFile.exists()) { String errorMessage = Bundle.AddRawImageTask_image_critical_error_adding() + imageFilePath + Bundle.AddRawImageTask_for_device() diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java index 7c0b16af78..a8572a4664 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,6 +28,7 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PathValidator; @@ -296,12 +297,18 @@ final class RawDSInputPanel extends JPanel implements DocumentListener { * * @param path Absolute path to the selected data source */ - @Messages({"RawDSInputPanel.error.text=Path to multi-user data source is on \"C:\" drive"}) + @Messages({"RawDSInputPanel.error.text=Path to multi-user data source is on \"C:\" drive", + "RawDSInputPanel.noOpenCase.errMsg=Exception while getting open case."}) private void warnIfPathIsInvalid(String path) { - if (!PathValidator.isValid(path, Case.getCurrentCase().getCaseType())) { + try { + if (!PathValidator.isValid(path, Case.getOpenCase().getCaseType())) { errorLabel.setVisible(true); errorLabel.setText(Bundle.RawDSInputPanel_error_text()); } + } catch (NoCurrentCaseException ex) { + errorLabel.setVisible(true); + errorLabel.setText(Bundle.RawDSInputPanel_noOpenCase_errMsg()); + } } void storeSettings() { diff --git a/Core/src/org/sleuthkit/autopsy/diagnostics/PerformancePanel.java b/Core/src/org/sleuthkit/autopsy/diagnostics/PerformancePanel.java index 56600fc2f3..1525958390 100644 --- a/Core/src/org/sleuthkit/autopsy/diagnostics/PerformancePanel.java +++ b/Core/src/org/sleuthkit/autopsy/diagnostics/PerformancePanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -299,7 +299,7 @@ public class PerformancePanel extends javax.swing.JDialog { Case curCase; try { - curCase = Case.getCurrentCase(); + curCase = Case.getOpenCase(); } catch (Exception e) { setImgLabel(NbBundle.getMessage(this.getClass(), "PerformancePanel.label.caseNotOpen.text")); setStatusMsg(""); @@ -380,7 +380,7 @@ public class PerformancePanel extends javax.swing.JDialog { Case curCase; try { - curCase = Case.getCurrentCase(); + curCase = Case.getOpenCase(); } catch (Exception e) { setFileReadLabel( NbBundle.getMessage(this.getClass(), "PerformancePanel.label.caseNotOpen.text")); @@ -472,7 +472,7 @@ public class PerformancePanel extends javax.swing.JDialog { Case curCase; try { - curCase = Case.getCurrentCase(); + curCase = Case.getOpenCase(); } catch (Exception e) { setDbLabel(NbBundle.getMessage(this.getClass(), "PerformancePanel.label.caseNotOpen.text")); return; diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index e0c9670a2a..13219f863d 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -53,6 +53,7 @@ import org.openide.util.NbBundle.Messages; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.corecomponentinterfaces.CoreComponentControl; @@ -363,8 +364,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); Case currentCase = null; try { - currentCase = Case.getCurrentCase(); - } catch (IllegalStateException ex) { + currentCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { // No open case. } @@ -524,7 +525,12 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * be closed if there is no opne case or the open case has no data * sources. */ - return !Case.isCaseOpen() || Case.getCurrentCase().hasData() == false; + try { + Case openCase = Case.getOpenCase(); + return openCase.hasData() == false; + } catch (NoCurrentCaseException ex) { + return true; + } } /** @@ -613,13 +619,13 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * already closed. */ try { - Case currentCase = Case.getCurrentCase(); + Case currentCase = Case.getOpenCase(); // We only need to trigger openCoreWindows() when the // first data source is added. if (currentCase.getDataSources().size() == 1) { SwingUtilities.invokeLater(CoreComponentControl::openCoreWindows); } - } catch (IllegalStateException | TskCoreException notUsed) { + } catch (NoCurrentCaseException | TskCoreException notUsed) { /** * Case is closed, do nothing. */ diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerAction.java index bd88f359ab..c453cc6a91 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerAction.java @@ -29,6 +29,7 @@ import org.openide.nodes.Node; import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.SlackFileNode; @@ -79,7 +80,14 @@ public class ExternalViewerAction extends AbstractAction { @Override public void actionPerformed(ActionEvent e) { // Get the temp folder path of the case - String tempPath = Case.getCurrentCase().getTempDirectory(); + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Exception while getting open case.", ex); //NON-NLS + return; + } + String tempPath = openCase.getTempDirectory(); tempPath = tempPath + File.separator + this.fileObject.getName(); // create the temporary file diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java index 207c9c1231..28a8bac071 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,9 +33,11 @@ import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.netbeans.api.progress.ProgressHandle; import org.openide.util.Cancellable; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -95,9 +97,18 @@ public final class ExtractAction extends AbstractAction { * @param e * @param selectedFile Selected file */ + @NbBundle.Messages ({"ExtractAction.noOpenCase.errMsg=No open case available."}) private void extractFile(ActionEvent e, AbstractFile selectedFile) { + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + JOptionPane.showMessageDialog((Component) e.getSource(), Bundle.ExtractAction_noOpenCase_errMsg()); + logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS + return; + } JFileChooser fileChooser = new JFileChooser(); - fileChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory())); + fileChooser.setCurrentDirectory(new File(openCase.getExportDirectory())); // If there is an attribute name, change the ":". Otherwise the extracted file will be hidden fileChooser.setSelectedFile(new File(FileUtil.escapeFileName(selectedFile.getName()))); if (fileChooser.showSaveDialog((Component) e.getSource()) == JFileChooser.APPROVE_OPTION) { @@ -114,9 +125,17 @@ public final class ExtractAction extends AbstractAction { * @param selectedFiles Selected files */ private void extractFiles(ActionEvent e, Collection selectedFiles) { + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + JOptionPane.showMessageDialog((Component) e.getSource(), Bundle.ExtractAction_noOpenCase_errMsg()); + logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS + return; + } JFileChooser folderChooser = new JFileChooser(); folderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - folderChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory())); + folderChooser.setCurrentDirectory(new File(openCase.getExportDirectory())); if (folderChooser.showSaveDialog((Component) e.getSource()) == JFileChooser.APPROVE_OPTION) { File destinationFolder = folderChooser.getSelectedFile(); if (!destinationFolder.exists()) { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java index b415b190ea..1960089075 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -41,6 +41,7 @@ import org.netbeans.api.progress.ProgressHandle; import org.openide.util.Cancellable; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.datamodel.AbstractContent; @@ -100,7 +101,8 @@ final class ExtractUnallocAction extends AbstractAction { "ExtractUnallocAction.volumeInProgress=Already extracting unallocated space into {0} - will skip this volume", "ExtractUnallocAction.volumeError=Error extracting unallocated space from volume", "ExtractUnallocAction.noFiles=No unallocated files found on volume", - "ExtractUnallocAction.imageError=Error extracting unallocated space from image"}) + "ExtractUnallocAction.imageError=Error extracting unallocated space from image", + "ExtractUnallocAction.noOpenCase.errMsg=No open case available."}) @Override public void actionPerformed(ActionEvent e) { if (filesToExtract != null && filesToExtract.size() > 0) { @@ -111,6 +113,13 @@ final class ExtractUnallocAction extends AbstractAction { //JOptionPane.showMessageDialog(new Frame(), "Unallocated Space is already being extracted on this Image. Please select a different Image."); return; } + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + MessageNotifyUtil.Message.info(Bundle.ExtractAction_noOpenCase_errMsg()); + return; + } List copyList = new ArrayList() { { addAll(filesToExtract); @@ -130,7 +139,7 @@ final class ExtractUnallocAction extends AbstractAction { } }; - fileChooser.setCurrentDirectory(new File(Case.getCurrentCase().getExportDirectory())); + fileChooser.setCurrentDirectory(new File(openCase.getExportDirectory())); fileChooser.setDialogTitle( NbBundle.getMessage(this.getClass(), "ExtractUnallocAction.dlgTitle.selectDirToSaveTo.msg")); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewSourceArtifactAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewSourceArtifactAction.java index a9d23a14de..04a2cccc2c 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewSourceArtifactAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewSourceArtifactAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,6 +23,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; @@ -48,7 +49,7 @@ class ViewSourceArtifactAction extends AbstractAction { try { for (BlackboardAttribute attribute : artifact.getAttributes()) { if (attribute.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) { - BlackboardArtifact associatedArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong()); + BlackboardArtifact associatedArtifact = Case.getOpenCase().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong()); if (associatedArtifact != null) { dirTree.viewArtifact(associatedArtifact); break; @@ -56,7 +57,7 @@ class ViewSourceArtifactAction extends AbstractAction { } } - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.WARNING, "Unable to perform view artifact on an associated artifact of " + artifact.getDisplayName(), ex); //NON-NLS } } diff --git a/Core/src/org/sleuthkit/autopsy/examples/SampleDataSourceIngestModule.java b/Core/src/org/sleuthkit/autopsy/examples/SampleDataSourceIngestModule.java index d1f1d7e5aa..8605d33c13 100644 --- a/Core/src/org/sleuthkit/autopsy/examples/SampleDataSourceIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/examples/SampleDataSourceIngestModule.java @@ -32,6 +32,7 @@ package org.sleuthkit.autopsy.examples; import java.util.List; import java.util.logging.Level; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; @@ -76,7 +77,7 @@ class SampleDataSourceIngestModule implements DataSourceIngestModule { try { // Get count of files with .doc extension. - FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); + FileManager fileManager = Case.getOpenCase().getServices().getFileManager(); List docFiles = fileManager.findFiles(dataSource, "%.doc"); long fileCount = 0; @@ -117,7 +118,7 @@ class SampleDataSourceIngestModule implements DataSourceIngestModule { return IngestModule.ProcessResult.OK; - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { IngestServices ingestServices = IngestServices.getInstance(); Logger logger = ingestServices.getLogger(SampleIngestModuleFactory.getModuleName()); logger.log(Level.SEVERE, "File query failed", ex); diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java index 64666e66d9..661e08a542 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -43,6 +43,7 @@ import javax.swing.border.EmptyBorder; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** * Filters file date properties (modified/created/etc.. times) @@ -140,7 +141,7 @@ class DateSearchFilter extends AbstractFileSearchFilter { try { // get the latest case - Case currentCase = Case.getCurrentCase(); // get the most updated case + Case currentCase = Case.getOpenCase(); // get the most updated case Set caseTimeZones = currentCase.getTimeZones(); Iterator iterator = caseTimeZones.iterator(); @@ -167,7 +168,7 @@ class DateSearchFilter extends AbstractFileSearchFilter { String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id); //NON-NLS timeZones.add(item); } - } catch (IllegalStateException ex) { + } catch (NoCurrentCaseException ex) { // No current case. } @@ -281,9 +282,9 @@ class DateSearchFilter extends AbstractFileSearchFilter { * that is already closed. */ try { - Case.getCurrentCase(); + Case.getOpenCase(); SwingUtilities.invokeLater(DateSearchFilter.this::updateTimeZoneList); - } catch (IllegalStateException notUsed) { + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java index 21c62d9c3e..ae894f632a 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java @@ -43,6 +43,7 @@ import org.openide.NotifyDescriptor; import org.openide.util.NbBundle; import org.openide.windows.TopComponent; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.coreutils.Logger; @@ -152,7 +153,7 @@ class FileSearchPanel extends javax.swing.JPanel { String pathText = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.pathText"); // try to get the number of matches first - Case currentCase = Case.getCurrentCase(); // get the most updated case + Case currentCase = Case.getOpenCase(); // get the most updated case long totalMatches = 0; List contentList = null; try { @@ -189,7 +190,7 @@ class FileSearchPanel extends javax.swing.JPanel { throw new FilterValidationException( NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.exception.noFilterSelected.msg")); } - } catch (FilterValidationException ex) { + } catch (FilterValidationException | NoCurrentCaseException ex) { NotifyDescriptor d = new NotifyDescriptor.Message( NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.validationErr.msg", ex.getMessage())); DialogDisplayer.getDefault().notify(d); diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/WhatsApp.png b/Core/src/org/sleuthkit/autopsy/images/WhatsApp.png similarity index 100% rename from Core/src/org/sleuthkit/autopsy/communications/images/WhatsApp.png rename to Core/src/org/sleuthkit/autopsy/images/WhatsApp.png diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/email.png b/Core/src/org/sleuthkit/autopsy/images/email.png similarity index 100% rename from Core/src/org/sleuthkit/autopsy/communications/images/email.png rename to Core/src/org/sleuthkit/autopsy/images/email.png diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/facebook.png b/Core/src/org/sleuthkit/autopsy/images/facebook.png similarity index 100% rename from Core/src/org/sleuthkit/autopsy/communications/images/facebook.png rename to Core/src/org/sleuthkit/autopsy/images/facebook.png diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/instagram.png b/Core/src/org/sleuthkit/autopsy/images/instagram.png similarity index 100% rename from Core/src/org/sleuthkit/autopsy/communications/images/instagram.png rename to Core/src/org/sleuthkit/autopsy/images/instagram.png diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/messaging.png b/Core/src/org/sleuthkit/autopsy/images/messaging.png similarity index 100% rename from Core/src/org/sleuthkit/autopsy/communications/images/messaging.png rename to Core/src/org/sleuthkit/autopsy/images/messaging.png diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/phone.png b/Core/src/org/sleuthkit/autopsy/images/phone.png similarity index 100% rename from Core/src/org/sleuthkit/autopsy/communications/images/phone.png rename to Core/src/org/sleuthkit/autopsy/images/phone.png diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/twitter.png b/Core/src/org/sleuthkit/autopsy/images/twitter.png similarity index 100% rename from Core/src/org/sleuthkit/autopsy/communications/images/twitter.png rename to Core/src/org/sleuthkit/autopsy/images/twitter.png diff --git a/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java b/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java index 3cd166a1b5..b7d064aa44 100644 --- a/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java +++ b/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,6 +32,7 @@ import java.util.logging.Level; import org.netbeans.api.progress.ProgressHandle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Image; @@ -78,12 +79,12 @@ class ImageWriter implements PropertyChangeListener{ this.settings = settings; doUI = RuntimeProperties.runningWithGUI(); - // We save the reference to the sleuthkit case here in case getCurrentCase() is set to + // We save the reference to the sleuthkit case here in case getOpenCase() is set to // null before Image Writer finishes. The user can still elect to wait for image writer // (in ImageWriterService.closeCaseResources) even though the case is closing. try{ - caseDb = Case.getCurrentCase().getSleuthkitCase(); - } catch (IllegalStateException ex){ + caseDb = Case.getOpenCase().getSleuthkitCase(); + } catch (NoCurrentCaseException ex){ logger.log(Level.SEVERE, "Unable to load case. Image writer will be cancelled."); this.isCancelled = true; } @@ -151,10 +152,10 @@ class ImageWriter implements PropertyChangeListener{ Image image; try{ - image = Case.getCurrentCase().getSleuthkitCase().getImageById(dataSourceId); + image = Case.getOpenCase().getSleuthkitCase().getImageById(dataSourceId); imageHandle = image.getImageHandle(); - } catch (IllegalStateException ex){ - // This exception means that getCurrentCase() failed because no case was open. + } catch (NoCurrentCaseException ex){ + // This exception means that getOpenCase() failed because no case was open. // This can happen when the user closes the case while ingest is ongoing - canceling // ingest fires off the DataSourceAnalysisCompletedEvent while the case is in the // process of closing. @@ -173,7 +174,7 @@ class ImageWriter implements PropertyChangeListener{ periodicTasksExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("image-writer-progress-update-%d").build()); //NON-NLS progressHandle = ProgressHandle.createHandle(Bundle.ImageWriter_progressBar_message(dataSourceName)); progressHandle.start(100); - progressUpdateTask = periodicTasksExecutor.scheduleAtFixedRate( + progressUpdateTask = periodicTasksExecutor.scheduleWithFixedDelay( new ProgressUpdateTask(progressHandle, imageHandle), 0, 250, TimeUnit.MILLISECONDS); } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java index 568e410de6..8ba34c9492 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java @@ -34,6 +34,7 @@ import org.openide.util.Cancellable; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.NetworkUtils; import org.sleuthkit.datamodel.AbstractFile; @@ -254,12 +255,12 @@ final class DataSourceIngestJob { */ Thread.currentThread().interrupt(); } - SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); try { + SleuthkitCase skCase = Case.getOpenCase().getSleuthkitCase(); this.addIngestModules(firstStageDataSourceModuleTemplates, IngestModuleType.DATA_SOURCE_LEVEL, skCase); this.addIngestModules(fileIngestModuleTemplates, IngestModuleType.FILE_LEVEL, skCase); this.addIngestModules(secondStageDataSourceModuleTemplates, IngestModuleType.DATA_SOURCE_LEVEL, skCase); - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Failed to add ingest modules to database.", ex); } } @@ -338,7 +339,7 @@ final class DataSourceIngestJob { * @return True or false. */ FilesSet getFileIngestFilter() { - return this.settings.getFileIngestFilter(); + return this.settings.getFileFilter(); } /** @@ -400,8 +401,8 @@ final class DataSourceIngestJob { this.startSecondStage(); } try { - this.ingestJob = Case.getCurrentCase().getSleuthkitCase().addIngestJob(dataSource, NetworkUtils.getLocalHostName(), ingestModules, new Date(this.createTime), new Date(0), IngestJobStatusType.STARTED, ""); - } catch (TskCoreException ex) { + this.ingestJob = Case.getOpenCase().getSleuthkitCase().addIngestJob(dataSource, NetworkUtils.getLocalHostName(), ingestModules, new Date(this.createTime), new Date(0), IngestJobStatusType.STARTED, ""); + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Failed to add ingest job to database.", ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/GetFilesCountVisitor.java b/Core/src/org/sleuthkit/autopsy/ingest/GetFilesCountVisitor.java index df9eeacbff..94b9b2a93b 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/GetFilesCountVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/GetFilesCountVisitor.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.FileSystem; @@ -44,7 +45,13 @@ final class GetFilesCountVisitor extends ContentVisitor.Default { public Long visit(FileSystem fs) { //recursion stop here //case of a real fs, query all files for it - SleuthkitCase sc = Case.getCurrentCase().getSleuthkitCase(); + SleuthkitCase sc; + try { + sc = Case.getOpenCase().getSleuthkitCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return 0L; + } StringBuilder queryB = new StringBuilder(); queryB.append("( (fs_obj_id = ").append(fs.getId()); //NON-NLS //queryB.append(") OR (fs_obj_id = NULL) )"); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java index ad93b012c3..5b8f54db97 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2014-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,6 +26,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -43,148 +44,159 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSet; import org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager; /** - * Encapsulates the ingest job settings for a particular execution context. - * Examples of execution contexts include the add data source wizard and the run - * ingest modules dialog. Different execution contexts may have different ingest - * job settings. + * The settings for an ingest job. */ -public class IngestJobSettings { +public final class IngestJobSettings { - private static final String ENABLED_MODULES_KEY = "Enabled_Ingest_Modules"; //NON-NLS - private static final String DISABLED_MODULES_KEY = "Disabled_Ingest_Modules"; //NON-NLS - private static final String LAST_FILE_INGEST_FILTER_KEY = "Last_File_Ingest_Filter"; //NON-NLS + private static final String ENABLED_MODULES_PROPERTY = "Enabled_Ingest_Modules"; //NON-NLS + private static final String DISABLED_MODULES_PROPERTY = "Disabled_Ingest_Modules"; //NON-NLS + private static final String LAST_FILE_INGEST_FILTER_PROPERTY = "Last_File_Ingest_Filter"; //NON-NLS private static final String MODULE_SETTINGS_FOLDER = "IngestModuleSettings"; //NON-NLS private static final String MODULE_SETTINGS_FOLDER_PATH = Paths.get(PlatformUtil.getUserConfigDirectory(), IngestJobSettings.MODULE_SETTINGS_FOLDER).toAbsolutePath().toString(); private static final String MODULE_SETTINGS_FILE_EXT = ".settings"; //NON-NLS - private static final Logger LOGGER = Logger.getLogger(IngestJobSettings.class.getName()); - private FilesSet fileIngestFilter; - private String executionContext; + private static final CharSequence PYTHON_CLASS_PROXY_PREFIX = "org.python.proxies.".subSequence(0, "org.python.proxies.".length() - 1); //NON-NLS + private static final Logger logger = Logger.getLogger(IngestJobSettings.class.getName()); private final IngestType ingestType; + private final List moduleTemplates = new ArrayList<>(); + private final List warnings = new ArrayList<>(); + private String executionContext; + private FilesSet fileFilter; private String moduleSettingsFolderPath; - private static final CharSequence pythonModuleSettingsPrefixCS = "org.python.proxies.".subSequence(0, "org.python.proxies.".length() - 1); //NON-NLS - private final List moduleTemplates; - private final List warnings; /** - * Gets the last selected FileIngestFilter saved in settings which is - * represented by a FilesSet, if the last selected filter is null the - * default filter will be returned. + * Gets the path to the module settings folder for a given execution + * context. * - * @return FilesSet which represents the FileIngestFilter + * Some examples of execution contexts include the Add Data Source wizard, + * the Run Ingest Modules dialog, and auto ingest. Different execution + * contexts may have different ingest job settings. + * + * @param The execution context identifier. + * + * @return The path to the module settings folder */ - FilesSet getFileIngestFilter() { - if (fileIngestFilter == null) { - fileIngestFilter = FilesSetsManager.getDefaultFilter(); - } - return fileIngestFilter; + static Path getSavedModuleSettingsFolder(String executionContext) { + return Paths.get(IngestJobSettings.MODULE_SETTINGS_FOLDER_PATH, executionContext); } /** - * Sets the FileIngestFilter which is currently being used by ingest. + * Loads the ingest job settings for a given execution context. If settings + * for the context have not been previously saved, default settings are + * used. * - * @param fileIngestFilter the FilesSet which represents the - * FileIngestFilter + * Some examples of execution contexts include the Add Data Source wizard, + * the Run Ingest Modules dialog, and auto ingest. Different execution + * contexts may have different ingest job settings. + * + * @param executionContext The execution context identifier. */ - void setFileIngestFilter(FilesSet fileIngestFilter) { - this.fileIngestFilter = fileIngestFilter; + public IngestJobSettings(final String executionContext) { + this(executionContext, IngestType.ALL_MODULES); } /** - * The type of ingest modules to run. - */ - public enum IngestType { - - /** - * Run both data source level and file-level ingest modules. - */ - ALL_MODULES, - /** - * Run only data source level ingest modules. - */ - DATA_SOURCE_ONLY, - /** - * Run only file level ingest modules. - */ - FILES_ONLY - } - - /** - * Constructs an ingest job settings object for a given execution context. - * Examples of execution contexts include the add data source wizard and the - * run ingest modules dialog. Different execution contexts may have - * different ingest job settings. + * Loads the ingest job settings for a given execution context. If settings + * for the context have not been previously saved, default settings are + * used. * - * @param executionContext The ingest execution context identifier. - */ - public IngestJobSettings(String executionContext) { - this.executionContext = executionContext; - this.ingestType = IngestType.ALL_MODULES; - this.moduleTemplates = new ArrayList<>(); - this.warnings = new ArrayList<>(); - this.createSavedModuleSettingsFolder(); - this.load(); - } - - /** - * Constructs an ingest job settings object for a given context. Examples of - * execution contexts include the add data source wizard and the run ingest - * modules dialog. Different execution contexts may have different ingest - * job settings. + * Some examples of execution contexts include the Add Data Source wizard, + * the Run Ingest Modules dialog, and auto ingest. Different execution + * contexts may have different ingest job settings. * - * @param context The context identifier string. - * @param ingestType The type of modules ingest is running. + * @param executionContext The execution context identifier. + * @param ingestType Whether to run all ingest modules, data source + * level ingest modules only, or file level ingest + * modules only. */ - public IngestJobSettings(String context, IngestType ingestType) { + public IngestJobSettings(String executionContext, IngestType ingestType) { this.ingestType = ingestType; - if (this.ingestType.equals(IngestType.ALL_MODULES)) { - this.executionContext = context; + this.executionContext = executionContext; } else { - this.executionContext = context + "." + this.ingestType.name(); + this.executionContext = executionContext + "." + this.ingestType.name(); } - - this.moduleTemplates = new ArrayList<>(); - - this.warnings = new ArrayList<>(); this.createSavedModuleSettingsFolder(); this.load(); } + /** + * Creates entirely new ingest job settings for a given context without + * saving them. + * + * @param executionContext The execution context identifier. + * @param ingestType Whether to run all ingest modules, data source + * level ingest modules only, or file level ingest + * modules only. + * @param moduleTemplates A collection of ingest module templates for + * creating fully configured ingest modules; each + * template combines an ingest module factory with + * ingest module job settings and an enabled flag. + */ + public IngestJobSettings(String executionContext, IngestType ingestType, Collection moduleTemplates) { + this.ingestType = ingestType; + if (this.ingestType.equals(IngestType.ALL_MODULES)) { + this.executionContext = executionContext; + } else { + this.executionContext = executionContext + "." + this.ingestType.name(); + } + this.moduleTemplates.addAll(moduleTemplates); + } + + /** + * Creates entirely new ingest job settings for a given context without + * saving them. + * + * @param executionContext The execution context identifier. + * @param ingestType Whether to run all ingest modules, data source + * level ingest modules only, or file level ingest + * modules only. + * @param moduleTemplates A collection of ingest module templates for + * creating fully configured ingest modules; each + * template combines an ingest module factory with + * ingest module job settings and an enabled flag. + * @param fileFilter A file filter in the form of a files set. + */ + public IngestJobSettings(String executionContext, IngestType ingestType, Collection moduleTemplates, FilesSet fileFilter) { + this(executionContext, ingestType, moduleTemplates); + this.setFileFilter(fileFilter); + } + + /** + * Gets the path to the module settings folder for these ingest job + * settings. + * + * @return The path to the ingest module settings folder. + */ + public Path getSavedModuleSettingsFolder() { + return Paths.get(IngestJobSettings.MODULE_SETTINGS_FOLDER_PATH, executionContext); + } + /** * Saves these ingest job settings. */ public void save() { + this.createSavedModuleSettingsFolder(); this.store(); } /** - * Saves the settings with a new context name removing the old profile - * folder + * Saves these ingest job settings for use in a different execution context. * - * @param executionContext will be used to name the new folder for storing - * the settings + * Some examples of execution contexts include the Add Data Source wizard, + * the Run Ingest Modules dialog, and auto ingest. Different execution + * contexts may have different ingest job settings. + * + * @param executionContext The new execution context. */ - void saveAs(String executionContext) { + public void saveAs(String executionContext) { this.executionContext = executionContext; this.createSavedModuleSettingsFolder(); this.store(); } /** - * Gets the ingest execution context identifier. Examples of execution - * contexts include the add data source wizard and the run ingest modules - * dialog. Different execution contexts may have different ingest job - * settings. - * - * @return The execution context identifier. - */ - String getExecutionContext() { - return this.executionContext; - } - - /** - * Gets and clears any accumulated warnings associated with these ingest job - * settings. + * Gets and clears any accumulated warnings associated with the loading or + * saving of these ingest job settings. * * @return A list of warning messages, possibly empty. */ @@ -195,21 +207,64 @@ public class IngestJobSettings { } /** - * Gets the ingest module templates part of these ingest job settings. + * Gets the execution context identifier. + * + * Some examples of execution contexts include the Add Data Source wizard, + * the Run Ingest Modules dialog, and auto ingest. Different execution + * contexts may have different ingest job settings. + * + * @return The execution context identifier. + */ + public String getExecutionContext() { + return this.executionContext; + } + + /** + * Gets the file filter for the ingest job. + * + * @return FilesSet The filter as a files set. + */ + public FilesSet getFileFilter() { + if (fileFilter == null) { + fileFilter = FilesSetsManager.getDefaultFilter(); + } + return fileFilter; + } + + /** + * Sets the file filter for the ingest job. + * + * @param fileIngestFilter The filter as a files set. + */ + public void setFileFilter(FilesSet fileIngestFilter) { + this.fileFilter = fileIngestFilter; + } + + /** + * Gets the enabled ingest module templates for the ingest job. * * @return The list of ingest module templates. */ - List getIngestModuleTemplates() { + public List getIngestModuleTemplates() { return Collections.unmodifiableList(this.moduleTemplates); } /** - * Gets the enabled ingest module templates part of these ingest job - * settings. + * Sets the enabled ingest module templates for the ingest job. + * + * @param moduleTemplates The ingest module templates. + */ + public void setIngestModuleTemplates(List moduleTemplates) { + this.moduleTemplates.clear(); + this.moduleTemplates.addAll(moduleTemplates); + } + + /** + * Gets the enabled ingest module templates for this ingest job. * * @return The list of enabled ingest module templates. */ - List getEnabledIngestModuleTemplates() { + public List getEnabledIngestModuleTemplates() { List enabledModuleTemplates = new ArrayList<>(); for (IngestModuleTemplate moduleTemplate : this.moduleTemplates) { if (moduleTemplate.isEnabled()) { @@ -220,60 +275,22 @@ public class IngestJobSettings { } /** - * Sets the ingest module templates part of these ingest job settings. - * - * @param moduleTemplates The ingest module templates. - */ - void setIngestModuleTemplates(List moduleTemplates) { - this.moduleTemplates.clear(); - this.moduleTemplates.addAll(moduleTemplates); - } - - /** - * Gets the process unallocated space flag part of these ingest job - * settings. + * Gets the process unallocated space flag for this ingest job. * * @return True or false. * */ - boolean getProcessUnallocatedSpace() { - /* - * Used to be a simple flag but the processUnallocated checkbox was - * changed to a skip unallocated. This was due to the FileIngestFilters - * needing a default value which did not skip unallocated files. This - * method exists to maintain existing functionality. - */ + public boolean getProcessUnallocatedSpace() { boolean processUnallocated = true; - if (!Objects.isNull(this.fileIngestFilter)) { - processUnallocated = (this.fileIngestFilter.ingoresUnallocatedSpace() == false); + if (!Objects.isNull(this.fileFilter)) { + processUnallocated = (this.fileFilter.ingoresUnallocatedSpace() == false); } return processUnallocated; } /** - * Returns the path to the ingest module settings folder. - * - * @return path to the module settings folder - */ - public Path getSavedModuleSettingsFolder() { - return Paths.get(IngestJobSettings.MODULE_SETTINGS_FOLDER_PATH, executionContext); - } - - /** - * Returns the path to the ingest module settings folder from a static - * manner. - * - * @param context specify the context of the folder you wish to get - * - * @return path to the module settings folder - */ - static Path getSavedModuleSettingsFolder(String context) { - return Paths.get(IngestJobSettings.MODULE_SETTINGS_FOLDER_PATH, context); - } - - /** - * Creates the folder for saving the individual ingest module settings part - * of these ingest job settings. + * Creates the module folder for these ingest job settings, if it does not + * already exist. */ private void createSavedModuleSettingsFolder() { try { @@ -281,13 +298,14 @@ public class IngestJobSettings { Files.createDirectories(folder); this.moduleSettingsFolderPath = folder.toAbsolutePath().toString(); } catch (IOException | SecurityException ex) { - LOGGER.log(Level.SEVERE, "Failed to create ingest module settings directory " + this.moduleSettingsFolderPath, ex); //NON-NLS + logger.log(Level.SEVERE, "Failed to create ingest module settings directory " + this.moduleSettingsFolderPath, ex); //NON-NLS this.warnings.add(NbBundle.getMessage(IngestJobSettings.class, "IngestJobSettings.createModuleSettingsFolder.warning")); //NON-NLS } } /** - * Loads the saved or default ingest job settings context into memory. + * Loads the saved or default ingest job settings for the execution context + * into memory. */ private void load() { /** @@ -317,8 +335,8 @@ public class IngestJobSettings { * Get the enabled/disabled ingest modules settings for this context. By * default, all loaded modules are enabled. */ - HashSet enabledModuleNames = getModulesNamesFromSetting(executionContext, IngestJobSettings.ENABLED_MODULES_KEY, makeCommaSeparatedValuesList(loadedModuleNames)); - HashSet disabledModuleNames = getModulesNamesFromSetting(executionContext, IngestJobSettings.DISABLED_MODULES_KEY, ""); //NON-NLS + HashSet enabledModuleNames = getModulesNames(executionContext, IngestJobSettings.ENABLED_MODULES_PROPERTY, makeCsvList(loadedModuleNames)); + HashSet disabledModuleNames = getModulesNames(executionContext, IngestJobSettings.DISABLED_MODULES_PROPERTY, ""); //NON-NLS /** * Check for missing modules and create warnings if any are found. @@ -338,7 +356,7 @@ public class IngestJobSettings { enabledModuleNames.remove(moduleName); disabledModuleNames.remove(moduleName); String warning = NbBundle.getMessage(IngestJobSettings.class, "IngestJobSettings.missingModule.warning", moduleName); //NON-NLS - LOGGER.log(Level.WARNING, warning); + logger.log(Level.WARNING, warning); this.warnings.add(warning); } @@ -367,14 +385,14 @@ public class IngestJobSettings { * Update the enabled/disabled ingest module settings for this context * to reflect any missing modules or newly discovered modules. */ - ModuleSettings.setConfigSetting(this.executionContext, IngestJobSettings.ENABLED_MODULES_KEY, makeCommaSeparatedValuesList(enabledModuleNames)); - ModuleSettings.setConfigSetting(this.executionContext, IngestJobSettings.DISABLED_MODULES_KEY, makeCommaSeparatedValuesList(disabledModuleNames)); + ModuleSettings.setConfigSetting(this.executionContext, IngestJobSettings.ENABLED_MODULES_PROPERTY, makeCsvList(enabledModuleNames)); + ModuleSettings.setConfigSetting(this.executionContext, IngestJobSettings.DISABLED_MODULES_PROPERTY, makeCsvList(disabledModuleNames)); /** * Restore the last used File Ingest Filter */ - if (ModuleSettings.settingExists(this.executionContext, IngestJobSettings.LAST_FILE_INGEST_FILTER_KEY) == false) { - ModuleSettings.setConfigSetting(this.executionContext, IngestJobSettings.LAST_FILE_INGEST_FILTER_KEY, FilesSetsManager.getDefaultFilter().getName()); + if (ModuleSettings.settingExists(this.executionContext, IngestJobSettings.LAST_FILE_INGEST_FILTER_PROPERTY) == false) { + ModuleSettings.setConfigSetting(this.executionContext, IngestJobSettings.LAST_FILE_INGEST_FILTER_PROPERTY, FilesSetsManager.getDefaultFilter().getName()); } try { Map fileIngestFilters = FilesSetsManager.getInstance() @@ -382,35 +400,37 @@ public class IngestJobSettings { for (FilesSet fSet : FilesSetsManager.getStandardFileIngestFilters()) { fileIngestFilters.put(fSet.getName(), fSet); } - this.fileIngestFilter = fileIngestFilters.get(ModuleSettings.getConfigSetting( - this.executionContext, IngestJobSettings.LAST_FILE_INGEST_FILTER_KEY)); + this.fileFilter = fileIngestFilters.get(ModuleSettings.getConfigSetting(this.executionContext, IngestJobSettings.LAST_FILE_INGEST_FILTER_PROPERTY)); } catch (FilesSetsManager.FilesSetsManagerException ex) { - this.fileIngestFilter = FilesSetsManager.getDefaultFilter(); - LOGGER.log(Level.SEVERE, "Failed to get file ingest filter from .properties file, default filter being used", ex); //NON-NLS + this.fileFilter = FilesSetsManager.getDefaultFilter(); + logger.log(Level.SEVERE, "Failed to get file filter from .properties file, default filter being used", ex); //NON-NLS } } /** - * Gets the module names for a given key within these ingest job settings. + * Gets a list of enabled module names from the properties file for the + * execution context of these ingest job settings. * - * @param context The identifier for the context for which to get the - * module names, e.g., the Add Data Source wizard or - * Run Ingest Modules context. - * @param key The key string. - * @param defaultSetting The default list of module names. + * @param executionContext The execution context identifier. + * @param propertyName The property name. + * @param defaultSetting The default list of module names to se and return + * if the property does not exist. * - * @return The list of module names associated with the key. + * @return */ - private static HashSet getModulesNamesFromSetting(String context, String key, String defaultSetting) { - if (ModuleSettings.settingExists(context, key) == false) { - ModuleSettings.setConfigSetting(context, key, defaultSetting); + private static HashSet getModulesNames(String executionContext, String propertyName, String defaultSetting) { + if (ModuleSettings.settingExists(executionContext, propertyName) == false) { + ModuleSettings.setConfigSetting(executionContext, propertyName, defaultSetting); } HashSet moduleNames = new HashSet<>(); - String modulesSetting = ModuleSettings.getConfigSetting(context, key); + String modulesSetting = ModuleSettings.getConfigSetting(executionContext, propertyName); if (!modulesSetting.isEmpty()) { String[] settingNames = modulesSetting.split(", "); for (String name : settingNames) { - // Map some old core module names to the current core module names. + /* + * Map some obsolete core ingest module names to the current + * core ingest module names. + */ switch (name) { case "Thunderbird Parser": //NON-NLS case "MBox Parser": //NON-NLS @@ -435,7 +455,7 @@ public class IngestJobSettings { } /** - * Get a set which contains all the names of enabled modules for the + * Gets a set which contains all the names of enabled modules for the * specified context. * * @param context -the execution context (profile name) to check @@ -443,7 +463,7 @@ public class IngestJobSettings { * @return the names of the enabled modules */ static List getEnabledModules(String context) { - return new ArrayList<>(getModulesNamesFromSetting(context, ENABLED_MODULES_KEY, "")); + return new ArrayList<>(getModulesNames(context, ENABLED_MODULES_PROPERTY, "")); } /** @@ -457,14 +477,13 @@ public class IngestJobSettings { * @return True or false */ private boolean isPythonModuleSettingsFile(String moduleSettingsFilePath) { - return moduleSettingsFilePath.contains(pythonModuleSettingsPrefixCS); + return moduleSettingsFilePath.contains(PYTHON_CLASS_PROXY_PREFIX); } /** - * Gets the saved or default ingest job settings for a given ingest module - * for these ingest job settings. + * Gets the saved or default ingest job settings for a given ingest module. * - * @param factory The ingest module factory for an ingest module. + * @param factory The ingest module factory. * * @return The ingest module settings. */ @@ -478,7 +497,7 @@ public class IngestJobSettings { settings = (IngestModuleIngestJobSettings) in.readObject(); } catch (IOException | ClassNotFoundException ex) { String warning = NbBundle.getMessage(IngestJobSettings.class, "IngestJobSettings.moduleSettingsLoad.warning", factory.getModuleDisplayName(), this.executionContext); //NON-NLS - LOGGER.log(Level.WARNING, warning, ex); + logger.log(Level.WARNING, warning, ex); this.warnings.add(warning); } } else { @@ -486,7 +505,7 @@ public class IngestJobSettings { settings = (IngestModuleIngestJobSettings) in.readObject(); } catch (IOException | ClassNotFoundException exception) { String warning = NbBundle.getMessage(IngestJobSettings.class, "IngestJobSettings.moduleSettingsLoad.warning", factory.getModuleDisplayName(), this.executionContext); //NON-NLS - LOGGER.log(Level.WARNING, warning, exception); + logger.log(Level.WARNING, warning, exception); this.warnings.add(warning); } } @@ -529,18 +548,17 @@ public class IngestJobSettings { disabledModuleNames.add(moduleName); } } - ModuleSettings.setConfigSetting(this.executionContext, IngestJobSettings.ENABLED_MODULES_KEY, makeCommaSeparatedValuesList(enabledModuleNames)); - ModuleSettings.setConfigSetting(this.executionContext, IngestJobSettings.DISABLED_MODULES_KEY, makeCommaSeparatedValuesList(disabledModuleNames)); + ModuleSettings.setConfigSetting(this.executionContext, IngestJobSettings.ENABLED_MODULES_PROPERTY, makeCsvList(enabledModuleNames)); + ModuleSettings.setConfigSetting(this.executionContext, IngestJobSettings.DISABLED_MODULES_PROPERTY, makeCsvList(disabledModuleNames)); /** * Save the last used File Ingest Filter setting for this context. */ - ModuleSettings.setConfigSetting(this.executionContext, LAST_FILE_INGEST_FILTER_KEY, fileIngestFilter.getName()); + ModuleSettings.setConfigSetting(this.executionContext, LAST_FILE_INGEST_FILTER_PROPERTY, fileFilter.getName()); } /** - * Serializes the ingest job settings for this context for a given ingest - * module. + * Serializes the ingest job settings for a given ingest module. * * @param factory The ingest module factory for the module. * @param settings The ingest job settings for the ingest module @@ -551,26 +569,26 @@ public class IngestJobSettings { out.writeObject(settings); } catch (IOException ex) { String warning = NbBundle.getMessage(IngestJobSettings.class, "IngestJobSettings.moduleSettingsSave.warning", factory.getModuleDisplayName(), this.executionContext); //NON-NLS - LOGGER.log(Level.SEVERE, warning, ex); + logger.log(Level.SEVERE, warning, ex); this.warnings.add(warning); } } /** - * Makes a comma-separated values list from a hash set of strings. + * Makes a comma-separated values list from a collection of strings. * - * @param input A hash set of strings. + * @param collection A collection of strings. * - * @return The contents of the hash set as a single string of + * @return The contents of the collection as a single string of * comma-separated values. */ - private static String makeCommaSeparatedValuesList(HashSet input) { - if (input == null || input.isEmpty()) { + private static String makeCsvList(Collection collection) { + if (collection == null || collection.isEmpty()) { return ""; } ArrayList list = new ArrayList<>(); - list.addAll(input); + list.addAll(collection); StringBuilder csvList = new StringBuilder(); for (int i = 0; i < list.size() - 1; ++i) { csvList.append(list.get(i)).append(", "); @@ -579,4 +597,23 @@ public class IngestJobSettings { return csvList.toString(); } + /** + * The type of ingest modules to run. + */ + public enum IngestType { + + /** + * Run both data source level and file-level ingest modules. + */ + ALL_MODULES, + /** + * Run only data source level ingest modules. + */ + DATA_SOURCE_ONLY, + /** + * Run only file level ingest modules. + */ + FILES_ONLY + } + } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index 6f15b3606d..b5aef4ad0b 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -43,6 +43,7 @@ import javax.swing.table.TableColumn; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.IngestJobInfoPanel; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationDialog; import org.sleuthkit.autopsy.modules.interestingitems.FilesSet; import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel; @@ -83,7 +84,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { } initComponents(); customizeComponents(); - fileIngestFilterComboBox.setSelectedItem(settings.getFileIngestFilter().getName()); + fileIngestFilterComboBox.setSelectedItem(settings.getFileFilter().getName()); } /** @@ -97,9 +98,9 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { this.settings = settings; this.dataSources.addAll(dataSources); try { - SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); + SleuthkitCase skCase = Case.getOpenCase().getSleuthkitCase(); ingestJobs.addAll(skCase.getIngestJobs()); - } catch (IllegalStateException ex) { + } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "No open case", ex); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Failed to load ingest job information", ex); @@ -109,7 +110,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { } initComponents(); customizeComponents(); - fileIngestFilterComboBox.setSelectedItem(settings.getFileIngestFilter().getName()); + fileIngestFilterComboBox.setSelectedItem(settings.getFileFilter().getName()); } /** @@ -425,19 +426,19 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { for (FilesSet filter : newFilterList) { //getting one of the recently created filters if (!oldFilterList.contains(filter.getName())) { //set newly created filter to selected filter - settings.setFileIngestFilter(filter); + settings.setFileFilter(filter); break; } } fileIngestFilterComboBox.setModel(new DefaultComboBoxModel<>(getComboBoxContents())); //set the selected filter after the comboBox Contents were updated to include it - fileIngestFilterComboBox.setSelectedItem(settings.getFileIngestFilter().getName()); + fileIngestFilterComboBox.setSelectedItem(settings.getFileFilter().getName()); dialog.close(); } ); dialog.display(fileIngestFilterPanel); //return to saved selection in case they cancel out of filter creation - fileIngestFilterComboBox.setSelectedItem(settings.getFileIngestFilter().getName()); + fileIngestFilterComboBox.setSelectedItem(settings.getFileFilter().getName()); } else if (evt.getActionCommand().equals("comboBoxChanged")) { try { Map fileIngestFilters = FilesSetsManager.getInstance() @@ -445,10 +446,10 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { for (FilesSet fSet : FilesSetsManager.getStandardFileIngestFilters()) { fileIngestFilters.put(fSet.getName(), fSet); } - settings.setFileIngestFilter(fileIngestFilters + settings.setFileFilter(fileIngestFilters .get(fileIngestFilterComboBox.getSelectedItem().toString())); } catch (FilesSetsManager.FilesSetsManagerException ex) { - settings.setFileIngestFilter(FilesSetsManager.getDefaultFilter()); + settings.setFileFilter(FilesSetsManager.getDefaultFilter()); logger.log(Level.SEVERE, "Failed to get file ingest filter from combobox selection, default filter being used", ex); //NON-NLS } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index 089ebfc53e..13d67f9e9c 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -50,6 +50,7 @@ import org.openide.util.Cancellable; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.core.ServicesMonitor; import org.sleuthkit.autopsy.core.UserPreferences; @@ -190,10 +191,10 @@ public class IngestManager { * only necessary for multi-user cases. */ try { - if (Case.getCurrentCase().getCaseType() != Case.CaseType.MULTI_USER_CASE) { + if (Case.getOpenCase().getCaseType() != Case.CaseType.MULTI_USER_CASE) { return; } - } catch (IllegalStateException noCaseOpenException) { + } catch (NoCurrentCaseException noCaseOpenException) { return; } @@ -251,13 +252,13 @@ public class IngestManager { caseIsOpen = true; clearIngestMessageBox(); try { - Case openedCase = Case.getCurrentCase(); + Case openedCase = Case.getOpenCase(); String channelPrefix = openedCase.getName(); if (Case.CaseType.MULTI_USER_CASE == openedCase.getCaseType()) { jobEventPublisher.openRemoteEventChannel(String.format(INGEST_JOB_EVENT_CHANNEL_NAME, channelPrefix)); moduleEventPublisher.openRemoteEventChannel(String.format(INGEST_MODULE_EVENT_CHANNEL_NAME, channelPrefix)); } - } catch (IllegalStateException | AutopsyEventException ex) { + } catch (NoCurrentCaseException | AutopsyEventException ex) { logger.log(Level.SEVERE, "Failed to open remote events channel", ex); //NON-NLS MessageNotifyUtil.Notify.error(NbBundle.getMessage(IngestManager.class, "IngestManager.OpenEventChannel.Fail.Title"), NbBundle.getMessage(IngestManager.class, "IngestManager.OpenEventChannel.Fail.ErrMsg")); @@ -347,61 +348,65 @@ public class IngestManager { }) private IngestJobStartResult startIngestJob(IngestJob job) { List errors = null; - if (caseIsOpen) { - if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { - try { - if (!servicesMonitor.getServiceStatus(ServicesMonitor.Service.REMOTE_CASE_DATABASE.toString()).equals(ServicesMonitor.ServiceStatus.UP.toString())) { - if (RuntimeProperties.runningWithGUI()) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - String serviceDisplayName = ServicesMonitor.Service.REMOTE_CASE_DATABASE.getDisplayName(); - JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), - NbBundle.getMessage(this.getClass(), "IngestManager.cancellingIngest.msgDlg.text"), - NbBundle.getMessage(this.getClass(), "IngestManager.serviceIsDown.msgDlg.text", serviceDisplayName), - JOptionPane.ERROR_MESSAGE); - } - }); - } - return new IngestJobStartResult(null, new IngestManagerException("Ingest aborted. Remote database is down"), Collections.emptyList()); //NON-NLS + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + return new IngestJobStartResult(null, new IngestManagerException("Exception while getting open case.", ex), Collections.emptyList()); //NON-NLS + } + if (openCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { + try { + if (!servicesMonitor.getServiceStatus(ServicesMonitor.Service.REMOTE_CASE_DATABASE.toString()).equals(ServicesMonitor.ServiceStatus.UP.toString())) { + if (RuntimeProperties.runningWithGUI()) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + String serviceDisplayName = ServicesMonitor.Service.REMOTE_CASE_DATABASE.getDisplayName(); + JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), + NbBundle.getMessage(this.getClass(), "IngestManager.cancellingIngest.msgDlg.text"), + NbBundle.getMessage(this.getClass(), "IngestManager.serviceIsDown.msgDlg.text", serviceDisplayName), + JOptionPane.ERROR_MESSAGE); + } + }); } - } catch (ServicesMonitor.ServicesMonitorException ex) { - return new IngestJobStartResult(null, new IngestManagerException("Database server is down", ex), Collections.emptyList()); //NON-NLS + return new IngestJobStartResult(null, new IngestManagerException("Ingest aborted. Remote database is down"), Collections.emptyList()); //NON-NLS } + } catch (ServicesMonitor.ServicesMonitorException ex) { + return new IngestJobStartResult(null, new IngestManagerException("Database server is down", ex), Collections.emptyList()); //NON-NLS } + } - if (!ingestMonitor.isRunning()) { - ingestMonitor.start(); + if (!ingestMonitor.isRunning()) { + ingestMonitor.start(); + } + + ingestJobsById.put(job.getId(), job); + errors = job.start(); + if (errors.isEmpty()) { + this.fireIngestJobStarted(job.getId()); + IngestManager.logger.log(Level.INFO, "Ingest job {0} started", job.getId()); //NON-NLS + } else { + this.ingestJobsById.remove(job.getId()); + for (IngestModuleError error : errors) { + logger.log(Level.SEVERE, String.format("Error starting %s ingest module for job %d", error.getModuleDisplayName(), job.getId()), error.getThrowable()); //NON-NLS } - - ingestJobsById.put(job.getId(), job); - errors = job.start(); - if (errors.isEmpty()) { - this.fireIngestJobStarted(job.getId()); - IngestManager.logger.log(Level.INFO, "Ingest job {0} started", job.getId()); //NON-NLS - } else { - this.ingestJobsById.remove(job.getId()); + IngestManager.logger.log(Level.SEVERE, "Ingest job {0} could not be started", job.getId()); //NON-NLS + if (RuntimeProperties.runningWithGUI()) { + final StringBuilder message = new StringBuilder(1024); + message.append(Bundle.IngestManager_startupErr_dlgMsg()).append("\n"); //NON-NLS + message.append(Bundle.IngestManager_startupErr_dlgSolution()).append("\n\n"); //NON-NLS + message.append(Bundle.IngestManager_startupErr_dlgErrorList()).append("\n"); //NON-NLS for (IngestModuleError error : errors) { - logger.log(Level.SEVERE, String.format("Error starting %s ingest module for job %d", error.getModuleDisplayName(), job.getId()), error.getThrowable()); //NON-NLS + String moduleName = error.getModuleDisplayName(); + String errorMessage = error.getThrowable().getLocalizedMessage(); + message.append(moduleName).append(": ").append(errorMessage).append("\n"); //NON-NLS } - IngestManager.logger.log(Level.SEVERE, "Ingest job {0} could not be started", job.getId()); //NON-NLS - if (RuntimeProperties.runningWithGUI()) { - final StringBuilder message = new StringBuilder(1024); - message.append(Bundle.IngestManager_startupErr_dlgMsg()).append("\n"); //NON-NLS - message.append(Bundle.IngestManager_startupErr_dlgSolution()).append("\n\n"); //NON-NLS - message.append(Bundle.IngestManager_startupErr_dlgErrorList()).append("\n"); //NON-NLS - for (IngestModuleError error : errors) { - String moduleName = error.getModuleDisplayName(); - String errorMessage = error.getThrowable().getLocalizedMessage(); - message.append(moduleName).append(": ").append(errorMessage).append("\n"); //NON-NLS - } - message.append("\n\n"); - EventQueue.invokeLater(() -> { - JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), message, Bundle.IngestManager_startupErr_dlgTitle(), JOptionPane.ERROR_MESSAGE); - }); - } - return new IngestJobStartResult(null, new IngestManagerException("Errors occurred while starting ingest"), errors); //NON-NLS + message.append("\n\n"); + EventQueue.invokeLater(() -> { + JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), message, Bundle.IngestManager_startupErr_dlgTitle(), JOptionPane.ERROR_MESSAGE); + }); } + return new IngestJobStartResult(null, new IngestManagerException("Errors occurred while starting ingest"), errors); //NON-NLS } return new IngestJobStartResult(job, null, errors); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageDetailsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageDetailsPanel.java index 363a11b969..52698415d3 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageDetailsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageDetailsPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,7 @@ import javax.swing.JMenuItem; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.ingest.IngestMessagePanel.IngestMessageGroup; import org.sleuthkit.datamodel.AbstractFile; @@ -247,8 +248,8 @@ class IngestMessageDetailsPanel extends javax.swing.JPanel { long objId = artifact.getObjectID(); AbstractFile file = null; try { - file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId); - } catch (TskException ex) { + file = Case.getOpenCase().getSleuthkitCase().getAbstractFileById(objId); + } catch (TskException | NoCurrentCaseException ex) { } if (file == null) { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleTemplate.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleTemplate.java index 9353ba0bf2..83a290c78a 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleTemplate.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleTemplate.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,74 +22,75 @@ package org.sleuthkit.autopsy.ingest; * Combines an ingest module factory with ingest module settings and an enabled * flag to create a template for creating fully configured ingest modules. */ -final class IngestModuleTemplate { +public final class IngestModuleTemplate { private final IngestModuleFactory moduleFactory; private IngestModuleIngestJobSettings settings = null; private boolean enabled = true; - IngestModuleTemplate(IngestModuleFactory moduleFactory, IngestModuleIngestJobSettings settings) { + public IngestModuleTemplate(IngestModuleFactory moduleFactory, IngestModuleIngestJobSettings settings) { this.moduleFactory = moduleFactory; this.settings = settings; } - IngestModuleFactory getModuleFactory() { + public IngestModuleFactory getModuleFactory() { return moduleFactory; } - String getModuleName() { + public String getModuleName() { return moduleFactory.getModuleDisplayName(); } - String getModuleDescription() { + public String getModuleDescription() { return moduleFactory.getModuleDescription(); } - IngestModuleIngestJobSettings getModuleSettings() { + public IngestModuleIngestJobSettings getModuleSettings() { return settings; } - void setModuleSettings(IngestModuleIngestJobSettings settings) { + public void setModuleSettings(IngestModuleIngestJobSettings settings) { this.settings = settings; } - boolean hasModuleSettingsPanel() { + public boolean hasModuleSettingsPanel() { return moduleFactory.hasIngestJobSettingsPanel(); } - IngestModuleIngestJobSettingsPanel getModuleSettingsPanel() { + public IngestModuleIngestJobSettingsPanel getModuleSettingsPanel() { return moduleFactory.getIngestJobSettingsPanel(settings); } - boolean hasGlobalSettingsPanel() { + public boolean hasGlobalSettingsPanel() { return moduleFactory.hasGlobalSettingsPanel(); } - IngestModuleGlobalSettingsPanel getGlobalSettingsPanel() { + public IngestModuleGlobalSettingsPanel getGlobalSettingsPanel() { return moduleFactory.getGlobalSettingsPanel(); } - boolean isDataSourceIngestModuleTemplate() { + public boolean isDataSourceIngestModuleTemplate() { return moduleFactory.isDataSourceIngestModuleFactory(); } - DataSourceIngestModule createDataSourceIngestModule() { + public DataSourceIngestModule createDataSourceIngestModule() { return moduleFactory.createDataSourceIngestModule(settings); } - boolean isFileIngestModuleTemplate() { + public boolean isFileIngestModuleTemplate() { return moduleFactory.isFileIngestModuleFactory(); } - FileIngestModule createFileIngestModule() { + public FileIngestModule createFileIngestModule() { return moduleFactory.createFileIngestModule(settings); } - void setEnabled(boolean enabled) { + public void setEnabled(boolean enabled) { this.enabled = enabled; } - boolean isEnabled() { + public boolean isEnabled() { return enabled; } + } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java index 8aeda52597..e4c5c41340 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,6 +31,7 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.Timer; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.events.AutopsyEvent; @@ -144,11 +145,11 @@ public final class IngestMonitor { */ private void findRootDirectoryForCurrentCase() { try { - Case currentCase = Case.getCurrentCase(); + Case currentCase = Case.getOpenCase(); findRootDirectoryForCurrentCase(currentCase); - } catch (IllegalStateException unused) { + } catch (NoCurrentCaseException unused) { /* - * Case.getCurrentCase() throws IllegalStateException when there + * Case.getOpenCase() throws NoCurrentCaseException when there * is no case. */ root = new File(File.separator); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestServices.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestServices.java index 8310d36297..f70c9b0813 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestServices.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestServices.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.ingest; import java.util.Map; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.datamodel.SleuthkitCase; @@ -53,18 +54,20 @@ public final class IngestServices { * Get the current Autopsy case. * * @return The current case. + * @throws NoCurrentCaseException if there is no open case. */ - public Case getCurrentCase() { - return Case.getCurrentCase(); + public Case getOpenCase() throws NoCurrentCaseException { + return Case.getOpenCase(); } /** * Get the current SleuthKit case. The SleuthKit case is the case database. * * @return The current case database. + * @throws NoCurrentCaseException if there is no open case. */ - public SleuthkitCase getCurrentSleuthkitCaseDb() { - return Case.getCurrentCase().getSleuthkitCase(); + public SleuthkitCase getCurrentSleuthkitCaseDb() throws NoCurrentCaseException { + return Case.getOpenCase().getSleuthkitCase(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index 83b7cd3036..ec09fbca6e 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -222,7 +222,7 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { } else if (!profile.getName().equals(getProfileName())) { IngestProfile.renameProfile(profile.getName(), getProfileName()); } - profile = new IngestProfile(getProfileName(), profileDescArea.getText(), ingestSettingsPanel.getSettings().getFileIngestFilter().getName()); + profile = new IngestProfile(getProfileName(), profileDescArea.getText(), ingestSettingsPanel.getSettings().getFileFilter().getName()); IngestProfile.saveProfile(profile); ingestSettingsPanel.getSettings().saveAs(getProfileName()); } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestAction.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestAction.java index 49875a3997..72bc963fe7 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,6 +29,7 @@ import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** * The action associated with assorted Run Ingest Modules menu items. @@ -82,6 +83,11 @@ public final class RunIngestAction extends CallableSystemAction implements Prese @Override public boolean isEnabled() { - return Case.isCaseOpen() && Case.getCurrentCase().hasData(); + try { + Case openCase = Case.getOpenCase(); + return openCase.hasData(); + } catch (NoCurrentCaseException ex) { + return false; + } } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java index 0900e3041d..d58c57da72 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestSubMenu.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,6 +27,7 @@ import javax.swing.JMenuItem; import org.openide.awt.DynamicMenuContent; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; @@ -48,11 +49,11 @@ final class RunIngestSubMenu extends JMenuItem implements DynamicMenuContent { List dataSources = new ArrayList<>(); try { - dataSources = Case.getCurrentCase().getDataSources(); + dataSources = Case.getOpenCase().getDataSources(); } catch (IllegalStateException ex) { // No open Cases, create a disabled empty menu return getEmpty(); - } catch (TskCoreException e) { + } catch (TskCoreException | NoCurrentCaseException e) { System.out.println("Exception getting images: " + e.getMessage()); //NON-NLS } JComponent[] comps = new JComponent[dataSources.size()]; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/events/BlackboardPostEvent.java b/Core/src/org/sleuthkit/autopsy/ingest/events/BlackboardPostEvent.java index 7846f122f3..9e05d538de 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/events/BlackboardPostEvent.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/events/BlackboardPostEvent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,6 +26,7 @@ import java.util.logging.Level; import java.util.stream.Collectors; import javax.annotation.concurrent.Immutable; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -93,11 +94,11 @@ public final class BlackboardPostEvent extends AutopsyEvent implements Serializa SerializableEventData data = (SerializableEventData) super.getOldValue(); Collection artifacts = new ArrayList<>(); for (Long id : data.artifactIds) { - artifacts.add(Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(id)); + artifacts.add(Case.getOpenCase().getSleuthkitCase().getBlackboardArtifact(id)); } eventData = new ModuleDataEvent(data.moduleName, data.artifactTypeId, !artifacts.isEmpty() ? artifacts : null); return eventData; - } catch (IllegalStateException | TskCoreException ex) { + } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS return null; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/events/ContentChangedEvent.java b/Core/src/org/sleuthkit/autopsy/ingest/events/ContentChangedEvent.java index 0f7dcdc0dc..d22cefb5ac 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/events/ContentChangedEvent.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/events/ContentChangedEvent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.ingest.events; import java.io.Serializable; import java.util.logging.Level; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -85,10 +86,10 @@ public final class ContentChangedEvent extends AutopsyEvent implements Serializa } try { SerializableEventData data = (SerializableEventData) super.getOldValue(); - Content content = Case.getCurrentCase().getSleuthkitCase().getContentById(data.contentId); + Content content = Case.getOpenCase().getSleuthkitCase().getContentById(data.contentId); eventData = new ModuleContentEvent(data.moduleName, content); return eventData; - } catch (IllegalStateException | TskCoreException ex) { + } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS return null; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/events/DataSourceAnalysisEvent.java b/Core/src/org/sleuthkit/autopsy/ingest/events/DataSourceAnalysisEvent.java index c508d3e276..100db13067 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/events/DataSourceAnalysisEvent.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/events/DataSourceAnalysisEvent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.ingest.events; import java.io.Serializable; import java.util.logging.Level; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -96,9 +97,9 @@ public abstract class DataSourceAnalysisEvent extends AutopsyEvent implements Se } try { long id = (Long) super.getNewValue(); - dataSource = Case.getCurrentCase().getSleuthkitCase().getContentById(id); + dataSource = Case.getOpenCase().getSleuthkitCase().getContentById(id); return dataSource; - } catch (IllegalStateException | TskCoreException ex) { + } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS return null; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/events/FileAnalyzedEvent.java b/Core/src/org/sleuthkit/autopsy/ingest/events/FileAnalyzedEvent.java index afc8c0a996..6845fcf391 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/events/FileAnalyzedEvent.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/events/FileAnalyzedEvent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.ingest.events; import java.io.Serializable; import java.util.logging.Level; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -76,9 +77,9 @@ public final class FileAnalyzedEvent extends AutopsyEvent implements Serializabl } try { long id = (Long) super.getOldValue(); - file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(id); + file = Case.getOpenCase().getSleuthkitCase().getAbstractFileById(id); return file; - } catch (IllegalStateException | TskCoreException ex) { + } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS return null; } diff --git a/Core/src/org/sleuthkit/autopsy/menuactions/DataContentDynamicMenu.java b/Core/src/org/sleuthkit/autopsy/menuactions/DataContentDynamicMenu.java index 40ae79064c..a677f8042a 100644 --- a/Core/src/org/sleuthkit/autopsy/menuactions/DataContentDynamicMenu.java +++ b/Core/src/org/sleuthkit/autopsy/menuactions/DataContentDynamicMenu.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,6 +27,7 @@ import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.windows.TopComponent; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent; import org.sleuthkit.autopsy.corecomponents.DataContentTopComponent; @@ -51,9 +52,9 @@ class DataContentDynamicMenu extends JMenuItem implements DynamicMenuContent { defaultItem.addActionListener(new OpenTopComponentAction(contentWin)); try { - Case currentCase = Case.getCurrentCase(); + Case currentCase = Case.getOpenCase(); defaultItem.setEnabled(currentCase.hasData()); - } catch (IllegalStateException ex) { + } catch (NoCurrentCaseException ex) { defaultItem.setEnabled(false); // disable the menu when no case is opened } diff --git a/Core/src/org/sleuthkit/autopsy/menuactions/DataExplorerDynamicMenu.java b/Core/src/org/sleuthkit/autopsy/menuactions/DataExplorerDynamicMenu.java index 16776ecdf4..38377d0f28 100644 --- a/Core/src/org/sleuthkit/autopsy/menuactions/DataExplorerDynamicMenu.java +++ b/Core/src/org/sleuthkit/autopsy/menuactions/DataExplorerDynamicMenu.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,7 @@ import org.openide.awt.DynamicMenuContent; import org.openide.util.Lookup; import org.openide.windows.TopComponent; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataExplorer; /** @@ -54,9 +55,9 @@ class DataExplorerDynamicMenu extends JMenuItem implements DynamicMenuContent { item.addActionListener(new OpenTopComponentAction(explorerWin)); try { - Case currentCase = Case.getCurrentCase(); + Case currentCase = Case.getOpenCase(); item.setEnabled(currentCase.hasData()); - } catch (IllegalStateException ex) { + } catch (NoCurrentCaseException ex) { item.setEnabled(false); // disable the menu when no case is opened } diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java index 64df63b8c9..bb7a220efd 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,6 +28,7 @@ import org.sleuthkit.autopsy.ingest.IngestModule.ProcessResult; import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import net.sf.sevenzipjbinding.SevenZipNativeInitializationException; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.ingest.FileIngestModuleAdapter; /** @@ -37,7 +38,9 @@ import org.sleuthkit.autopsy.ingest.FileIngestModuleAdapter; @NbBundle.Messages({ "CannotCreateOutputFolder=Unable to create output folder.", "CannotRunFileTypeDetection=Unable to run file type detection.", - "UnableToInitializeLibraries=Unable to initialize 7Zip libraries." + "UnableToInitializeLibraries=Unable to initialize 7Zip libraries.", + "EmbeddedFileExtractorIngestModule.NoOpenCase.errMsg=No open case available.", + "EmbeddedFileExtractorIngestModule.UnableToGetMSOfficeExtractor.errMsg=Unable to get MSOfficeEmbeddedContentExtractor." }) public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAdapter { @@ -63,10 +66,13 @@ public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAda * case database for extracted (derived) file paths. The absolute path * is used to write the extracted (derived) files to local storage. */ - final Case currentCase = Case.getCurrentCase(); + try { + final Case currentCase = Case.getOpenCase(); moduleDirRelative = Paths.get(currentCase.getModuleOutputDirectoryRelativePath(), EmbeddedFileExtractorModuleFactory.getModuleName()).toString(); moduleDirAbsolute = Paths.get(currentCase.getModuleDirectory(), EmbeddedFileExtractorModuleFactory.getModuleName()).toString(); - + } catch (NoCurrentCaseException ex) { + throw new IngestModuleException(Bundle.EmbeddedFileExtractorIngestModule_NoOpenCase_errMsg(), ex); + } /* * Create the output directory. */ @@ -101,7 +107,11 @@ public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAda * Construct an embedded content extractor for processing Microsoft * Office documents. */ - this.officeExtractor = new MSOfficeEmbeddedContentExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute); + try { + this.officeExtractor = new MSOfficeEmbeddedContentExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute); + } catch (NoCurrentCaseException ex) { + throw new IngestModuleException(Bundle.EmbeddedFileExtractorIngestModule_UnableToGetMSOfficeExtractor_errMsg(), ex); + } } @Override diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java index 506fc5a6f3..23e33dc180 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java @@ -55,6 +55,7 @@ import org.apache.tika.parser.microsoft.OfficeParserConfig; import org.apache.tika.sax.BodyContentHandler; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestJobContext; @@ -115,9 +116,9 @@ class MSOfficeEmbeddedContentExtractor { } private SupportedExtractionFormats abstractFileExtractionFormat; - MSOfficeEmbeddedContentExtractor(IngestJobContext context, FileTypeDetector fileTypeDetector, String moduleDirRelative, String moduleDirAbsolute) { + MSOfficeEmbeddedContentExtractor(IngestJobContext context, FileTypeDetector fileTypeDetector, String moduleDirRelative, String moduleDirAbsolute) throws NoCurrentCaseException { - this.fileManager = Case.getCurrentCase().getServices().getFileManager(); + this.fileManager = Case.getOpenCase().getServices().getFileManager(); this.services = IngestServices.getInstance(); this.context = context; this.fileTypeDetector = fileTypeDetector; diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 2a08f88723..5639576c98 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -46,6 +46,7 @@ import org.netbeans.api.progress.ProgressHandle; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.coreutils.FileUtil; @@ -347,9 +348,9 @@ class SevenZipExtractor { UnpackedTree.UnpackedNode currentNode = node; String name = currentNode.getFileName(); currentNode = currentNode.getParent(); - while(currentNode != null && currentNode.getParent() != null){ - name = currentNode.getFileName() +"/"+ name; - currentNode = currentNode.getParent(); + while (currentNode != null && currentNode.getParent() != null) { + name = currentNode.getFileName() + "/" + name; + currentNode = currentNode.getParent(); } // String dataSourceName = null; // if (lastNode != null){ @@ -435,7 +436,13 @@ class SevenZipExtractor { //recursion depth check for zip bomb final long archiveId = archiveFile.getId(); SevenZipExtractor.ArchiveDepthCountTree.Archive parentAr = null; - blackboard = Case.getCurrentCase().getServices().getBlackboard(); + try { + blackboard = Case.getOpenCase().getServices().getBlackboard(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS + unpackSuccessful = false; + return unpackSuccessful; + } try { List existingFiles = getAlreadyExtractedFiles(archiveFile, archiveFilePath); @@ -609,8 +616,8 @@ class SevenZipExtractor { } } - } catch (TskCoreException e) { - logger.log(Level.SEVERE, "Error populating complete derived file hierarchy from the unpacked dir structure"); //NON-NLS + } catch (TskCoreException | NoCurrentCaseException e) { + logger.log(Level.SEVERE, "Error populating complete derived file hierarchy from the unpacked dir structure", e); //NON-NLS //TODO decide if anything to cleanup, for now bailing } @@ -933,8 +940,8 @@ class SevenZipExtractor { * Traverse the tree top-down after unzipping is done and create derived * files for the entire hierarchy */ - void updateOrAddFileToCaseRec(HashMap statusMap, String archiveFilePath) throws TskCoreException { - final FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); + void updateOrAddFileToCaseRec(HashMap statusMap, String archiveFilePath) throws TskCoreException, NoCurrentCaseException { + final FileManager fileManager = Case.getOpenCase().getServices().getFileManager(); for (UnpackedNode child : rootNode.children) { updateOrAddFileToCaseRec(child, fileManager, statusMap, archiveFilePath); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties index 95ce1719ef..37cfd1d8b2 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties @@ -1,6 +1,6 @@ EncryptionDetectionIngestJobSettingsPanel.minimumEntropyLabel.text=Minimum Entropy: EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeLabel.text=Minimum File Size: -EncryptionDetectionIngestJobSettingsPanel.fileSizeMultiplesEnforcedCheckbox.text=Consider only files with sizes that are multiples of 512. +EncryptionDetectionIngestJobSettingsPanel.fileSizeMultiplesEnforcedCheckbox.text=Consider only file sizes that are multiples of 512. EncryptionDetectionIngestJobSettingsPanel.slackFilesAllowedCheckbox.text=Consider slack space files. EncryptionDetectionIngestJobSettingsPanel.mbLabel.text=MB EncryptionDetectionIngestJobSettingsPanel.detectionSettingsLabel.text=Detection Settings diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java index 0e618ba9c9..7b48606ea0 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java @@ -25,6 +25,7 @@ import java.util.Collections; import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.FileIngestModuleAdapter; @@ -87,10 +88,12 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter public void startUp(IngestJobContext context) throws IngestModule.IngestModuleException { try { validateSettings(); - blackboard = Case.getCurrentCase().getServices().getBlackboard(); + blackboard = Case.getOpenCase().getServices().getBlackboard(); fileTypeDetector = new FileTypeDetector(); } catch (FileTypeDetector.FileTypeDetectorInitException ex) { throw new IngestModule.IngestModuleException("Failed to create file type detector", ex); + } catch (NoCurrentCaseException ex) { + throw new IngestModule.IngestModuleException("Exception while getting open case.", ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form index c2bb97607e..2f66c65b81 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form @@ -35,7 +35,7 @@
- +
@@ -59,7 +59,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java index eb318ccdfd..b4e2ed487a 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java @@ -174,7 +174,7 @@ final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngest .addComponent(minimumEntropyLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(minimumEntropyTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addContainerGap(15, Short.MAX_VALUE)) + .addContainerGap(33, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -194,7 +194,7 @@ final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngest .addComponent(fileSizeMultiplesEnforcedCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(slackFilesAllowedCheckbox) - .addContainerGap(160, Short.MAX_VALUE)) + .addContainerGap(60, Short.MAX_VALUE)) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java index 4b7703dbd2..f6fc2292ae 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -40,6 +40,7 @@ import java.util.logging.Level; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -102,8 +103,12 @@ public final class ExifParserFileIngestModule implements FileIngestModule { @Override public ProcessResult process(AbstractFile content) { - blackboard = Case.getCurrentCase().getServices().getBlackboard(); - + try { + blackboard = Case.getOpenCase().getServices().getBlackboard(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS + return ProcessResult.ERROR; + } //skip unalloc if ((content.getType().equals(TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) || (content.getType().equals(TSK_DB_FILES_TYPE_ENUM.SLACK)))) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchIngestModule.java index 672bf83d97..1d33730e20 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,7 @@ import java.util.logging.Level; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -108,7 +109,12 @@ public class FileExtMismatchIngestModule implements FileIngestModule { @Override @Messages({"FileExtMismatchIngestModule.indexError.message=Failed to index file extension mismatch artifact for keyword search."}) public ProcessResult process(AbstractFile abstractFile) { - blackboard = Case.getCurrentCase().getServices().getBlackboard(); + try { + blackboard = Case.getOpenCase().getServices().getBlackboard(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Exception while getting open case.", ex); //NON-NLS + return ProcessResult.ERROR; + } if (this.settings.skipKnownFiles() && (abstractFile.getKnown() == FileKnown.KNOWN)) { return ProcessResult.OK; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java index be0bcdfbb3..f9cb21434c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.FileIngestModule; @@ -155,9 +156,11 @@ public class FileTypeIdIngestModule implements FileIngestModule { attributes.add(ruleNameAttribute); artifact.addAttributes(attributes); try { - Case.getCurrentCase().getServices().getBlackboard().indexArtifact(artifact); + Case.getOpenCase().getServices().getBlackboard().indexArtifact(artifact); } catch (Blackboard.BlackboardException ex) { logger.log(Level.SEVERE, String.format("Unable to index TSK_INTERESTING_FILE_HIT blackboard artifact %d (file obj_id=%d)", artifact.getArtifactID(), file.getId()), ex); //NON-NLS + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS } } catch (TskCoreException ex) { logger.log(Level.SEVERE, String.format("Unable to create TSK_INTERESTING_FILE_HIT artifact for file (obj_id=%d)", file.getId()), ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 022cda8a9c..92e2989e64 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -29,6 +29,7 @@ import java.util.logging.Level; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -61,7 +62,7 @@ public class HashDbIngestModule implements FileIngestModule { private static final Logger logger = Logger.getLogger(HashDbIngestModule.class.getName()); private static final int MAX_COMMENT_SIZE = 500; private final IngestServices services = IngestServices.getInstance(); - private final SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); + private final SleuthkitCase skCase; private final HashDbManager hashDbManager = HashDbManager.getInstance(); private final HashLookupModuleSettings settings; private List knownBadHashSets = new ArrayList<>(); @@ -87,8 +88,9 @@ public class HashDbIngestModule implements FileIngestModule { return totals; } - HashDbIngestModule(HashLookupModuleSettings settings) { + HashDbIngestModule(HashLookupModuleSettings settings) throws NoCurrentCaseException { this.settings = settings; + skCase = Case.getOpenCase().getSleuthkitCase(); } @Override @@ -144,7 +146,12 @@ public class HashDbIngestModule implements FileIngestModule { @Override public ProcessResult process(AbstractFile file) { - blackboard = Case.getCurrentCase().getServices().getBlackboard(); + try { + blackboard = Case.getOpenCase().getServices().getBlackboard(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return ProcessResult.ERROR; + } // Skip unallocated space files. if ((file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) || diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbSearchAction.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbSearchAction.java index 61c2fe699e..7d4ec611b6 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbSearchAction.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbSearchAction.java @@ -24,6 +24,7 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.directorytree.HashSearchProvider; import org.sleuthkit.datamodel.AbstractFile; @@ -118,8 +119,12 @@ public class HashDbSearchAction extends CallableSystemAction implements HashSear * performAction. */ @Override + @NbBundle.Messages ({ + "HashDbSearchAction.noOpenCase.errMsg=No open case available." + }) public void performAction() { // Make sure at least 1 file has an md5 hash + try { if (file != null && HashDbSearcher.countFilesMd5Hashed() > 0) { doSearch(); } else { @@ -129,6 +134,12 @@ public class HashDbSearchAction extends CallableSystemAction implements HashSear NbBundle.getMessage(this.getClass(), "HashDbSearchAction.dlgMsg.title"), JOptionPane.ERROR_MESSAGE); } + } catch (NoCurrentCaseException ex) { + JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), + Bundle.HashDbSearchAction_noOpenCase_errMsg(), + NbBundle.getMessage(this.getClass(), "HashDbSearchAction.dlgMsg.title"), + JOptionPane.ERROR_MESSAGE); + } } private void doSearch() { diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbSearchPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbSearchPanel.java index a85e9a5074..a75b47646e 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbSearchPanel.java @@ -32,6 +32,7 @@ import javax.swing.table.DefaultTableModel; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.PlainDocument; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.ingest.IngestManager; /** @@ -292,16 +293,27 @@ class HashDbSearchPanel extends javax.swing.JPanel implements ActionListener { * Search through all tsk_files to find ones with the same hashes as the * hashes given. */ + @NbBundle.Messages ({ + "HashDbSearchPanel.noOpenCase.errMsg=No open case available." + }) boolean search() { // Check if any hashed have been entered if (hashTable.getRowCount() != 0) { // Make sure at least 1 file has an md5 hash - if (HashDbSearcher.countFilesMd5Hashed() > 0) { - return doSearch(); - } else { + try { + if (HashDbSearcher.countFilesMd5Hashed() > 0) { + return doSearch(); + } else { + JOptionPane.showMessageDialog(this, + NbBundle.getMessage(this.getClass(), + "HashDbSearchPanel.noFilesHaveMD5HashMsg"), + NbBundle.getMessage(this.getClass(), "HashDbSearchPanel.dlgMsg.title"), + JOptionPane.ERROR_MESSAGE); + return false; + } + } catch (NoCurrentCaseException ex) { JOptionPane.showMessageDialog(this, - NbBundle.getMessage(this.getClass(), - "HashDbSearchPanel.noFilesHaveMD5HashMsg"), + Bundle.HashDbSearchPanel_noOpenCase_errMsg(), NbBundle.getMessage(this.getClass(), "HashDbSearchPanel.dlgMsg.title"), JOptionPane.ERROR_MESSAGE); return false; diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbSearcher.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbSearcher.java index 628f99f78e..213400925f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbSearcher.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbSearcher.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,9 +22,12 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.logging.Level; import javax.swing.SwingWorker; import org.netbeans.api.progress.ProgressHandle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.FsContent; import org.sleuthkit.datamodel.SleuthkitCase; @@ -34,7 +37,7 @@ import org.sleuthkit.datamodel.SleuthkitCase; * the same content. */ class HashDbSearcher { - + private static final Logger logger = Logger.getLogger(HashDbSearcher.class.getName()); /** * Given a string hash value, find all files with that hash. * @@ -42,8 +45,8 @@ class HashDbSearcher { * * @return a List of all FsContent with the given hash */ - static List findFilesByMd5(String md5Hash) { - final Case currentCase = Case.getCurrentCase(); + static List findFilesByMd5(String md5Hash) throws NoCurrentCaseException { + final Case currentCase = Case.getOpenCase(); final SleuthkitCase skCase = currentCase.getSleuthkitCase(); return skCase.findFilesByMd5(md5Hash); } @@ -56,7 +59,7 @@ class HashDbSearcher { * * @return a Map of md5 hashes mapped to the list of files hit */ - static Map> findFilesBymd5(List md5Hash) { + static Map> findFilesBymd5(List md5Hash) throws NoCurrentCaseException { Map> map = new LinkedHashMap>(); for (String md5 : md5Hash) { List files = findFilesByMd5(md5); @@ -69,7 +72,7 @@ class HashDbSearcher { // Same as above, but with a given ProgressHandle to accumulate and StringWorker to check if cancelled - static Map> findFilesBymd5(List md5Hash, ProgressHandle progress, SwingWorker worker) { + static Map> findFilesBymd5(List md5Hash, ProgressHandle progress, SwingWorker worker) throws NoCurrentCaseException { Map> map = new LinkedHashMap>(); if (!worker.isCancelled()) { progress.switchToDeterminate(md5Hash.size()); @@ -101,9 +104,14 @@ class HashDbSearcher { */ static List findFiles(FsContent file) { String md5; - if ((md5 = file.getMd5Hash()) != null) { - return findFilesByMd5(md5); - } else { + try { + if ((md5 = file.getMd5Hash()) != null) { + return findFilesByMd5(md5); + } else { + return Collections.emptyList(); + } + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); return Collections.emptyList(); } } @@ -114,8 +122,8 @@ class HashDbSearcher { * * @return true if the search feature is ready. */ - static boolean allFilesMd5Hashed() { - final Case currentCase = Case.getCurrentCase(); + static boolean allFilesMd5Hashed() throws NoCurrentCaseException { + final Case currentCase = Case.getOpenCase(); final SleuthkitCase skCase = currentCase.getSleuthkitCase(); return skCase.allFilesMd5Hashed(); } @@ -125,8 +133,8 @@ class HashDbSearcher { * * @return the number of files with an MD5 */ - static int countFilesMd5Hashed() { - final Case currentCase = Case.getCurrentCase(); + static int countFilesMd5Hashed() throws NoCurrentCaseException { + final Case currentCase = Case.getOpenCase(); final SleuthkitCase skCase = currentCase.getSleuthkitCase(); return skCase.countFilesMd5Hashed(); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java index 2fb515832b..257f90ad2f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.List; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.FileIngestModule; @@ -105,6 +106,10 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { throw new IllegalArgumentException( NbBundle.getMessage(this.getClass(), "HashLookupModuleFactory.createFileIngestModule.exception.msg")); } - return new HashDbIngestModule((HashLookupModuleSettings) settings); + try { + return new HashDbIngestModule((HashLookupModuleSettings) settings); + } catch (NoCurrentCaseException ex) { + throw new IllegalArgumentException("Exception while getting open case.", ex); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/iOS/CallLogAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/iOS/CallLogAnalyzer.java index 20b0954fd3..976f8aefac 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/iOS/CallLogAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/iOS/CallLogAnalyzer.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.logging.Level; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -62,17 +63,24 @@ final class CallLogAnalyzer { * @param context The ingest job context. */ public void findCallLogs(IngestJobContext context) { - blackboard = Case.getCurrentCase().getServices().getBlackboard(); + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return; + } + blackboard = openCase.getServices().getBlackboard(); List absFiles; try { - SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); + SleuthkitCase skCase = openCase.getSleuthkitCase(); absFiles = skCase.findAllFilesWhere("name ='contacts2.db' OR name ='contacts.db'"); //NON-NLS //get exact file names if (absFiles.isEmpty()) { return; } for (AbstractFile file : absFiles) { try { - jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), file.getName().replaceAll("[<>%|\"/:*\\\\]", "")); + jFile = new java.io.File(Case.getOpenCase().getTempDirectory(), file.getName().replaceAll("[<>%|\"/:*\\\\]", "")); dbPath = jFile.toString(); //path of file as string fileId = file.getId(); ContentUtils.writeToFile(file, jFile, context::dataSourceIngestIsCancelled); @@ -107,7 +115,13 @@ final class CallLogAnalyzer { logger.log(Level.SEVERE, "Error opening database", e); //NON-NLS } - Case currentCase = Case.getCurrentCase(); + Case currentCase; + try { + currentCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return; + } SleuthkitCase skCase = currentCase.getSleuthkitCase(); try { AbstractFile file = skCase.getAbstractFileById(fileId); diff --git a/Core/src/org/sleuthkit/autopsy/modules/iOS/ContactAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/iOS/ContactAnalyzer.java index 25020aff9c..9346b10acb 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/iOS/ContactAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/iOS/ContactAnalyzer.java @@ -34,6 +34,7 @@ import java.util.List; import java.util.logging.Level; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -68,18 +69,25 @@ final class ContactAnalyzer { * @param context The ingest job context. */ public void findContacts(IngestJobContext context) { - - blackboard = Case.getCurrentCase().getServices().getBlackboard(); + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return; + } + + blackboard = openCase.getServices().getBlackboard(); List absFiles; try { - SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); + SleuthkitCase skCase = openCase.getSleuthkitCase(); absFiles = skCase.findAllFilesWhere("LOWER(name) LIKE LOWER('%call_history%') "); //NON-NLS //get exact file names if (absFiles.isEmpty()) { return; } for (AbstractFile file : absFiles) { try { - jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), file.getName().replaceAll("[<>%|\"/:*\\\\]", "")); + jFile = new java.io.File(openCase.getTempDirectory(), file.getName().replaceAll("[<>%|\"/:*\\\\]", "")); dbPath = jFile.toString(); //path of file as string fileId = file.getId(); ContentUtils.writeToFile(file, jFile, context::dataSourceIngestIsCancelled); @@ -106,6 +114,13 @@ final class ContactAnalyzer { if (DatabasePath == null || DatabasePath.isEmpty()) { return; } + Case currentCase; + try { + currentCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return; + } try { Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS @@ -114,7 +129,6 @@ final class ContactAnalyzer { logger.log(Level.SEVERE, "Error opening database", e); //NON-NLS } - Case currentCase = Case.getCurrentCase(); SleuthkitCase skCase = currentCase.getSleuthkitCase(); try { AbstractFile file = skCase.getAbstractFileById(fileId); diff --git a/Core/src/org/sleuthkit/autopsy/modules/iOS/TextMessageAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/iOS/TextMessageAnalyzer.java index 4e6f1c2037..dd3cc14d5b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/iOS/TextMessageAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/iOS/TextMessageAnalyzer.java @@ -30,6 +30,7 @@ import java.util.logging.Level; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -65,16 +66,23 @@ class TextMessageAnalyzer { * @param context The ingest job context. */ void findTexts(IngestJobContext context) { - blackboard = Case.getCurrentCase().getServices().getBlackboard(); + Case openCase; try { - SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return; + } + blackboard = openCase.getServices().getBlackboard(); + try { + SleuthkitCase skCase = openCase.getSleuthkitCase(); absFiles = skCase.findAllFilesWhere("name ='mmssms.db'"); //NON-NLS //get exact file name if (absFiles.isEmpty()) { return; } for (AbstractFile file : absFiles) { try { - jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), file.getName().replaceAll("[<>%|\"/:*\\\\]", "")); + jFile = new java.io.File(Case.getOpenCase().getTempDirectory(), file.getName().replaceAll("[<>%|\"/:*\\\\]", "")); dbPath = jFile.toString(); //path of file as string fileId = file.getId(); ContentUtils.writeToFile(file, jFile, context::dataSourceIngestIsCancelled); @@ -102,6 +110,13 @@ class TextMessageAnalyzer { if (DatabasePath == null || DatabasePath.isEmpty()) { return; } + Case currentCase; + try { + currentCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return; + } try { Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS @@ -110,7 +125,6 @@ class TextMessageAnalyzer { logger.log(Level.SEVERE, "Error opening database", e); //NON-NLS } - Case currentCase = Case.getCurrentCase(); SleuthkitCase skCase = currentCase.getSleuthkitCase(); try { AbstractFile file = skCase.getAbstractFileById(fileId); diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestModule.java index 88ee3ae1b7..8ae1db3dc5 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,6 +28,7 @@ import java.util.logging.Level; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -105,8 +106,12 @@ final class FilesIdentifierIngestModule implements FileIngestModule { @Override @Messages({"FilesIdentifierIngestModule.indexError.message=Failed to index interesting file hit artifact for keyword search."}) public ProcessResult process(AbstractFile file) { - blackboard = Case.getCurrentCase().getServices().getBlackboard(); - + try { + blackboard = Case.getOpenCase().getServices().getBlackboard(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return ProcessResult.ERROR; + } // Skip slack space files. if (file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)) { return ProcessResult.OK; diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java index 3a3e9b2360..0dbb0300f2 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java @@ -98,7 +98,7 @@ public final class FilesSet implements Serializable { * * @return True if known files are ignored, false otherwise. */ - boolean ignoresKnownFiles() { + public boolean ignoresKnownFiles() { return this.ignoreKnownFiles; } @@ -117,7 +117,7 @@ public final class FilesSet implements Serializable { * * @return A map of set membership rule names to rules, possibly empty. */ - Map getRules() { + public Map getRules() { return new HashMap<>(this.rules); } @@ -160,7 +160,7 @@ public final class FilesSet implements Serializable { * A set membership rule for an interesting files set. The immutability of a * rule object allows it to be safely published to multiple threads. */ - static class Rule implements Serializable { + public final static class Rule implements Serializable { private static final long serialVersionUID = 1L; private final String uuid; @@ -185,7 +185,7 @@ public final class FilesSet implements Serializable { * @param dateCondition A file date created or modified condition, * may be null */ - Rule(String ruleName, FileNameCondition fileNameCondition, MetaTypeCondition metaTypeCondition, ParentPathCondition pathCondition, MimeTypeCondition mimeTypeCondition, FileSizeCondition fileSizeCondition, DateCondition dateCondition) { + public Rule(String ruleName, FileNameCondition fileNameCondition, MetaTypeCondition metaTypeCondition, ParentPathCondition pathCondition, MimeTypeCondition mimeTypeCondition, FileSizeCondition fileSizeCondition, DateCondition dateCondition) { // since ruleName is optional, ruleUUID can be used to uniquely identify a rule. this.uuid = UUID.randomUUID().toString(); if (metaTypeCondition == null) { @@ -231,7 +231,7 @@ public final class FilesSet implements Serializable { * * @return A name string. */ - String getName() { + public String getName() { return ruleName; } @@ -240,7 +240,7 @@ public final class FilesSet implements Serializable { * * @return A file name condition. Can be null. */ - FileNameCondition getFileNameCondition() { + public FileNameCondition getFileNameCondition() { return this.fileNameCondition; } @@ -249,7 +249,7 @@ public final class FilesSet implements Serializable { * * @return A meta-type condition. Can be null. */ - MetaTypeCondition getMetaTypeCondition() { + public MetaTypeCondition getMetaTypeCondition() { return this.metaTypeCondition; } @@ -258,11 +258,11 @@ public final class FilesSet implements Serializable { * * @return A path condition, may be null. */ - ParentPathCondition getPathCondition() { + public ParentPathCondition getPathCondition() { return this.pathCondition; } - DateCondition getDateCondition() { + public DateCondition getDateCondition() { return this.dateCondition; } @@ -273,7 +273,7 @@ public final class FilesSet implements Serializable { * * @return True if the rule is satisfied, false otherwise. */ - boolean isSatisfied(AbstractFile file) { + public boolean isSatisfied(AbstractFile file) { for (FileAttributeCondition condition : conditions) { if (!condition.passes(file)) { return false; @@ -317,14 +317,14 @@ public final class FilesSet implements Serializable { /** * @return the mime type condition. Can be null. */ - MimeTypeCondition getMimeTypeCondition() { + public MimeTypeCondition getMimeTypeCondition() { return mimeTypeCondition; } /** * @return the file size condition. Can be null. */ - FileSizeCondition getFileSizeCondition() { + public FileSizeCondition getFileSizeCondition() { return fileSizeCondition; } @@ -347,7 +347,7 @@ public final class FilesSet implements Serializable { /** * A class for checking files based upon their MIME types. */ - static final class MimeTypeCondition implements FileAttributeCondition { + public static final class MimeTypeCondition implements FileAttributeCondition { private static final long serialVersionUID = 1L; private final String mimeType; @@ -357,7 +357,7 @@ public final class FilesSet implements Serializable { * * @param mimeType The mime type to condition for */ - MimeTypeCondition(String mimeType) { + public MimeTypeCondition(String mimeType) { this.mimeType = mimeType; } @@ -371,7 +371,7 @@ public final class FilesSet implements Serializable { * * @return the mime type */ - String getMimeType() { + public String getMimeType() { return this.mimeType; } @@ -381,14 +381,14 @@ public final class FilesSet implements Serializable { * A class for checking whether a file's size is within the * specifications given (i.e. < N Bytes). */ - static final class FileSizeCondition implements FileAttributeCondition { + public static final class FileSizeCondition implements FileAttributeCondition { private static final long serialVersionUID = 1L; /** * Represents a comparison item for file size */ - static enum COMPARATOR { + public static enum COMPARATOR { LESS_THAN("<"), LESS_THAN_EQUAL("≤"), @@ -398,23 +398,27 @@ public final class FilesSet implements Serializable { private String symbol; - COMPARATOR(String symbol) { + private COMPARATOR(String symbol) { this.symbol = symbol; } public static COMPARATOR fromSymbol(String symbol) { - if (symbol.equals("<=") || symbol.equals("≤")) { - return LESS_THAN_EQUAL; - } else if (symbol.equals("<")) { - return LESS_THAN; - } else if (symbol.equals("==") || symbol.equals("=")) { - return EQUAL; - } else if (symbol.equals(">")) { - return GREATER_THAN; - } else if (symbol.equals(">=") || symbol.equals("≥")) { - return GREATER_THAN_EQUAL; - } else { - throw new IllegalArgumentException("Invalid symbol"); + switch (symbol) { + case "<=": + case "≤": + return LESS_THAN_EQUAL; + case "<": + return LESS_THAN; + case "==": + case "=": + return EQUAL; + case ">": + return GREATER_THAN; + case ">=": + case "≥": + return GREATER_THAN_EQUAL; + default: + throw new IllegalArgumentException("Invalid symbol"); } } @@ -429,7 +433,7 @@ public final class FilesSet implements Serializable { /** * Represents the units of size */ - static enum SIZE_UNIT { + public static enum SIZE_UNIT { BYTE(1, "Bytes"), KILOBYTE(1024, "Kilobytes"), @@ -467,7 +471,7 @@ public final class FilesSet implements Serializable { private final SIZE_UNIT unit; private final int sizeValue; - FileSizeCondition(COMPARATOR comparator, SIZE_UNIT unit, int sizeValue) { + public FileSizeCondition(COMPARATOR comparator, SIZE_UNIT unit, int sizeValue) { this.comparator = comparator; this.unit = unit; this.sizeValue = sizeValue; @@ -478,7 +482,7 @@ public final class FilesSet implements Serializable { * * @return the comparator */ - COMPARATOR getComparator() { + public COMPARATOR getComparator() { return comparator; } @@ -487,7 +491,7 @@ public final class FilesSet implements Serializable { * * @return the unit */ - SIZE_UNIT getUnit() { + public SIZE_UNIT getUnit() { return unit; } @@ -496,7 +500,7 @@ public final class FilesSet implements Serializable { * * @return the size value */ - int getSizeValue() { + public int getSizeValue() { return sizeValue; } @@ -526,11 +530,11 @@ public final class FilesSet implements Serializable { * rule. The immutability of a meta-type condition object allows it to * be safely published to multiple threads. */ - static final class MetaTypeCondition implements FileAttributeCondition { + public static final class MetaTypeCondition implements FileAttributeCondition { private static final long serialVersionUID = 1L; - enum Type { + public enum Type { FILES, DIRECTORIES, @@ -545,7 +549,7 @@ public final class FilesSet implements Serializable { * * @param metaType The meta-type to match, must. */ - MetaTypeCondition(Type type) { + public MetaTypeCondition(Type type) { this.type = type; } @@ -573,7 +577,7 @@ public final class FilesSet implements Serializable { * * @return A member of the MetaTypeCondition.Type enumeration. */ - Type getMetaType() { + public Type getMetaType() { return this.type; } } @@ -616,6 +620,7 @@ public final class FilesSet implements Serializable { */ private static abstract class AbstractTextCondition implements TextCondition { + private static final long serialVersionUID = 1L; private final TextMatcher textMatcher; /** @@ -684,7 +689,7 @@ public final class FilesSet implements Serializable { * The immutability of a path condition object allows it to be safely * published to multiple threads. */ - static final class ParentPathCondition extends AbstractTextCondition { + public static final class ParentPathCondition extends AbstractTextCondition { private static final long serialVersionUID = 1L; @@ -693,7 +698,7 @@ public final class FilesSet implements Serializable { * * @param path The path to be matched. */ - ParentPathCondition(String path) { + public ParentPathCondition(String path) { super(path, true); } @@ -702,7 +707,7 @@ public final class FilesSet implements Serializable { * * @param path The path regular expression to be matched. */ - ParentPathCondition(Pattern path) { + public ParentPathCondition(Pattern path) { super(path); } @@ -726,7 +731,7 @@ public final class FilesSet implements Serializable { * The immutability of a file name condition object allows it to be * safely published to multiple threads. */ - static final class FullNameCondition extends AbstractTextCondition implements FileNameCondition { + public static final class FullNameCondition extends AbstractTextCondition implements FileNameCondition { private static final long serialVersionUID = 1L; @@ -735,7 +740,7 @@ public final class FilesSet implements Serializable { * * @param name The file name to be matched. */ - FullNameCondition(String name) { + public FullNameCondition(String name) { super(name, false); } @@ -744,7 +749,7 @@ public final class FilesSet implements Serializable { * * @param name The file name regular expression to be matched. */ - FullNameCondition(Pattern name) { + public FullNameCondition(Pattern name) { super(name); } @@ -759,8 +764,9 @@ public final class FilesSet implements Serializable { * A class for checking whether a file's creation or modification * occured in a specific range of time */ - static final class DateCondition implements FileAttributeCondition { + public static final class DateCondition implements FileAttributeCondition { + private static final long serialVersionUID = 1L; private final static long SECS_PER_DAY = 60 * 60 * 24; private int daysIncluded; @@ -771,7 +777,7 @@ public final class FilesSet implements Serializable { * @param days - files created or modified more recently than this * number of days will pass */ - DateCondition(int days) { + public DateCondition(int days) { daysIncluded = days; } @@ -780,17 +786,14 @@ public final class FilesSet implements Serializable { * * @return integer value of the number days which will pass */ - int getDaysIncluded() { + public int getDaysIncluded() { return daysIncluded; } @Override public boolean passes(AbstractFile file) { long dateThreshold = System.currentTimeMillis() / 1000 - daysIncluded * SECS_PER_DAY; - if (file.getCrtime() > dateThreshold || file.getMtime() > dateThreshold) { - return true; - } - return false; + return file.getCrtime() > dateThreshold || file.getMtime() > dateThreshold; } } @@ -800,7 +803,7 @@ public final class FilesSet implements Serializable { * membership rule. The immutability of a file name extension condition * object allows it to be safely published to multiple threads. */ - static final class ExtensionCondition extends AbstractTextCondition implements FileNameCondition { + public static final class ExtensionCondition extends AbstractTextCondition implements FileNameCondition { private static final long serialVersionUID = 1L; @@ -809,7 +812,7 @@ public final class FilesSet implements Serializable { * * @param extension The file name extension to be matched. */ - ExtensionCondition(String extension) { + public ExtensionCondition(String extension) { // If there is a leading ".", strip it since // AbstractFile.getFileNameExtension() returns just the // extension chars and not the dot. @@ -822,7 +825,7 @@ public final class FilesSet implements Serializable { * @param extension The file name extension regular expression to be * matched. */ - ExtensionCondition(Pattern extension) { + public ExtensionCondition(Pattern extension) { super(extension); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties index 295f82f1cb..f4089caff7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties @@ -17,3 +17,5 @@ PhotoRecIngestModule.cancelledByUser=PhotoRec cancelled by user. PhotoRecIngestModule.error.exitValue=PhotoRec carver returned error exit value \= {0} when scanning {1} PhotoRecIngestModule.error.msg=Error processing {0} with PhotoRec carver. PhotoRecIngestModule.complete.numberOfErrors=Number of Errors while Carving\: +PhotoRecCarverIngestJobSettingsPanel.detectionSettingsLabel.text=PhotoRec Settings +PhotoRecCarverIngestJobSettingsPanel.keepCorruptedFilesCheckbox.text=Keep corrupted files diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java index 1f0bafb892..446da55940 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java @@ -39,6 +39,7 @@ import java.util.logging.Level; import org.openide.modules.InstalledFileLocator; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.ExecUtil; import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; @@ -77,6 +78,8 @@ import org.sleuthkit.datamodel.TskData; }) final class PhotoRecCarverFileIngestModule implements FileIngestModule { + static final boolean DEFAULT_CONFIG_KEEP_CORRUPTED_FILES = false; + private static final String PHOTOREC_DIRECTORY = "photorec_exec"; //NON-NLS private static final String PHOTOREC_EXECUTABLE = "photorec_win.exe"; //NON-NLS private static final String PHOTOREC_LINUX_EXECUTABLE = "photorec"; @@ -94,15 +97,24 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { private Path rootOutputDirPath; private File executableFile; private IngestServices services; - private UNCPathUtilities uncPathUtilities = new UNCPathUtilities(); + private final UNCPathUtilities uncPathUtilities = new UNCPathUtilities(); private long jobId; + + private final boolean keepCorruptedFiles; private static class IngestJobTotals { - - private AtomicLong totalItemsRecovered = new AtomicLong(0); - private AtomicLong totalItemsWithErrors = new AtomicLong(0); - private AtomicLong totalWritetime = new AtomicLong(0); - private AtomicLong totalParsetime = new AtomicLong(0); + private final AtomicLong totalItemsRecovered = new AtomicLong(0); + private final AtomicLong totalItemsWithErrors = new AtomicLong(0); + private final AtomicLong totalWritetime = new AtomicLong(0); + private final AtomicLong totalParsetime = new AtomicLong(0); + } + /** + * Create a PhotoRec Carver ingest module instance. + * + * @param settings Ingest job settings used to configure the module. + */ + PhotoRecCarverFileIngestModule(PhotoRecCarverIngestJobSettings settings) { + keepCorruptedFiles = settings.isKeepCorruptedFiles(); } private static synchronized IngestJobTotals getTotalsForIngestJobs(long ingestJobId) { @@ -228,8 +240,12 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { "/d", // NON-NLS outputDirPath.toAbsolutePath().toString() + File.separator + PHOTOREC_RESULTS_BASE, "/cmd", // NON-NLS - tempFilePath.toFile().toString(), - "search"); // NON-NLS + tempFilePath.toFile().toString()); + if (keepCorruptedFiles) { + processAndSettings.command().add("options,keep_corrupted_file,search"); // NON-NLS + } else { + processAndSettings.command().add("search"); // NON-NLS + } // Add environment variable to force PhotoRec to run with the same permissions Autopsy uses processAndSettings.environment().put("__COMPAT_LAYER", "RunAsInvoker"); //NON-NLS @@ -409,7 +425,12 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { * @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException */ synchronized Path createModuleOutputDirectoryForCase() throws IngestModule.IngestModuleException { - Path path = Paths.get(Case.getCurrentCase().getModuleDirectory(), PhotoRecCarverIngestModuleFactory.getModuleName()); + Path path; + try { + path = Paths.get(Case.getOpenCase().getModuleDirectory(), PhotoRecCarverIngestModuleFactory.getModuleName()); + } catch (NoCurrentCaseException ex) { + throw new IngestModule.IngestModuleException(Bundle.cannotCreateOutputDir_message(ex.getLocalizedMessage()), ex); + } try { Files.createDirectory(path); if (UNCPathUtilities.isUNC(path)) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestJobSettings.java new file mode 100755 index 0000000000..93de74f1d6 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestJobSettings.java @@ -0,0 +1,70 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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.modules.photoreccarver; + +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; + +/** + * Ingest job settings for the PhotoRec Carver module. + */ +final class PhotoRecCarverIngestJobSettings implements IngestModuleIngestJobSettings { + + private static final long serialVersionUID = 1L; + + private boolean keepCorruptedFiles; + + /** + * Instantiate the ingest job settings with default values. + */ + PhotoRecCarverIngestJobSettings() { + this.keepCorruptedFiles = PhotoRecCarverFileIngestModule.DEFAULT_CONFIG_KEEP_CORRUPTED_FILES; + } + + /** + * Instantiate the ingest job settings. + * + * @param keepCorruptedFiles Keep corrupted files. + */ + PhotoRecCarverIngestJobSettings(boolean keepCorruptedFiles) { + this.keepCorruptedFiles = keepCorruptedFiles; + } + + @Override + public long getVersionNumber() { + return serialVersionUID; + } + + /** + * Are corrupted files being kept? + * + * @return True if keeping corrupted files; otherwise false. + */ + boolean isKeepCorruptedFiles() { + return keepCorruptedFiles; + } + + /** + * Keep or disgard corrupted files. + * + * @param keepCorruptedFiles Are corrupted files being kept? + */ + void setKeepCorruptedFiles(boolean keepCorruptedFiles) { + this.keepCorruptedFiles = keepCorruptedFiles; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestJobSettingsPanel.form new file mode 100755 index 0000000000..2fe8e89dba --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestJobSettingsPanel.form @@ -0,0 +1,63 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestJobSettingsPanel.java new file mode 100755 index 0000000000..9af6902a2d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestJobSettingsPanel.java @@ -0,0 +1,99 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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.modules.photoreccarver; + +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; + +/** + * Ingest job settings panel for the Encryption Detection module. + */ +final class PhotoRecCarverIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPanel { + + /** + * Instantiate the ingest job settings panel. + * + * @param settings The ingest job settings. + */ + public PhotoRecCarverIngestJobSettingsPanel(PhotoRecCarverIngestJobSettings settings) { + initComponents(); + customizeComponents(settings); + } + + /** + * Update components with values from the ingest job settings. + * + * @param settings The ingest job settings. + */ + private void customizeComponents(PhotoRecCarverIngestJobSettings settings) { + keepCorruptedFilesCheckbox.setSelected(settings.isKeepCorruptedFiles()); + } + + @Override + public IngestModuleIngestJobSettings getSettings() { + return new PhotoRecCarverIngestJobSettings( + keepCorruptedFilesCheckbox.isSelected()); + } + + /** + * 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") + // //GEN-BEGIN:initComponents + private void initComponents() { + + keepCorruptedFilesCheckbox = new javax.swing.JCheckBox(); + detectionSettingsLabel = new javax.swing.JLabel(); + + org.openide.awt.Mnemonics.setLocalizedText(keepCorruptedFilesCheckbox, org.openide.util.NbBundle.getMessage(PhotoRecCarverIngestJobSettingsPanel.class, "PhotoRecCarverIngestJobSettingsPanel.keepCorruptedFilesCheckbox.text")); // NOI18N + + detectionSettingsLabel.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(detectionSettingsLabel, org.openide.util.NbBundle.getMessage(PhotoRecCarverIngestJobSettingsPanel.class, "PhotoRecCarverIngestJobSettingsPanel.detectionSettingsLabel.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(keepCorruptedFilesCheckbox)) + .addComponent(detectionSettingsLabel)) + .addContainerGap(159, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(detectionSettingsLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(keepCorruptedFilesCheckbox) + .addContainerGap(145, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel detectionSettingsLabel; + private javax.swing.JCheckBox keepCorruptedFilesCheckbox; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestModuleFactory.java index 0898f20928..47658b55e0 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestModuleFactory.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,6 +24,7 @@ import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.IngestModuleFactory; import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; /** * A factory for creating instances of file ingest modules that carve @@ -32,7 +33,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; @ServiceProvider(service = IngestModuleFactory.class) public class PhotoRecCarverIngestModuleFactory extends IngestModuleFactoryAdapter { - private static final String VERSION = "7.0"; + private static final String VERSION = "7.0"; // Version should match the PhotoRec tool version. /** * Gets the ingest module name for use within this package. @@ -65,7 +66,22 @@ public class PhotoRecCarverIngestModuleFactory extends IngestModuleFactoryAdapte @Override public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) { - return new PhotoRecCarverFileIngestModule(); + return new PhotoRecCarverFileIngestModule((PhotoRecCarverIngestJobSettings) settings); + } + + @Override + public IngestModuleIngestJobSettings getDefaultIngestJobSettings() { + return new PhotoRecCarverIngestJobSettings(); + } + + @Override + public boolean hasIngestJobSettingsPanel() { + return true; + } + + @Override + public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) { + return new PhotoRecCarverIngestJobSettingsPanel((PhotoRecCarverIngestJobSettings) settings); } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverOutputParser.java b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverOutputParser.java index 01d19b84d1..6c1975f5a8 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverOutputParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverOutputParser.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,6 +29,7 @@ import java.util.List; import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -99,7 +100,7 @@ class PhotoRecCarverOutputParser { NodeList fileRanges; Element entry; Path filePath; - FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); + FileManager fileManager = Case.getOpenCase().getServices().getFileManager(); // create and initialize the list to put into the database List carvedFiles = new ArrayList<>(); @@ -156,7 +157,7 @@ class PhotoRecCarverOutputParser { } } return fileManager.addCarvedFiles(new CarvingResult(af, carvedFiles)); - } catch (NumberFormatException | TskCoreException ex) { + } catch (NumberFormatException | TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Error parsing PhotoRec output and inserting it into the database", ex); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAccountObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAccountObj.java index d2a6b19551..5174e479eb 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAccountObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAccountObj.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,6 +30,7 @@ import java.util.ArrayList; import org.mitre.cybox.objects.AccountObjectType; import org.mitre.cybox.objects.UserAccountObjectType; import org.mitre.cybox.objects.WindowsUserAccount; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** * @@ -104,7 +105,7 @@ class EvalAccountObj extends EvaluatableObject { try { List finalHits = new ArrayList(); - Case case1 = Case.getCurrentCase(); + Case case1 = Case.getOpenCase(); SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); List artList = sleuthkitCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_ACCOUNT); @@ -150,7 +151,7 @@ class EvalAccountObj extends EvaluatableObject { // Didn't find any matches return new ObservableResult(id, "AccountObject: No matches found for " + searchString, //NON-NLS spacing, ObservableResult.ObservableState.FALSE, null); - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { return new ObservableResult(id, "AccountObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS spacing, ObservableResult.ObservableState.INDETERMINATE, null); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAddressObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAddressObj.java index faaac1dc4e..4141ba874f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAddressObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAddressObj.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,6 +30,7 @@ import org.mitre.cybox.common_2.ConditionApplicationEnum; import org.mitre.cybox.common_2.ConditionTypeEnum; import org.mitre.cybox.objects.Address; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** * @@ -54,6 +55,14 @@ class EvalAddressObj extends EvaluatableObject { spacing, ObservableResult.ObservableState.INDETERMINATE, null); } + Case case1; + try { + case1 = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + return new ObservableResult(id, "Exception while getting open case.", //NON-NLS + spacing, ObservableResult.ObservableState.FALSE, null); + } + String origAddressStr = obj.getAddressValue().getValue().toString(); // For now, we don't support "NONE" because it honestly doesn't seem like it @@ -67,7 +76,6 @@ class EvalAddressObj extends EvaluatableObject { // Set warnings for any unsupported fields setUnsupportedFieldWarnings(); - Case case1 = Case.getCurrentCase(); SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); try { diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalDomainObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalDomainObj.java index 2dd6c7f680..d06c5a19e0 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalDomainObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalDomainObj.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,6 +27,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.SleuthkitCase; /** @@ -52,7 +53,14 @@ class EvalDomainObj extends EvaluatableObject { spacing, ObservableResult.ObservableState.INDETERMINATE, null); } - // Since we have single URL artifacts, ALL and NONE conditions probably don't make sense to test + Case case1; + try { + case1 = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + return new ObservableResult(id, "Exception while getting open case.", //NON-NLS + spacing, ObservableResult.ObservableState.FALSE, null); + } + // Since we have single URL artifacts, ALL and NONE conditions probably don't make sense to test if (!((obj.getValue().getApplyCondition() == null) || (obj.getValue().getApplyCondition() == ConditionApplicationEnum.ANY))) { return new ObservableResult(id, "DomainObject: Can not process apply condition " + obj.getValue().getApplyCondition().toString() //NON-NLS @@ -66,7 +74,6 @@ class EvalDomainObj extends EvaluatableObject { + " on DomainName - using substring comparison"); //NON-NLS } - Case case1 = Case.getCurrentCase(); SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); try { diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalFileObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalFileObj.java index 1d2925060e..e99f34fe06 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalFileObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalFileObj.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -41,6 +41,7 @@ import org.mitre.cybox.common_2.HashType; import org.mitre.cybox.common_2.DateTimeObjectPropertyType; import org.mitre.cybox.common_2.StringObjectPropertyType; import org.mitre.cybox.common_2.UnsignedLongObjectPropertyType; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** * @@ -59,7 +60,13 @@ class EvalFileObj extends EvaluatableObject { @SuppressWarnings("deprecation") public synchronized ObservableResult evaluate() { - Case case1 = Case.getCurrentCase(); + Case case1; + try { + case1 = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + return new ObservableResult(id, "Exception while getting open case.", //NON-NLS + spacing, ObservableResult.ObservableState.FALSE, null); + } SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); setWarnings(""); diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalNetworkShareObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalNetworkShareObj.java index 843f19c293..7c1379e75f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalNetworkShareObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalNetworkShareObj.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,6 +29,7 @@ import java.util.List; import org.mitre.cybox.common_2.ConditionApplicationEnum; import org.mitre.cybox.objects.WindowsNetworkShare; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** * @@ -88,7 +89,7 @@ class EvalNetworkShareObj extends EvaluatableObject { try { List finalHits = new ArrayList(); - Case case1 = Case.getCurrentCase(); + Case case1 = Case.getOpenCase(); SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); List artList = sleuthkitCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_REMOTE_DRIVE); @@ -128,7 +129,7 @@ class EvalNetworkShareObj extends EvaluatableObject { // Didn't find any matches return new ObservableResult(id, "NetworkObject: No matches found for " + searchString, //NON-NLS spacing, ObservableResult.ObservableState.FALSE, null); - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { return new ObservableResult(id, "NetworkObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS spacing, ObservableResult.ObservableState.INDETERMINATE, null); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalRegistryObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalRegistryObj.java index 53b8b2d1f2..6040ea66e5 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalRegistryObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalRegistryObj.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,6 +35,7 @@ import java.util.regex.Matcher; import org.mitre.cybox.objects.WindowsRegistryKey; import org.mitre.cybox.common_2.ConditionTypeEnum; import com.williballenthin.rejistry.*; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** * @@ -345,7 +346,12 @@ class EvalRegistryObj extends EvaluatableObject { List regFilesLocal = new ArrayList(); // Make the temp directory - String tmpDir = Case.getCurrentCase().getTempDirectory() + File.separator + "STIX"; //NON-NLS + String tmpDir; + try { + tmpDir = Case.getOpenCase().getTempDirectory() + File.separator + "STIX"; //NON-NLS + } catch (NoCurrentCaseException ex) { + throw new TskCoreException(ex.getLocalizedMessage()); + } File dir = new File(tmpDir); if (dir.exists() == false) { dir.mkdirs(); @@ -377,9 +383,15 @@ class EvalRegistryObj extends EvaluatableObject { */ private static List findRegistryFiles() throws TskCoreException { List registryFiles = new ArrayList(); - org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + throw new TskCoreException(ex.getLocalizedMessage()); + } + org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = openCase.getServices().getFileManager(); - for (Content ds : Case.getCurrentCase().getDataSources()) { + for (Content ds : openCase.getDataSources()) { // find the user-specific ntuser-dat files registryFiles.addAll(fileManager.findFiles(ds, "ntuser.dat")); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalSystemObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalSystemObj.java index 7280cad285..bcfc5bc88e 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalSystemObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalSystemObj.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,6 +31,7 @@ import java.util.ArrayList; import org.mitre.cybox.objects.SystemObjectType; import org.mitre.cybox.objects.WindowsSystem; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** * @@ -135,7 +136,7 @@ class EvalSystemObj extends EvaluatableObject { setUnsupportedFieldWarnings(); try { - Case case1 = Case.getCurrentCase(); + Case case1 = Case.getOpenCase(); SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); List osInfoList = OSUtility.getOSInfo(sleuthkitCase); @@ -217,7 +218,7 @@ class EvalSystemObj extends EvaluatableObject { return new ObservableResult(id, "SystemObject: No OS artifacts found", //NON-NLS spacing, ObservableResult.ObservableState.INDETERMINATE, null); } - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { return new ObservableResult(id, "SystemObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS spacing, ObservableResult.ObservableState.INDETERMINATE, null); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURIObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURIObj.java index c5e598b034..123468041d 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURIObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURIObj.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,6 +29,7 @@ import java.util.ArrayList; import org.mitre.cybox.common_2.ConditionApplicationEnum; import org.mitre.cybox.objects.URIObjectType; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** * @@ -52,6 +53,15 @@ class EvalURIObj extends EvaluatableObject { return new ObservableResult(id, "URIObject: No URI value field found", //NON-NLS spacing, ObservableResult.ObservableState.INDETERMINATE, null); } + + Case case1; + try { + case1 = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + return new ObservableResult(id, "Exception while getting open case: " + ex.getLocalizedMessage(), //NON-NLS + spacing, ObservableResult.ObservableState.FALSE, null); + } + String addressStr = obj.getValue().getValue().toString(); // Strip off http:// or https:// @@ -65,7 +75,6 @@ class EvalURIObj extends EvaluatableObject { + " on URI object", spacing, ObservableResult.ObservableState.INDETERMINATE, null); //NON-NLS } - Case case1 = Case.getCurrentCase(); SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); try { diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURLHistoryObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURLHistoryObj.java index f6a6b67075..5cfa2adcec 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURLHistoryObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURLHistoryObj.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,6 +30,7 @@ import java.util.ArrayList; import org.mitre.cybox.common_2.AnyURIObjectPropertyType; import org.mitre.cybox.objects.URLHistory; import org.mitre.cybox.objects.URLHistoryEntryType; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** * @@ -138,7 +139,7 @@ class EvalURLHistoryObj extends EvaluatableObject { } try { - Case case1 = Case.getCurrentCase(); + Case case1 = Case.getOpenCase(); SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); List artList = sleuthkitCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY); @@ -206,7 +207,7 @@ class EvalURLHistoryObj extends EvaluatableObject { } } - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { return new ObservableResult(id, "URLHistoryObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS spacing, ObservableResult.ObservableState.INDETERMINATE, null); } @@ -231,7 +232,7 @@ class EvalURLHistoryObj extends EvaluatableObject { // It doesn't seem too useful, but we can just search for the browser name // if there aren't any URL entries try { - Case case1 = Case.getCurrentCase(); + Case case1 = Case.getOpenCase(); SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); List artList = sleuthkitCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY); @@ -264,7 +265,7 @@ class EvalURLHistoryObj extends EvaluatableObject { // Didn't find any matches return new ObservableResult(id, "URLHistoryObject: No matches found for " + baseSearchString, //NON-NLS spacing, ObservableResult.ObservableState.FALSE, null); - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { return new ObservableResult(id, "URLHistoryObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS spacing, ObservableResult.ObservableState.INDETERMINATE, null); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvaluatableObject.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvaluatableObject.java index 6d0abbdcb8..5c3a4cc75a 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvaluatableObject.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvaluatableObject.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,6 +24,7 @@ import org.mitre.cybox.common_2.ConditionApplicationEnum; import org.mitre.cybox.common_2.ConditionTypeEnum; import org.mitre.cybox.common_2.StringObjectPropertyType; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; @@ -100,7 +101,7 @@ abstract class EvaluatableObject { List hits = null; try { - Case case1 = Case.getCurrentCase(); + Case case1 = Case.getOpenCase(); SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); String[] parts = item.getValue().toString().split("##comma##"); //NON-NLS @@ -143,7 +144,7 @@ abstract class EvaluatableObject { } else { throw new TskCoreException("Error: Can not apply NONE condition in search"); //NON-NLS } - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { addWarning(ex.getLocalizedMessage()); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java index 9d08bf7115..3f295b5cd7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java @@ -52,6 +52,7 @@ import org.mitre.stix.stix_1.STIXPackage; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ModuleSettings; @@ -185,7 +186,7 @@ public class STIXReportModule implements GeneralReportModule { // Set the progress bar to done. If any errors occurred along the way, modify // the "complete" message to indicate this. - Case.getCurrentCase().addReport(reportPath, Bundle.STIXReportModule_srcModuleName_text(), ""); + Case.getOpenCase().addReport(reportPath, Bundle.STIXReportModule_srcModuleName_text(), ""); if (hadErrors) { progressPanel.complete(ReportStatus.ERROR); progressPanel.updateStatusLabel( @@ -202,7 +203,7 @@ public class STIXReportModule implements GeneralReportModule { progressPanel.complete(ReportStatus.ERROR); progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.completedWithErrors")); - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Unable to add report to database.", ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/StixArtifactData.java b/Core/src/org/sleuthkit/autopsy/modules/stix/StixArtifactData.java index afc84d87aa..cf4c4a3aea 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/StixArtifactData.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/StixArtifactData.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,6 +23,7 @@ import java.util.Collection; import java.util.logging.Level; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -49,20 +50,28 @@ class StixArtifactData { } public StixArtifactData(long a_objId, String a_observableId, String a_objType) { - Case case1 = Case.getCurrentCase(); - SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); try { + Case case1 = Case.getOpenCase(); + SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); file = sleuthkitCase.getAbstractFileById(a_objId); - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { file = null; } observableId = a_observableId; objType = a_objType; } - @Messages({"StixArtifactData.indexError.message=Failed to index STIX interesting file hit artifact for keyword search."}) + @Messages({"StixArtifactData.indexError.message=Failed to index STIX interesting file hit artifact for keyword search.", + "StixArtifactData.noOpenCase.errMsg=No open case available."}) public void createArtifact(String a_title) throws TskCoreException { - Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard(); + Blackboard blackboard; + try { + blackboard = Case.getOpenCase().getServices().getBlackboard(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + MessageNotifyUtil.Notify.error(Bundle.StixArtifactData_noOpenCase_errMsg(), ex.getLocalizedMessage()); + return; + } String setName; if (a_title != null) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/vmextractor/VMExtractorIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/vmextractor/VMExtractorIngestModule.java index 3989c07879..a6d22b4d6b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/vmextractor/VMExtractorIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/vmextractor/VMExtractorIngestModule.java @@ -35,6 +35,7 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.GeneralFilter; import org.sleuthkit.autopsy.casemodule.ImageDSProcessor; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; import org.sleuthkit.autopsy.coreutils.Logger; @@ -73,13 +74,14 @@ final class VMExtractorIngestModule extends DataSourceIngestModuleAdapter { private final HashMap imageFolderToOutputFolder = new HashMap<>(); private int folderId = 0; - @Messages({"# {0} - data source name", "deviceIdQueryErrMsg=Data source {0} missing Device ID"}) + @Messages({"# {0} - data source name", "deviceIdQueryErrMsg=Data source {0} missing Device ID", + "VMExtractorIngestModule.noOpenCase.errMsg=No open case available."}) @Override public void startUp(IngestJobContext context) throws IngestModuleException { this.context = context; long dataSourceObjId = context.getDataSource().getId(); try { - Case currentCase = Case.getCurrentCase(); + Case currentCase = Case.getOpenCase(); SleuthkitCase caseDb = currentCase.getSleuthkitCase(); DataSource dataSource = caseDb.getDataSource(dataSourceObjId); parentDeviceId = dataSource.getDeviceId(); @@ -88,13 +90,15 @@ final class VMExtractorIngestModule extends DataSourceIngestModuleAdapter { String timeStamp = dateFormat.format(Calendar.getInstance().getTime()); String ingestJobOutputDirName = context.getDataSource().getName() + "_" + context.getDataSource().getId() + "_" + timeStamp; ingestJobOutputDirName = ingestJobOutputDirName.replace(':', '_'); - ingestJobOutputDir = Paths.get(Case.getCurrentCase().getModuleDirectory(), VMExtractorIngestModuleFactory.getModuleName(), ingestJobOutputDirName); + ingestJobOutputDir = Paths.get(currentCase.getModuleDirectory(), VMExtractorIngestModuleFactory.getModuleName(), ingestJobOutputDirName); // create module output folder to write extracted virtual machine files to Files.createDirectories(ingestJobOutputDir); } catch (IOException | SecurityException | UnsupportedOperationException ex) { throw new IngestModule.IngestModuleException(Bundle.VMExtractorIngestModule_cannotCreateOutputDir_message(ex.getLocalizedMessage()), ex); } catch (TskDataException | TskCoreException ex) { throw new IngestModule.IngestModuleException(Bundle.deviceIdQueryErrMsg(context.getDataSource().getName()), ex); + } catch (NoCurrentCaseException ex) { + throw new IngestModule.IngestModuleException(Bundle.VMExtractorIngestModule_noOpenCase_errMsg(), ex); } } @@ -117,6 +121,9 @@ final class VMExtractorIngestModule extends DataSourceIngestModuleAdapter { } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error querying case database", ex); //NON-NLS return ProcessResult.ERROR; + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return ProcessResult.ERROR; } if (vmFiles.isEmpty()) { @@ -198,6 +205,10 @@ final class VMExtractorIngestModule extends DataSourceIngestModuleAdapter { logger.log(Level.SEVERE, "Failed to ingest virtual machine file " + file + " in folder " + folder, ex); //NON-NLS MessageNotifyUtil.Notify.error(NbBundle.getMessage(this.getClass(), "VMExtractorIngestModule.msgNotify.failedIngestVM.title.txt"), NbBundle.getMessage(this.getClass(), "VMExtractorIngestModule.msgNotify.failedIngestVM.msg.txt", file)); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + MessageNotifyUtil.Notify.error(NbBundle.getMessage(this.getClass(), "VMExtractorIngestModule.msgNotify.failedIngestVM.title.txt"), + Bundle.VMExtractorIngestModule_noOpenCase_errMsg()); } } // Update progress bar @@ -219,11 +230,11 @@ final class VMExtractorIngestModule extends DataSourceIngestModuleAdapter { * @throws TskCoreException if there is a problem querying the case * database. */ - private static List findVirtualMachineFiles(Content dataSource) throws TskCoreException { + private static List findVirtualMachineFiles(Content dataSource) throws TskCoreException, NoCurrentCaseException { List vmFiles = new ArrayList<>(); for (String vmExtension : GeneralFilter.VIRTUAL_MACHINE_EXTS) { String searchString = "%" + vmExtension; // want a search string that looks like this "%.vmdk" - vmFiles.addAll(Case.getCurrentCase().getServices().getFileManager().findFiles(dataSource, searchString)); + vmFiles.addAll(Case.getOpenCase().getServices().getFileManager().findFiles(dataSource, searchString)); } return vmFiles; } @@ -258,13 +269,13 @@ final class VMExtractorIngestModule extends DataSourceIngestModuleAdapter { * * @param vmFile A virtual machine file. */ - private void ingestVirtualMachineImage(Path vmFile) throws InterruptedException, IOException { + private void ingestVirtualMachineImage(Path vmFile) throws InterruptedException, IOException, NoCurrentCaseException { /* * Try to add the virtual machine file to the case as a data source. */ UUID taskId = UUID.randomUUID(); - Case.getCurrentCase().notifyAddingDataSource(taskId); + Case.getOpenCase().notifyAddingDataSource(taskId); ImageDSProcessor dataSourceProcessor = new ImageDSProcessor(); AddDataSourceCallback dspCallback = new AddDataSourceCallback(vmFile); synchronized (this) { @@ -280,7 +291,7 @@ final class VMExtractorIngestModule extends DataSourceIngestModuleAdapter { * ingest context. */ if (!dspCallback.vmDataSources.isEmpty()) { - Case.getCurrentCase().notifyDataSourceAdded(dspCallback.vmDataSources.get(0), taskId); + Case.getOpenCase().notifyDataSourceAdded(dspCallback.vmDataSources.get(0), taskId); List dataSourceContent = new ArrayList<>(dspCallback.vmDataSources); IngestJobSettings ingestJobSettings = new IngestJobSettings(context.getExecutionContext()); for (String warning : ingestJobSettings.getWarnings()) { @@ -291,7 +302,7 @@ final class VMExtractorIngestModule extends DataSourceIngestModuleAdapter { NbBundle.getMessage(this.getClass(), "VMExtractorIngestModule.addedVirtualMachineImage.message", vmFile.toString()))); IngestManager.getInstance().queueIngestJob(dataSourceContent, ingestJobSettings); } else { - Case.getCurrentCase().notifyFailedAddingDataSource(taskId); + Case.getOpenCase().notifyFailedAddingDataSource(taskId); } } diff --git a/Core/src/org/sleuthkit/autopsy/progress/ModalDialogProgressIndicator.java b/Core/src/org/sleuthkit/autopsy/progress/ModalDialogProgressIndicator.java index d49574bf24..909c08d29e 100644 --- a/Core/src/org/sleuthkit/autopsy/progress/ModalDialogProgressIndicator.java +++ b/Core/src/org/sleuthkit/autopsy/progress/ModalDialogProgressIndicator.java @@ -227,6 +227,7 @@ public final class ModalDialogProgressIndicator implements ProgressIndicator { public synchronized void finish() { SwingUtilities.invokeLater(() -> { this.dialog.setVisible(false); + this.dialog.dispose(); }); } @@ -247,7 +248,7 @@ public final class ModalDialogProgressIndicator implements ProgressIndicator { DialogDescriptor.BOTTOM_ALIGN, HelpCtx.DEFAULT_HELP, buttonListener); - dialog = DialogDisplayer.getDefault().createDialog(dialogDescriptor); + dialog = DialogDisplayer.getDefault().createDialog(dialogDescriptor, parent); } else { /* * Dialog without buttons. @@ -256,6 +257,7 @@ public final class ModalDialogProgressIndicator implements ProgressIndicator { dialog.add(progressPanel); dialog.pack(); } + dialog.setResizable(false); dialog.setLocationRelativeTo(parent); this.dialog.setVisible(true); } diff --git a/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java b/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java index 3af9d2112d..300a810def 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java +++ b/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java @@ -36,6 +36,7 @@ import javax.swing.ListModel; import javax.swing.event.ListDataListener; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.TskCoreException; @@ -74,7 +75,7 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog { BlackboardArtifact.ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getLabel(), BlackboardArtifact.ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getDisplayName())); // output is too unstructured for table review - artifactTypes = Case.getCurrentCase().getSleuthkitCase().getArtifactTypesInUse(); + artifactTypes = Case.getOpenCase().getSleuthkitCase().getArtifactTypesInUse(); artifactTypes.removeAll(doNotReport); Collections.sort(artifactTypes, new Comparator() { @Override @@ -89,6 +90,8 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog { } } catch (TskCoreException ex) { Logger.getLogger(ArtifactSelectionDialog.class.getName()).log(Level.SEVERE, "Error getting list of artifacts in use: {0}", ex.getLocalizedMessage()); //NON-NLS + } catch (NoCurrentCaseException ex) { + Logger.getLogger(ArtifactSelectionDialog.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex.getLocalizedMessage()); //NON-NLS } } diff --git a/Core/src/org/sleuthkit/autopsy/report/FileReportText.java b/Core/src/org/sleuthkit/autopsy/report/FileReportText.java index c9a239cf0a..71cccf96ed 100644 --- a/Core/src/org/sleuthkit/autopsy/report/FileReportText.java +++ b/Core/src/org/sleuthkit/autopsy/report/FileReportText.java @@ -31,6 +31,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; @@ -71,13 +72,15 @@ class FileReportText implements FileReportModule { if (out != null) { try { out.close(); - Case.getCurrentCase().addReport(reportPath, NbBundle.getMessage(this.getClass(), + Case.getOpenCase().addReport(reportPath, NbBundle.getMessage(this.getClass(), "FileReportText.getName.text"), ""); } catch (IOException ex) { logger.log(Level.WARNING, "Could not close output writer when ending report.", ex); //NON-NLS } catch (TskCoreException ex) { String errorMessage = String.format("Error adding %s to case as a report", reportPath); //NON-NLS logger.log(Level.SEVERE, errorMessage, ex); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); } } } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java b/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java index 33609f7333..3a601fdd7f 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java @@ -31,6 +31,7 @@ import javax.swing.JPanel; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus; @@ -73,11 +74,17 @@ class ReportBodyFile implements GeneralReportModule { @SuppressWarnings("deprecation") public void generateReport(String baseReportDir, ReportProgressPanel progressPanel) { // Start the progress bar and setup the report + try { + currentCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); + return; + } progressPanel.setIndeterminate(false); progressPanel.start(); progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportBodyFile.progress.querying")); reportPath = baseReportDir + getRelativeFilePath(); //NON-NLS - currentCase = Case.getCurrentCase(); + skCase = currentCase.getSleuthkitCase(); // Run query to get all files @@ -154,14 +161,14 @@ class ReportBodyFile implements GeneralReportModule { if (out != null) { out.flush(); out.close(); - Case.getCurrentCase().addReport(reportPath, + Case.getOpenCase().addReport(reportPath, NbBundle.getMessage(this.getClass(), "ReportBodyFile.generateReport.srcModuleName.text"), ""); } } catch (IOException ex) { logger.log(Level.WARNING, "Could not flush and close the BufferedWriter.", ex); //NON-NLS - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { String errorMessage = String.format("Error adding %s to case as a report", reportPath); //NON-NLS logger.log(Level.SEVERE, errorMessage, ex); } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java b/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java index 9158790ad6..b28ac5ade2 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java @@ -27,6 +27,7 @@ import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskCoreException; @@ -112,13 +113,15 @@ class ReportExcel implements TableReportModule { try { out = new FileOutputStream(reportPath); wb.write(out); - Case.getCurrentCase().addReport(reportPath, NbBundle.getMessage(this.getClass(), + Case.getOpenCase().addReport(reportPath, NbBundle.getMessage(this.getClass(), "ReportExcel.endReport.srcModuleName.text"), ""); } catch (IOException ex) { logger.log(Level.SEVERE, "Failed to write Excel report.", ex); //NON-NLS } catch (TskCoreException ex) { String errorMessage = String.format("Error adding %s to case as a report", reportPath); //NON-NLS logger.log(Level.SEVERE, errorMessage, ex); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS } finally { if (out != null) { try { @@ -300,6 +303,13 @@ class ReportExcel implements TableReportModule { } private void writeSummaryWorksheet() { + Case currentCase; + try { + currentCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return; + } sheet = wb.createSheet(NbBundle.getMessage(this.getClass(), "ReportExcel.sheetName.text")); rowIndex = 0; @@ -311,8 +321,6 @@ class ReportExcel implements TableReportModule { sheet.createRow(rowIndex); ++rowIndex; - Case currentCase = Case.getCurrentCase(); - row = sheet.createRow(rowIndex); row.setRowStyle(setStyle); row.createCell(0).setCellValue(NbBundle.getMessage(this.getClass(), "ReportExcel.cellVal.caseName")); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index ab373e679a..127f537df4 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -41,6 +41,7 @@ import org.openide.filesystems.FileUtil; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus; @@ -54,8 +55,6 @@ class ReportGenerator { private static final Logger logger = Logger.getLogger(ReportGenerator.class.getName()); - private Case currentCase = Case.getCurrentCase(); - /** * Progress reportGenerationPanel that can be used to check for cancellation. */ @@ -229,10 +228,10 @@ class ReportGenerator { private List getFiles() { List absFiles; try { - SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); + SleuthkitCase skCase = Case.getOpenCase().getSleuthkitCase(); absFiles = skCase.findAllFilesWhere("meta_type != " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()); //NON-NLS return absFiles; - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { MessageNotifyUtil.Notify.show( NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), @@ -252,7 +251,12 @@ class ReportGenerator { } private static String createReportDirectory(ReportModule module) throws IOException { - Case currentCase = Case.getCurrentCase(); + Case currentCase; + try { + currentCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + throw new IOException("Exception while getting open case.", ex); + } // Create the root reports directory path of the form: /Reports/ / DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss"); Date date = new Date(); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 01a179a370..fdc0457b1c 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -49,6 +49,7 @@ import javax.imageio.ImageIO; import org.openide.filesystems.FileUtil; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Services; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.EscapeUtil; @@ -102,8 +103,8 @@ class ReportHTML implements TableReportModule { } // Refesh the member variables - private void refresh() { - currentCase = Case.getCurrentCase(); + private void refresh() throws NoCurrentCaseException { + currentCase = Case.getOpenCase(); skCase = currentCase.getSleuthkitCase(); dataTypes = new TreeMap<>(); @@ -327,7 +328,12 @@ class ReportHTML implements TableReportModule { @Override public void startReport(String baseReportDir) { // Refresh the HTML report - refresh(); + try { + refresh(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case."); //NON-NLS + return; + } // Setup the path for the HTML report this.path = baseReportDir; //NON-NLS this.subPath = this.path + HTML_SUBDIR + File.separator; @@ -882,6 +888,13 @@ class ReportHTML implements TableReportModule { private void writeIndex() { Writer indexOut = null; String indexFilePath = path + "report.html"; //NON-NLS + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return; + } try { indexOut = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(indexFilePath), "UTF-8")); //NON-NLS StringBuilder index = new StringBuilder(); @@ -909,7 +922,7 @@ class ReportHTML implements TableReportModule { index.append("\n"); //NON-NLS index.append(""); //NON-NLS indexOut.write(index.toString()); - Case.getCurrentCase().addReport(indexFilePath, NbBundle.getMessage(this.getClass(), + openCase.addReport(indexFilePath, NbBundle.getMessage(this.getClass(), "ReportHTML.writeIndex.srcModuleName.text"), ""); } catch (IOException ex) { logger.log(Level.SEVERE, "Error creating Writer for report.html: {0}", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java index 7df54b64b0..c5c57eccb8 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java @@ -43,6 +43,7 @@ import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter; import org.jdom2.CDATA; import org.openide.filesystems.FileUtil; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException; /** @@ -99,14 +100,18 @@ class ReportKML implements GeneralReportModule { */ @Override public void generateReport(String baseReportDir, ReportProgressPanel progressPanel) { - + try { + currentCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return; + } // Start the progress bar and setup the report progressPanel.setIndeterminate(true); progressPanel.start(); progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.querying")); String kmlFileFullPath = baseReportDir + REPORT_KML; //NON-NLS - - currentCase = Case.getCurrentCase(); + skCase = currentCase.getSleuthkitCase(); progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.loading")); @@ -382,7 +387,7 @@ class ReportKML implements GeneralReportModule { if (result == ReportProgressPanel.ReportStatus.ERROR) { prependedStatus = "Incomplete "; } - Case.getCurrentCase().addReport(kmlFileFullPath, + Case.getOpenCase().addReport(kmlFileFullPath, NbBundle.getMessage(this.getClass(), "ReportKML.genReport.srcModuleName.text"), prependedStatus + NbBundle.getMessage(this.getClass(), "ReportKML.genReport.reportName")); } catch (IOException ex) { @@ -392,6 +397,9 @@ class ReportKML implements GeneralReportModule { String errorMessage = String.format("Error adding %s to case as a report", kmlFileFullPath); //NON-NLS logger.log(Level.SEVERE, errorMessage, ex); result = ReportProgressPanel.ReportStatus.ERROR; + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); + result = ReportProgressPanel.ReportStatus.ERROR; } progressPanel.complete(result); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java index 5e516f7739..5790a34de4 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2014 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -41,6 +41,7 @@ import javax.swing.event.ListDataListener; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -97,8 +98,8 @@ final class ReportVisualPanel2 extends JPanel { private void initTags() { List tagNamesInUse; try { - tagNamesInUse = Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse(); - } catch (TskCoreException ex) { + tagNamesInUse = Case.getOpenCase().getServices().getTagsManager().getTagNamesInUse(); + } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(ReportVisualPanel2.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS return; } @@ -136,6 +137,7 @@ final class ReportVisualPanel2 extends JPanel { private void initArtifactTypes() { try { + Case openCase = Case.getOpenCase(); ArrayList doNotReport = new ArrayList<>(); doNotReport.add(new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO.getTypeID(), BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO.getLabel(), @@ -144,7 +146,7 @@ final class ReportVisualPanel2 extends JPanel { BlackboardArtifact.ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getLabel(), BlackboardArtifact.ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getDisplayName())); // output is too unstructured for table review - artifacts = Case.getCurrentCase().getSleuthkitCase().getArtifactTypesInUse(); + artifacts = openCase.getSleuthkitCase().getArtifactTypesInUse(); artifacts.removeAll(doNotReport); @@ -152,7 +154,7 @@ final class ReportVisualPanel2 extends JPanel { for (BlackboardArtifact.Type type : artifacts) { artifactStates.put(type, Boolean.TRUE); } - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(ReportVisualPanel2.class.getName()).log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage(), ex); //NON-NLS } } diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java index 499f848d54..673d5fa3d4 100644 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -39,6 +39,7 @@ import java.util.TreeSet; import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; @@ -181,11 +182,11 @@ class TableReportGenerator { String accountDisplayname = accountTypeStr; if (accountTypeStr != null) { try { - Account.Type acctType = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().getAccountType(accountTypeStr); + Account.Type acctType = Case.getOpenCase().getSleuthkitCase().getCommunicationsManager().getAccountType(accountTypeStr); if (acctType != null) { accountDisplayname = acctType.getDisplayName(); } - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Unable to get display name for account type " + accountTypeStr, ex); } } @@ -267,8 +268,8 @@ class TableReportGenerator { // Get the content tags. List tags; try { - tags = Case.getCurrentCase().getServices().getTagsManager().getAllContentTags(); - } catch (TskCoreException ex) { + tags = Case.getOpenCase().getServices().getTagsManager().getAllContentTags(); + } catch (TskCoreException | NoCurrentCaseException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetContentTags")); logger.log(Level.SEVERE, "failed to get content tags", ex); //NON-NLS return; @@ -360,8 +361,8 @@ class TableReportGenerator { List tags; try { - tags = Case.getCurrentCase().getServices().getTagsManager().getAllBlackboardArtifactTags(); - } catch (TskCoreException ex) { + tags = Case.getOpenCase().getServices().getTagsManager().getAllBlackboardArtifactTags(); + } catch (TskCoreException | NoCurrentCaseException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBArtifactTags")); logger.log(Level.SEVERE, "failed to get blackboard artifact tags", ex); //NON-NLS return; @@ -452,8 +453,8 @@ class TableReportGenerator { private void checkIfTagHasImage(BlackboardArtifactTag artifactTag) { AbstractFile file; try { - file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(artifactTag.getArtifact().getObjectID()); - } catch (TskCoreException ex) { + file = Case.getOpenCase().getSleuthkitCase().getAbstractFileById(artifactTag.getArtifact().getObjectID()); + } catch (TskCoreException | NoCurrentCaseException ex) { errorList.add( NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.errGetContentFromBBArtifact")); logger.log(Level.WARNING, "Error while getting content from a blackboard artifact to report on.", ex); //NON-NLS @@ -520,6 +521,7 @@ class TableReportGenerator { * @param tableModule module to report on */ @SuppressWarnings("deprecation") + @NbBundle.Messages ({"ReportGenerator.errList.noOpenCase=No open case available."}) private void writeKeywordHits(TableReportModule tableModule, String comment, HashSet tagNamesFilter) { // Query for keyword lists-only so that we can tell modules what lists @@ -528,7 +530,15 @@ class TableReportGenerator { // so that we only report the lists that we will later provide with real // hits. If no keyord hits are tagged, then we make the page for nothing. String orderByClause; - if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + errorList.add(Bundle.ReportGenerator_errList_noOpenCase()); + logger.log(Level.SEVERE, "Exception while getting open case: ", ex); //NON-NLS + return; + } + if (openCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS } else { orderByClause = "ORDER BY list ASC"; //NON-NLS @@ -546,7 +556,7 @@ class TableReportGenerator { + //NON-NLS "GROUP BY list " + orderByClause; //NON-NLS - try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(keywordListQuery)) { + try (SleuthkitCase.CaseDbQuery dbQuery = openCase.getSleuthkitCase().executeQuery(keywordListQuery)) { ResultSet listsRs = dbQuery.getResultSet(); List lists = new ArrayList<>(); while (listsRs.next()) { @@ -569,7 +579,7 @@ class TableReportGenerator { return; } - if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { + if (openCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { orderByClause = "ORDER BY convert_to(att3.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + "convert_to(att1.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + "convert_to(f.parent_path, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS @@ -602,7 +612,7 @@ class TableReportGenerator { + //NON-NLS orderByClause; //NON-NLS - try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(keywordsQuery)) { + try (SleuthkitCase.CaseDbQuery dbQuery = openCase.getSleuthkitCase().executeQuery(keywordsQuery)) { ResultSet resultSet = dbQuery.getResultSet(); String currentKeyword = ""; @@ -627,9 +637,9 @@ class TableReportGenerator { String uniquePath = ""; try { - AbstractFile f = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId); + AbstractFile f = openCase.getSleuthkitCase().getAbstractFileById(objId); if (f != null) { - uniquePath = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId).getUniquePath(); + uniquePath = openCase.getSleuthkitCase().getAbstractFileById(objId).getUniquePath(); } } catch (TskCoreException ex) { errorList.add( @@ -685,7 +695,15 @@ class TableReportGenerator { @SuppressWarnings("deprecation") private void writeHashsetHits(TableReportModule tableModule, String comment, HashSet tagNamesFilter) { String orderByClause; - if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + errorList.add(Bundle.ReportGenerator_errList_noOpenCase()); + logger.log(Level.SEVERE, "Exception while getting open case: ", ex); //NON-NLS + return; + } + if (openCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS } else { orderByClause = "ORDER BY att.value_text ASC"; //NON-NLS @@ -703,7 +721,7 @@ class TableReportGenerator { + //NON-NLS "GROUP BY list " + orderByClause; //NON-NLS - try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(hashsetsQuery)) { + try (SleuthkitCase.CaseDbQuery dbQuery = openCase.getSleuthkitCase().executeQuery(hashsetsQuery)) { // Query for hashsets ResultSet listsRs = dbQuery.getResultSet(); List lists = new ArrayList<>(); @@ -722,7 +740,7 @@ class TableReportGenerator { return; } - if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { + if (openCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + "convert_to(f.parent_path, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + "convert_to(f.name, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS @@ -745,7 +763,7 @@ class TableReportGenerator { + //NON-NLS orderByClause; //NON-NLS - try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(hashsetHitsQuery)) { + try (SleuthkitCase.CaseDbQuery dbQuery = openCase.getSleuthkitCase().executeQuery(hashsetHitsQuery)) { // Query for hashset hits ResultSet resultSet = dbQuery.getResultSet(); String currentSet = ""; @@ -768,9 +786,9 @@ class TableReportGenerator { String uniquePath = ""; try { - AbstractFile f = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId); + AbstractFile f = openCase.getSleuthkitCase().getAbstractFileById(objId); if (f != null) { - uniquePath = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId).getUniquePath(); + uniquePath = openCase.getSleuthkitCase().getAbstractFileById(objId).getUniquePath(); } } catch (TskCoreException ex) { errorList.add( @@ -834,9 +852,9 @@ class TableReportGenerator { this.attributes = attrs; this.tags = tags; try { - this.content = Case.getCurrentCase().getSleuthkitCase().getContentById(artifact.getObjectID()); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Could not get content from database"); + this.content = Case.getOpenCase().getSleuthkitCase().getContentById(artifact.getObjectID()); + } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Could not get content from database", ex); } } @@ -972,12 +990,12 @@ class TableReportGenerator { HashSet allTags = getTags(); try { - List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(content); + List contentTags = Case.getOpenCase().getServices().getTagsManager().getContentTagsByContent(content); for (ContentTag ct : contentTags) { String notableString = ct.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; allTags.add(ct.getName().getDisplayName() + notableString); } - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetContentTags")); logger.log(Level.SEVERE, "Failed to get content tags", ex); //NON-NLS } @@ -1008,8 +1026,8 @@ class TableReportGenerator { private List getFilteredArtifacts(BlackboardArtifact.Type type, HashSet tagNamesFilter) { List artifacts = new ArrayList<>(); try { - for (BlackboardArtifact artifact : Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifacts(type.getTypeID())) { - List tags = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact); + for (BlackboardArtifact artifact : Case.getOpenCase().getSleuthkitCase().getBlackboardArtifacts(type.getTypeID())) { + List tags = Case.getOpenCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact); HashSet uniqueTagNames = new HashSet<>(); for (BlackboardArtifactTag tag : tags) { String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; @@ -1019,13 +1037,13 @@ class TableReportGenerator { continue; } try { - artifacts.add(new ArtifactData(artifact, Case.getCurrentCase().getSleuthkitCase().getBlackboardAttributes(artifact), uniqueTagNames)); + artifacts.add(new ArtifactData(artifact, Case.getOpenCase().getSleuthkitCase().getBlackboardAttributes(artifact), uniqueTagNames)); } catch (TskCoreException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBAttribs")); logger.log(Level.SEVERE, "Failed to get Blackboard Attributes when generating report.", ex); //NON-NLS } } - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBArtifacts")); logger.log(Level.SEVERE, "Failed to get Blackboard Artifacts when generating report.", ex); //NON-NLS } @@ -1609,12 +1627,12 @@ class TableReportGenerator { + //NON-NLS "WHERE tn.tag_name_id = bat.tag_name_id AND bat.artifact_id = " + artifactId; //NON-NLS - try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(query)) { + try (SleuthkitCase.CaseDbQuery dbQuery = Case.getOpenCase().getSleuthkitCase().executeQuery(query)) { ResultSet tagNameRows = dbQuery.getResultSet(); while (tagNameRows.next()) { uniqueTagNames.add(tagNameRows.getString("display_name")); //NON-NLS } - } catch (TskCoreException | SQLException ex) { + } catch (TskCoreException | SQLException | NoCurrentCaseException ex) { throw new TskCoreException("Error getting tag names for artifact: ", ex); } diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java index 283425c5fc..f64a14306f 100644 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java @@ -27,6 +27,7 @@ import javax.swing.JPanel; import org.openide.util.lookup.ServiceProvider; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.report.GeneralReportModule; @@ -66,6 +67,14 @@ public class AddTaggedHashesToHashDb implements GeneralReportModule { @Override public void generateReport(String reportPath, ReportProgressPanel progressPanel) { + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + Logger.getLogger(AddTaggedHashesToHashDb.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); + JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), "No open Case", "Exception while getting open case.", JOptionPane.ERROR_MESSAGE); + return; + } progressPanel.setIndeterminate(true); progressPanel.start(); progressPanel.updateStatusLabel("Adding hashes..."); @@ -74,7 +83,7 @@ public class AddTaggedHashesToHashDb implements GeneralReportModule { if (hashSet != null) { progressPanel.updateStatusLabel("Adding hashes to " + hashSet.getHashSetName() + " hash set..."); - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + TagsManager tagsManager = openCase.getServices().getTagsManager(); List tagNames = configPanel.getSelectedTagNames(); ArrayList failedExports = new ArrayList<>(); for (TagName tagName : tagNames) { @@ -91,7 +100,7 @@ public class AddTaggedHashesToHashDb implements GeneralReportModule { if (content instanceof AbstractFile) { if (null != ((AbstractFile) content).getMd5Hash()) { try { - hashSet.addHashes(tag.getContent(), Case.getCurrentCase().getDisplayName()); + hashSet.addHashes(tag.getContent(), openCase.getDisplayName()); } catch (TskCoreException ex) { Logger.getLogger(AddTaggedHashesToHashDb.class.getName()).log(Level.SEVERE, "Error adding hash for obj_id = " + tag.getContent().getId() + " to hash set " + hashSet.getHashSetName(), ex); failedExports.add(tag.getContent().getName()); diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java index d8198c5198..44e0f93d75 100644 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java @@ -34,6 +34,7 @@ import javax.swing.ListCellRenderer; import javax.swing.ListModel; import javax.swing.event.ListDataListener; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; @@ -67,10 +68,13 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { private void populateTagNameComponents() { // Get the tag names in use for the current case. try { - tagNames = Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse(); + tagNames = Case.getOpenCase().getServices().getTagsManager().getTagNamesInUse(); } catch (TskCoreException ex) { Logger.getLogger(AddTaggedHashesToHashDbConfigPanel.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); JOptionPane.showMessageDialog(this, "Error getting tag names for case.", "Tag Names Not Found", JOptionPane.ERROR_MESSAGE); + } catch (NoCurrentCaseException ex) { + Logger.getLogger(AddTaggedHashesToHashDbConfigPanel.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); + JOptionPane.showMessageDialog(this, "Error getting tag names for case.", "Exception while getting open case.", JOptionPane.ERROR_MESSAGE); } // Mark the tag names as unselected. Note that tagNameSelections is a diff --git a/Core/src/org/sleuthkit/autopsy/test/CustomArtifactType.java b/Core/src/org/sleuthkit/autopsy/test/CustomArtifactType.java index ed0c216ac8..adb366878c 100644 --- a/Core/src/org/sleuthkit/autopsy/test/CustomArtifactType.java +++ b/Core/src/org/sleuthkit/autopsy/test/CustomArtifactType.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.List; import javax.xml.bind.DatatypeConverter; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -63,8 +64,8 @@ final class CustomArtifactType { * * @throws BlackboardException If there is an error adding any of the types. */ - static void addToCaseDatabase() throws Blackboard.BlackboardException { - Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard(); + static void addToCaseDatabase() throws Blackboard.BlackboardException, NoCurrentCaseException { + Blackboard blackboard = Case.getOpenCase().getServices().getBlackboard(); artifactType = blackboard.getOrAddArtifactType(ARTIFACT_TYPE_NAME, ARTIFACT_DISPLAY_NAME); intAttrType = blackboard.getOrAddAttributeType(INT_ATTR_TYPE_NAME, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.INTEGER, INT_ATTR_DISPLAY_NAME); doubleAttrType = blackboard.getOrAddAttributeType(DOUBLE_ATTR_TYPE_NAME, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DOUBLE, DOUBLE_ATTR_DISPLAY_NAME); diff --git a/Core/src/org/sleuthkit/autopsy/test/CustomArtifactsCreatorDataSourceIngestModule.java b/Core/src/org/sleuthkit/autopsy/test/CustomArtifactsCreatorDataSourceIngestModule.java index a6026357d1..8293ba934e 100644 --- a/Core/src/org/sleuthkit/autopsy/test/CustomArtifactsCreatorDataSourceIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/test/CustomArtifactsCreatorDataSourceIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.test; import java.util.logging.Level; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleAdapter; @@ -53,7 +54,7 @@ public class CustomArtifactsCreatorDataSourceIngestModule extends DataSourceInge public void startUp(IngestJobContext context) throws IngestModuleException { try { CustomArtifactType.addToCaseDatabase(); - } catch (Blackboard.BlackboardException ex) { + } catch (Blackboard.BlackboardException | NoCurrentCaseException ex) { throw new IngestModuleException(Bundle.CustomArtifactsCreatorDataSourceIngestModule_exceptionMessage_errorCreatingCustomType(), ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/test/CustomArtifactsCreatorFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/test/CustomArtifactsCreatorFileIngestModule.java index 752b007778..abd6f0d00d 100644 --- a/Core/src/org/sleuthkit/autopsy/test/CustomArtifactsCreatorFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/test/CustomArtifactsCreatorFileIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.test; import java.util.logging.Level; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.FileIngestModuleAdapter; @@ -52,7 +53,7 @@ final class CustomArtifactsCreatorFileIngestModule extends FileIngestModuleAdapt public void startUp(IngestJobContext context) throws IngestModuleException { try { CustomArtifactType.addToCaseDatabase(); - } catch (Blackboard.BlackboardException ex) { + } catch (Blackboard.BlackboardException | NoCurrentCaseException ex) { throw new IngestModuleException(Bundle.CustomArtifactsCreatorFileIngestModule_exceptionMessage_errorCreatingCustomType(), ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/test/InterestingArtifactCreatorIngestModule.java b/Core/src/org/sleuthkit/autopsy/test/InterestingArtifactCreatorIngestModule.java index a57623f02e..f56d4cb043 100644 --- a/Core/src/org/sleuthkit/autopsy/test/InterestingArtifactCreatorIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/test/InterestingArtifactCreatorIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,7 @@ import java.util.logging.Level; import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.FileIngestModuleAdapter; @@ -53,10 +54,10 @@ final class InterestingArtifactCreatorIngestModule extends FileIngestModuleAdapt @Override public void startUp(IngestJobContext context) throws IngestModuleException { - Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard(); try { + Blackboard blackboard = Case.getOpenCase().getServices().getBlackboard(); artifactType = blackboard.getOrAddArtifactType(INT_ARTIFACT_TYPE_NAME, INT_ARTIFACT_DISPLAY_NAME); - } catch (Blackboard.BlackboardException ex) { + } catch (Blackboard.BlackboardException | NoCurrentCaseException ex) { throw new IngestModuleException(Bundle.InterestingArtifactCreatorIngestModule_exceptionMessage_errorCreatingCustomType(), ex); } } @@ -76,7 +77,7 @@ final class InterestingArtifactCreatorIngestModule extends FileIngestModuleAdapt * type. */ int randomArtIndex = (int) (Math.random() * 3); - Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard(); + Blackboard blackboard = Case.getOpenCase().getServices().getBlackboard(); BlackboardArtifact.Type artifactTypeBase = blackboard.getOrAddArtifactType(ARTIFACT_TYPE_NAMES[randomArtIndex], ARTIFACT_DISPLAY_NAMES[randomArtIndex]); BlackboardArtifact artifactBase = file.newArtifact(artifactTypeBase.getTypeID()); Collection baseAttributes = new ArrayList<>(); @@ -123,7 +124,7 @@ final class InterestingArtifactCreatorIngestModule extends FileIngestModuleAdapt attributes.add(att3); attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactBase.getArtifactID())); artifact.addAttributes(attributes); - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, String.format("Failed to process file (obj_id = %d)", file.getId()), ex); return ProcessResult.ERROR; } catch (Blackboard.BlackboardException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java index aca5c4e7f7..c6e995c195 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014-2017 Basis Technology Corp. + * Copyright 2014-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,6 +33,7 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.Installer; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -80,7 +81,7 @@ public final class OpenTimelineAction extends CallableSystemAction { @Override public boolean isEnabled() { /** - * We used to also check if Case.getCurrentCase().hasData() was true. We + * We used to also check if Case.getOpenCase().hasData() was true. We * disabled that check because if it is executed while a data source is * being added, it blocks the edt. We still do that in ImageGallery. */ @@ -111,7 +112,7 @@ public final class OpenTimelineAction extends CallableSystemAction { "OpenTimeLineAction.msgdlg.text=Could not create timeline, there are no data sources."}) synchronized private void showTimeline(AbstractFile file, BlackboardArtifact artifact) { try { - Case currentCase = Case.getCurrentCase(); + Case currentCase = Case.getOpenCase(); if (currentCase.hasData() == false) { MessageNotifyUtil.Message.info(Bundle.OpenTimeLineAction_msgdlg_text()); logger.log(Level.INFO, "Could not create timeline, there are no data sources.");// NON-NLS @@ -131,7 +132,7 @@ public final class OpenTimelineAction extends CallableSystemAction { MessageNotifyUtil.Message.error(Bundle.OpenTimelineAction_settingsErrorMessage()); logger.log(Level.SEVERE, "Failed to initialize per case timeline settings.", iOException); } - } catch (IllegalStateException e) { + } catch (NoCurrentCaseException e) { //there is no case... Do nothing. } } @@ -212,8 +213,8 @@ public final class OpenTimelineAction extends CallableSystemAction { private boolean tooManyFiles() { try { - return FILE_LIMIT < Case.getCurrentCase().getSleuthkitCase().countFilesWhere("1 = 1"); - } catch (IllegalStateException ex) { + return FILE_LIMIT < Case.getOpenCase().getSleuthkitCase().countFilesWhere("1 = 1"); + } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Can not open timeline with no case open.", ex); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error counting files in the DB.", ex); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java index 3c8062355b..b382814f0d 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014-2016 Basis Technology Corp. + * Copyright 2014-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -67,6 +67,7 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import static org.sleuthkit.autopsy.casemodule.Case.Events.CURRENT_CASE; import static org.sleuthkit.autopsy.casemodule.Case.Events.DATA_SOURCE_ADDED; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; @@ -949,8 +950,8 @@ public class TimeLineController { * already closed. */ try { - Case.getCurrentCase(); - } catch (IllegalStateException notUsed) { + Case.getOpenCase(); + } catch (NoCurrentCaseException notUsed) { // Case is closed, do nothing. return; } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java index 70933143c2..2b0bf5d383 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -51,6 +51,7 @@ import org.openide.windows.RetainLocation; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.actions.AddBookmarkTagAction; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponents.DataContentPanel; import org.sleuthkit.autopsy.corecomponents.DataResultPanel; import org.sleuthkit.autopsy.corecomponents.TableFilterNode; @@ -132,7 +133,7 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer contentViewerPanel.setNode(null); } }); - } catch (IllegalStateException ex) { + } catch (NoCurrentCaseException ex) { //Since the case is closed, the user probably doesn't care about this, just log it as a precaution. LOGGER.log(Level.SEVERE, "There was no case open to lookup the Sleuthkit object backing a SingleEvent.", ex); // NON-NLS } catch (TskCoreException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java b/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java index d9226b587a..e0b3a3e333 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java @@ -47,6 +47,7 @@ import org.controlsfx.validation.Validator; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.timeline.PromptDialogManager; @@ -152,12 +153,12 @@ public class SaveSnapshotAsReport extends Action { try { //add main file as report to case - Case.getCurrentCase().addReport(reportMainFilePath.toString(), Bundle.Timeline_ModuleName(), reportName); - } catch (TskCoreException ex) { + Case.getOpenCase().addReport(reportMainFilePath.toString(), Bundle.Timeline_ModuleName(), reportName); + } catch (TskCoreException | NoCurrentCaseException ex) { LOGGER.log(Level.WARNING, "Failed to add " + reportMainFilePath.toString() + " to case as a report", ex); //NON_NLS new Alert(Alert.AlertType.ERROR, Bundle.SaveSnapShotAsReport_FailedToAddReport()).show(); return; - } + } //notify user of report location final Alert alert = new Alert(Alert.AlertType.INFORMATION, null, OPEN, OK); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/explorernodes/EventNode.java b/Core/src/org/sleuthkit/autopsy/timeline/explorernodes/EventNode.java index cf0524a893..d8f0bf9ac3 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/explorernodes/EventNode.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/explorernodes/EventNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,6 +33,7 @@ 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.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory; @@ -215,14 +216,14 @@ public class EventNode extends DisplayableItemNode { * @return An EventNode with the file (and artifact) backing this event in * its lookup. */ - public static EventNode createEventNode(final Long eventID, FilteredEventsModel eventsModel) throws TskCoreException, IllegalStateException { + public static EventNode createEventNode(final Long eventID, FilteredEventsModel eventsModel) throws TskCoreException, NoCurrentCaseException { /* * Look up the event by id and creata an EventNode with the appropriate * data in the lookup. */ final SingleEvent eventById = eventsModel.getEventById(eventID); - SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase(); + SleuthkitCase sleuthkitCase = Case.getOpenCase().getSleuthkitCase(); AbstractFile file = sleuthkitCase.getAbstractFileById(eventById.getFileID()); if (eventById.getArtifactID().isPresent()) { diff --git a/Core/src/org/sleuthkit/autopsy/timeline/explorernodes/EventRootNode.java b/Core/src/org/sleuthkit/autopsy/timeline/explorernodes/EventRootNode.java index 1b35d90188..3924918d06 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/explorernodes/EventRootNode.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/explorernodes/EventRootNode.java @@ -29,6 +29,7 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; @@ -130,7 +131,7 @@ public class EventRootNode extends DisplayableItemNode { } else { try { return EventNode.createEventNode(eventID, filteredEvents); - } catch (IllegalStateException ex) { + } catch (NoCurrentCaseException ex) { //Since the case is closed, the user probably doesn't care about this, just log it as a precaution. LOGGER.log(Level.SEVERE, "There was no case open to lookup the Sleuthkit object backing a SingleEvent.", ex); // NON-NLS return null; diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java index f7bfba4501..7515891356 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java @@ -78,6 +78,7 @@ import org.controlsfx.control.action.ActionUtils; import org.openide.awt.Actions; import org.openide.util.NbBundle; import org.openide.util.actions.Presenter; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; @@ -668,7 +669,7 @@ class ListTimeline extends BorderPane { //show new context menu. new ContextMenu(menuItems.toArray(new MenuItem[menuItems.size()])) .show(this, contextMenuEvent.getScreenX(), contextMenuEvent.getScreenY()); - } catch (IllegalStateException ex) { + } catch (NoCurrentCaseException ex) { //Since the case is closed, the user probably doesn't care about this, just log it as a precaution. LOGGER.log(Level.SEVERE, "There was no case open to lookup the Sleuthkit object backing a SingleEvent.", ex); //NON-NLS } catch (TskCoreException ex) { diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java index cce1e807e1..105f13146a 100644 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java @@ -41,6 +41,7 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.datamodel.TskData; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** * @@ -2343,9 +2344,9 @@ public class CentralRepoDatamodelTest extends TestCase { // Test creating a case from an Autopsy case // The case may already be in the database - the result is the same either way try { - caseB = EamDb.getInstance().newCase(Case.getCurrentCase()); + caseB = EamDb.getInstance().newCase(Case.getOpenCase()); assertTrue("Failed to create correlation case from Autopsy case", caseB != null); - } catch (EamDbException ex) { + } catch (EamDbException | NoCurrentCaseException ex) { Exceptions.printStackTrace(ex); Assert.fail(ex); return; @@ -2412,9 +2413,9 @@ public class CentralRepoDatamodelTest extends TestCase { // Test getting a case from an Autopsy case try { - CorrelationCase tempCase = EamDb.getInstance().getCase(Case.getCurrentCase()); + CorrelationCase tempCase = EamDb.getInstance().getCase(Case.getOpenCase()); assertTrue("getCase returned null for current Autopsy case", tempCase != null); - } catch (EamDbException ex) { + } catch (EamDbException | NoCurrentCaseException ex) { Exceptions.printStackTrace(ex); Assert.fail(ex); } diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java index 843e9e53fa..1b31a73840 100644 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2017-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/DataSourceProcessorRunner.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/DataSourceProcessorRunner.java new file mode 100755 index 0000000000..acb144405e --- /dev/null +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/DataSourceProcessorRunner.java @@ -0,0 +1,175 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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.testutils; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; +import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; +import org.sleuthkit.datamodel.Content; + +/** + * A utility that runs an auto ingest data source processor, blocking until the + * processor is finished. + */ +public final class DataSourceProcessorRunner { + + public static ProcessorCallback runDataSourceProcessor(AutoIngestDataSourceProcessor processor, Path dataSourcePath) throws AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, InterruptedException { + DataSourceProcessorProgressMonitor progressMonitor = new ProgressMonitor(); + Object ingestMonitor = new Object(); + ProcessorCallback callBack = new ProcessorCallback(ingestMonitor); + synchronized (ingestMonitor) { + processor.process(UUID.randomUUID().toString(), dataSourcePath, progressMonitor, callBack); + ingestMonitor.wait(); + } + return callBack; + } + + /** + * DataSourceProcessorRunner instances cannot be instatiated. + */ + private DataSourceProcessorRunner() { + } + + /** + * A data source processor "callback" that collects the results of running a + * data source processor on a data source and unblocks the caller's thread + * when the data source processor finishes running in its own thread. + */ + @Immutable + public static final class ProcessorCallback extends DataSourceProcessorCallback { + + private final Object monitor; + private final List errorMessages = new ArrayList<>(); + private final List dataSourceContent = new ArrayList<>(); + + /** + * Constructs a data source processor "callback" that collects the + * results of running a data source processor on a data source and + * unblocks the caller's thread when the data source processor finishes + * running in its own thread. + * + * @param monitor A monitor for the callback to signal when the data + * source processor completes its processing. + */ + private ProcessorCallback(Object monitor) { + this.monitor = monitor; + } + + /** + * Called by the data source processor when it finishes running in its + * own thread. + * + * @param result The result code for the processing of the + * data source. + * @param errorMessages Any error messages generated during the + * processing of the data source. + * @param dataSourceContent The content produced by processing the data + * source. + */ + @Override + public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSourceContent) { + this.errorMessages.addAll(errorMessages); + this.dataSourceContent.addAll(dataSourceContent); + synchronized (monitor) { + monitor.notify(); + } + } + + /** + * Called by the data source processor when it finishes running in its + * own thread, if that thread is the AWT (Abstract Window Toolkit) event + * dispatch thread (EDT). + * + * @param result The result code for the processing of the + * data source. + * @param errorMessages Any error messages generated during the + * processing of the data source. + * @param dataSourceContent The content produced by processing the data + * source. + */ + @Override + public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSourceContent) { + done(result, errorMessages, dataSourceContent); + } + + /** + * Gets any error messages emitted by the data source processor. + * + * @return A list of error messages, possibly empty. + */ + public List getErrorMessages() { + return new ArrayList<>(this.errorMessages); + } + + /** + * Gets any data source Content objects produced by the data source + * processor. + * + * @return A list of content objects, possibly empty. + */ + public List getDataSourceContent() { + return new ArrayList<>(this.dataSourceContent); + } + } + + /** + * A do-nothing data source processor progress monitor. + */ + @Immutable + private static final class ProgressMonitor implements DataSourceProcessorProgressMonitor { + + /** + * Switches the progress indicator to indeterminate mode (the total + * number of work units to be completed is unknown) or determinate mode + * (the total number of work units to be completed is unknown). + * + * @param indeterminate True for indeterminate mode, false for + * determinate mode. + */ + @Override + public void setIndeterminate(final boolean indeterminate) { + } + + /** + * Updates the progress indicator with the number of work units + * completed so far when in determinate mode (the total number of work + * units to be completed is known). + * + * @param workUnitsCompleted Number of work units completed so far. + */ + @Override + public void setProgress(final int workUnitsCompleted) { + } + + /** + * Updates the progress indicator with a progress message. + * + * @param message The progress message. + */ + @Override + public void setProgressText(final String message) { + } + } + +} diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspCallback.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspCallback.java deleted file mode 100644 index cfa9f3dc59..0000000000 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspCallback.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2017 Basis Technology Corp. - * Contact: carrier sleuthkit 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.testutils; - -import java.util.ArrayList; -import java.util.List; -import javax.annotation.concurrent.Immutable; -import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; -import org.sleuthkit.datamodel.Content; - -/** - * A data source processor "callback" for unit testing that collects the results - * of running a data source processor on a data source and unblocks the job - * processing thread when the data source processor finishes running in its own - * thread. - */ -@Immutable -public class FunctionalTestDspCallback extends DataSourceProcessorCallback { - - private final Object monitor; - private final List errorMessages = new ArrayList<>(); - private final List dataSourceContent = new ArrayList<>(); - - /** - * Constructs a data source processor "callback" for unit testing that - * collects the results of running a data source processor on a data source - * and unblocks the job processing thread when the data source processor - * finishes running in its own thread. - * - * @param monitor A monitor for the callback to signal when the data source - * processor completes its processing. - */ - FunctionalTestDspCallback(Object monitor) { - this.monitor = monitor; - } - - /** - * Called by the data source processor when it finishes running in its own - * thread. - * - * @param result The result code for the processing of the data - * source. - * @param errorMessages Any error messages generated during the - * processing of the data source. - * @param dataSourceContent The content produced by processing the data - * source. - */ - @Override - public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSourceContent) { - this.errorMessages.addAll(errorMessages); - this.dataSourceContent.addAll(dataSourceContent); - synchronized (monitor) { - monitor.notify(); - } - } - - /** - * Called by the data source processor when it finishes running in its own - * thread, if that thread is the AWT (Abstract Window Toolkit) event - * dispatch thread (EDT). - * - * @param result The result code for the processing of the data - * source. - * @param errorMessages Any error messages generated during the - * processing of the data source. - * @param dataSourceContent The content produced by processing the data - * source. - */ - @Override - public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSourceContent) { - done(result, errorMessages, dataSourceContent); - } - - /** - * Gets any error messages emitted by the data source processor. - * - * @return A list of error messages, possibly empty. - */ - public List getDspErrorMessages() { - return new ArrayList<>(this.errorMessages); - } - - /** - * Gets any data source content objects produced by the data source - * processor. - * - * @return A list of content objects, possibly empty. - */ - public List getDataSourceContent() { - return new ArrayList<>(this.dataSourceContent); - } - -} diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspProgressMonitor.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspProgressMonitor.java deleted file mode 100644 index 03d26eb9b2..0000000000 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspProgressMonitor.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2017 Basis Technology Corp. - * Contact: carrier sleuthkit 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.testutils; - -import javax.annotation.concurrent.Immutable; -import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; - -/** - * A data source processor progress monitor for unit testing. - */ -@Immutable -public class FunctionalTestDspProgressMonitor implements DataSourceProcessorProgressMonitor { - - /** - * Switches the progress indicator to indeterminate mode (the total number - * of work units to be completed is unknown) or determinate mode (the total - * number of work units to be completed is unknown). - * - * @param indeterminate True for indeterminate mode, false for determinate - * mode. - */ - @Override - public void setIndeterminate(final boolean indeterminate) { - } - - /** - * Updates the progress indicator with the number of work units completed so - * far when in determinate mode (the total number of work units to be - * completed is known). - * - * @param workUnitsCompleted Number of work units completed so far. - */ - @Override - public void setProgress(final int workUnitsCompleted) { - } - - /** - * Updates the progress indicator with a progress message. - * - * @param message The progress message. - */ - @Override - public void setProgressText(final String message) { - } - -} diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/IngestJobRunner.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/IngestJobRunner.java new file mode 100755 index 0000000000..5597ce8500 --- /dev/null +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/IngestJobRunner.java @@ -0,0 +1,115 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit 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.testutils; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import org.sleuthkit.autopsy.events.AutopsyEvent; +import org.sleuthkit.autopsy.ingest.IngestJobSettings; +import org.sleuthkit.autopsy.ingest.IngestJobStartResult; +import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.IngestModuleError; +import org.sleuthkit.datamodel.Content; + +/** + * A utility that runs an ingest job, blocking until the job is completed. + */ +public final class IngestRunner { + + /** + * Runs an ingest job, blocking until the job is completed. + * + * @param dataSources The data sources for the ingest job. + * @param settings The settings for the ingst job + * + * @return A list of ingest module start up error messages, empty if the job + * was started sucessfully. + * + * @throws InterruptedException If interrupted while wiagin for the ingest + * job to complete. + */ + public static List runIngestJob(Collection dataSources, IngestJobSettings settings) throws InterruptedException { + Object ingestMonitor = new Object(); + IngestJobCompletiontListener completiontListener = new IngestJobCompletiontListener(ingestMonitor); + IngestManager ingestManager = IngestManager.getInstance(); + ingestManager.addIngestJobEventListener(completiontListener); + try { + synchronized (ingestMonitor) { + IngestJobStartResult jobStartResult = ingestManager.beginIngestJob(dataSources, settings); + if (jobStartResult.getModuleErrors().isEmpty()) { + ingestMonitor.wait(); + return Collections.emptyList(); + } else { + return jobStartResult.getModuleErrors(); + } + } + } finally { + ingestManager.removeIngestJobEventListener(completiontListener); + } + } + + /** + * IngestRunner instances cannot be instatiated. + */ + private IngestRunner() { + } + + /** + * An ingest job event listener that allows IngestRunner.runIngestJob to + * block until the specified ingest job is completed. + */ + private static final class IngestJobCompletiontListener implements PropertyChangeListener { + + private final Object ingestMonitor; + + /** + * Constructs an ingest job event listener that allows + * IngestRunner.runIngestJob to block until the specified ingest job is + * completed. + * + * @param ingestMonitor A Java object to notify when the ingest job is + * omcpleted. + */ + IngestJobCompletiontListener(Object ingestMonitor) { + this.ingestMonitor = ingestMonitor; + } + + /** + * Listens for local ingest job completed or cancelled events and + * notifies the ingest monitor when such an event occurs. + * + * @param event + */ + @Override + public void propertyChange(PropertyChangeEvent event) { + if (AutopsyEvent.SourceType.LOCAL == ((AutopsyEvent) event).getSourceType()) { + String eventType = event.getPropertyName(); + if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { + synchronized (ingestMonitor) { + ingestMonitor.notify(); + } + } + } + } + } + +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 00f4a06e63..6835510e78 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.experimental.autoingest; import java.io.File; -import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -101,7 +100,7 @@ class AddArchiveTask implements Runnable { // extract the archive and pass the extracted folder as input try { - Case currentCase = Case.getCurrentCase(); + Case currentCase = Case.getOpenCase(); // create folder to extract archive to Path destinationFolder = createDirectoryForFile(archivePath, currentCase.getModuleDirectory()); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java index e5285d9e75..449c36dfff 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,6 +29,7 @@ import javax.swing.filechooser.FileFilter; import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import static org.sleuthkit.autopsy.experimental.autoingest.Bundle.*; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.DriveUtils; @@ -204,7 +205,9 @@ class ArchiveFilePanel extends JPanel implements DocumentListener { * * @return true if a proper archive has been selected, false otherwise */ - @NbBundle.Messages("DataSourceOnCDriveError.text=Warning: Path to multi-user data source is on \"C:\" drive") + @NbBundle.Messages({"DataSourceOnCDriveError.text=Warning: Path to multi-user data source is on \"C:\" drive", + "DataSourceOnCDriveError.noOpenCase.errMsg=Warning: Exception while getting open case." + }) public boolean validatePanel() { errorLabel.setVisible(false); String path = getContentPaths(); @@ -213,9 +216,14 @@ class ArchiveFilePanel extends JPanel implements DocumentListener { } // display warning if there is one (but don't disable "next" button) - if (false == PathValidator.isValid(path, Case.getCurrentCase().getCaseType())) { + try { + if (false == PathValidator.isValid(path, Case.getOpenCase().getCaseType())) { + errorLabel.setVisible(true); + errorLabel.setText(Bundle.DataSourceOnCDriveError_text()); + } + } catch (NoCurrentCaseException ex) { errorLabel.setVisible(true); - errorLabel.setText(Bundle.DataSourceOnCDriveError_text()); + errorLabel.setText(Bundle.DataSourceOnCDriveError_noOpenCase_errMsg()); } return new File(path).isFile() diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java index f299fbc5a3..45563a4f4b 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017-2018 Basis Technology Corp. + * Copyright 2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,14 +28,13 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.experimental.autoingest.AutoIngestDashboardOpenAction") -@ActionReference(path = "Menu/Tools", position = 201) +@ActionReference(path = "Menu/Tools", position = 104) @ActionRegistration(displayName = "#CTL_AutoIngestDashboardOpenAction", lazy = false) @Messages({"CTL_AutoIngestDashboardOpenAction=Auto Ingest Dashboard"}) public final class AutoIngestDashboardOpenAction extends CallableSystemAction { private static final Logger LOGGER = Logger.getLogger(AutoIngestDashboardOpenAction.class.getName()); private static final String DISPLAY_NAME = Bundle.CTL_AutoIngestDashboardOpenAction(); - private static final long serialVersionUID = 1L; @Override public boolean isEnabled() { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index c9fb9a7003..41a5d46192 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -63,6 +63,7 @@ import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.CaseActionException; import org.sleuthkit.autopsy.casemodule.CaseDetails; import org.sleuthkit.autopsy.casemodule.CaseMetadata; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coordinationservice.CaseNodeData; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; @@ -226,10 +227,10 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen } rootInputDirectory = Paths.get(AutoIngestUserPreferences.getAutoModeImageFolder()); rootOutputDirectory = Paths.get(AutoIngestUserPreferences.getAutoModeResultsFolder()); - inputScanSchedulingExecutor.scheduleAtFixedRate(new InputDirScanSchedulingTask(), 0, AutoIngestUserPreferences.getMinutesOfInputScanInterval(), TimeUnit.MINUTES); + inputScanSchedulingExecutor.scheduleWithFixedDelay(new InputDirScanSchedulingTask(), 0, AutoIngestUserPreferences.getMinutesOfInputScanInterval(), TimeUnit.MINUTES); jobProcessingTask = new JobProcessingTask(); jobProcessingTaskFuture = jobProcessingExecutor.submit(jobProcessingTask); - jobStatusPublishingExecutor.scheduleAtFixedRate(new PeriodicJobStatusEventTask(), JOB_STATUS_EVENT_INTERVAL_SECONDS, JOB_STATUS_EVENT_INTERVAL_SECONDS, TimeUnit.SECONDS); + jobStatusPublishingExecutor.scheduleWithFixedDelay(new PeriodicJobStatusEventTask(), JOB_STATUS_EVENT_INTERVAL_SECONDS, JOB_STATUS_EVENT_INTERVAL_SECONDS, TimeUnit.SECONDS); eventPublisher.addSubscriber(EVENT_LIST, instance); state = State.RUNNING; errorState = ErrorState.NONE; @@ -2269,7 +2270,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen Thread.sleep(AutoIngestUserPreferences.getSecondsToSleepBetweenCases() * 1000); } currentJob.setCaseDirectoryPath(caseDirectoryPath); - Case caseForJob = Case.getCurrentCase(); + Case caseForJob = Case.getOpenCase(); SYS_LOGGER.log(Level.INFO, "Opened case {0} for {1}", new Object[]{caseForJob.getName(), manifest.getFilePath()}); return caseForJob; @@ -2277,10 +2278,10 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen throw new CaseManagementException(String.format("Error creating solr settings file for case %s for %s", caseName, manifest.getFilePath()), ex); } catch (CaseActionException ex) { throw new CaseManagementException(String.format("Error creating or opening case %s for %s", caseName, manifest.getFilePath()), ex); - } catch (IllegalStateException ex) { + } catch (NoCurrentCaseException ex) { /* * Deal with the unfortunate fact that - * Case.getCurrentCase throws IllegalStateException. + * Case.getOpenCase throws NoCurrentCaseException. */ throw new CaseManagementException(String.format("Error getting current case %s for %s", caseName, manifest.getFilePath()), ex); } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java index 9209fa1147..b8c5fcf23a 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java @@ -92,7 +92,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen } catch (AutopsyEventException ex) { throw new AutoIngestMonitorException("Failed to open auto ingest event channel", ex); //NON-NLS } - coordSvcQueryExecutor.scheduleAtFixedRate(new CoordinationServiceQueryTask(), 0, CORRD_SVC_QUERY_INERVAL_MINS, TimeUnit.MINUTES); + coordSvcQueryExecutor.scheduleWithFixedDelay(new CoordinationServiceQueryTask(), 0, CORRD_SVC_QUERY_INERVAL_MINS, TimeUnit.MINUTES); eventPublisher.addSubscriber(EVENT_LIST, this); } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExportRuleSet.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExportRuleSet.java index d4616036f7..0029150e3d 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExportRuleSet.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExportRuleSet.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,6 +39,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.apache.commons.codec.binary.Hex; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** * Uniquely named file export rules organized into uniquely named rule sets. @@ -374,7 +375,7 @@ final class FileExportRuleSet implements Serializable, Comparable evaluate(long dataSourceId) throws ExportRulesException { try { - SleuthkitCase db = Case.getCurrentCase().getSleuthkitCase(); + SleuthkitCase db = Case.getOpenCase().getSleuthkitCase(); try (SleuthkitCase.CaseDbQuery queryResult = db.executeQuery(getQuery(dataSourceId))) { ResultSet resultSet = queryResult.getResultSet(); List fileIds = new ArrayList<>(); @@ -383,7 +384,7 @@ final class FileExportRuleSet implements Serializable, Comparable sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,6 +34,7 @@ import java.util.Map; import java.util.TreeMap; import java.util.function.Supplier; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.AbstractFile; @@ -111,7 +112,7 @@ final class FileExporter { } closeCatalogs(); writeFlagFiles(); - } catch (FileExportSettings.PersistenceException | FileExportRuleSet.ExportRulesException | TskCoreException | IOException ex) { + } catch (FileExportSettings.PersistenceException | FileExportRuleSet.ExportRulesException | TskCoreException | IOException | NoCurrentCaseException ex) { throw new FileExportException("Error occurred during file export", ex); } } @@ -128,7 +129,12 @@ final class FileExporter { * @throws org.sleuthkit.autopsy.autoingest.FileExporter.FileExportException */ private boolean verifyPrerequisites(List dataSources) throws FileExportException { - SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); + SleuthkitCase skCase; + try { + skCase = Case.getOpenCase().getSleuthkitCase(); + } catch (NoCurrentCaseException ex) { + throw new FileExportException("Exception while getting open case.", ex); + } List ingestJobs = new ArrayList<>(); try { // all ingest jobs that were processed as part of this case @@ -310,7 +316,7 @@ final class FileExporter { * @throws IOException If there is a problem writing a file to * secondary storage. */ - private void exportFiles(Map> fileIdsToRuleNames, Supplier cancelCheck) throws TskCoreException, IOException { + private void exportFiles(Map> fileIdsToRuleNames, Supplier cancelCheck) throws TskCoreException, IOException, NoCurrentCaseException { for (Map.Entry> entry : fileIdsToRuleNames.entrySet()) { if (cancelCheck.get()) { return; @@ -334,8 +340,8 @@ final class FileExporter { * @throws IOException If there is a problem writing the file to * storage. */ - private void exportFile(Long fileId, List ruleNames, Supplier cancelCheck) throws TskCoreException, IOException { - AbstractFile file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(fileId); + private void exportFile(Long fileId, List ruleNames, Supplier cancelCheck) throws TskCoreException, IOException, NoCurrentCaseException { + AbstractFile file = Case.getOpenCase().getSleuthkitCase().getAbstractFileById(fileId); if (!shouldExportFile(file)) { return; } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExporterSettingsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExporterSettingsPanel.java index ab1b44702c..62b01b558f 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExporterSettingsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExporterSettingsPanel.java @@ -82,6 +82,7 @@ import java.time.ZoneId; import javax.swing.DefaultListModel; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** * Global settings panel for data-source-level ingest modules that export and @@ -528,11 +529,11 @@ public final class FileExporterSettingsPanel extends JPanel { void populateArtifacts() { Set artifactTypes = scanRulesForArtifacts(); try { - SleuthkitCase currentCase = Case.getCurrentCase().getSleuthkitCase(); + SleuthkitCase currentCase = Case.getOpenCase().getSleuthkitCase(); for (BlackboardArtifact.Type type : currentCase.getArtifactTypes()) { artifactTypes.add(type.getTypeName()); } - } catch (IllegalStateException | TskCoreException ex) { + } catch (NoCurrentCaseException | TskCoreException ex) { // Unable to find and open case or cannot read the database. Use enum. for (BlackboardArtifact.ARTIFACT_TYPE artifact : BlackboardArtifact.ARTIFACT_TYPE.values()) { artifactTypes.add(artifact.toString()); @@ -602,12 +603,12 @@ public final class FileExporterSettingsPanel extends JPanel { Set attributeTypes = scanRulesForAttributes(); try { - SleuthkitCase currentCase = Case.getCurrentCase().getSleuthkitCase(); + SleuthkitCase currentCase = Case.getOpenCase().getSleuthkitCase(); for (BlackboardAttribute.Type type : currentCase.getAttributeTypes()) { attributeTypes.add(type.getTypeName()); attributeTypeMap.put(type.getTypeName(), type.getValueType()); } - } catch (IllegalStateException | TskCoreException ex) { + } catch (NoCurrentCaseException | TskCoreException ex) { // Unable to find and open case or cannot read the database. Use enum. for (BlackboardAttribute.ATTRIBUTE_TYPE type : BlackboardAttribute.ATTRIBUTE_TYPE.values()) { attributeTypes.add(type.getLabel()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index f4e0a6959c..5c9acf45bf 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-17 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -58,6 +58,7 @@ import org.netbeans.api.progress.ProgressHandle; import org.openide.util.Cancellable; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.core.RuntimeProperties; @@ -192,8 +193,10 @@ public final class ImageGalleryController { Platform.runLater(() -> { stale.set(b); }); - if (Case.isCaseOpen()) { - new PerCaseProperties(Case.getCurrentCase()).setConfigSetting(ImageGalleryModule.getModuleName(), PerCaseProperties.STALE, b.toString()); + try { + new PerCaseProperties(Case.getOpenCase()).setConfigSetting(ImageGalleryModule.getModuleName(), PerCaseProperties.STALE, b.toString()); + } catch (NoCurrentCaseException ex) { + Logger.getLogger(ImageGalleryController.class.getName()).log(Level.WARNING, "Exception while getting open case."); //NON-NLS } } @@ -209,10 +212,14 @@ public final class ImageGalleryController { private ImageGalleryController() { listeningEnabled.addListener((observable, oldValue, newValue) -> { - //if we just turned on listening and a case is open and that case is not up to date - if (newValue && !oldValue && Case.isCaseOpen() && ImageGalleryModule.isDrawableDBStale(Case.getCurrentCase())) { - //populate the db - queueDBTask(new CopyAnalyzedFiles(instance, db, sleuthKitCase)); + try { + //if we just turned on listening and a case is open and that case is not up to date + if (newValue && !oldValue && ImageGalleryModule.isDrawableDBStale(Case.getOpenCase())) { + //populate the db + queueDBTask(new CopyAnalyzedFiles(instance, db, sleuthKitCase)); + } + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.WARNING, "Exception while getting open case.", ex); } }); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.java index 6437566fa8..b97a116ad8 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.java @@ -19,9 +19,12 @@ package org.sleuthkit.autopsy.imagegallery; import java.awt.event.ActionEvent; +import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.coreutils.Logger; /** * The Image/Video Gallery panel in the NetBeans provided Options Dialogs @@ -183,10 +186,15 @@ final class ImageGalleryOptionsPanel extends javax.swing.JPanel { void load() { enabledByDefaultBox.setSelected(ImageGalleryPreferences.isEnabledByDefault()); - if (Case.isCaseOpen() && IngestManager.getInstance().isIngestRunning() == false) { - enabledForCaseBox.setEnabled(true); - enabledForCaseBox.setSelected(ImageGalleryModule.isEnabledforCase(Case.getCurrentCase())); - } else { + try { + if (IngestManager.getInstance().isIngestRunning() == false) { + enabledForCaseBox.setEnabled(true); + enabledForCaseBox.setSelected(ImageGalleryModule.isEnabledforCase(Case.getOpenCase())); + } else { + enabledForCaseBox.setEnabled(false); + enabledForCaseBox.setSelected(enabledByDefaultBox.isSelected()); + } + } catch (NoCurrentCaseException ex) { enabledForCaseBox.setEnabled(false); enabledForCaseBox.setSelected(enabledByDefaultBox.isSelected()); } @@ -194,11 +202,16 @@ final class ImageGalleryOptionsPanel extends javax.swing.JPanel { } void store() { + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + Logger.getLogger(ImageGalleryOptionsPanel.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return; + } ImageGalleryPreferences.setEnabledByDefault(enabledByDefaultBox.isSelected()); ImageGalleryController.getDefault().setListeningEnabled(enabledForCaseBox.isSelected()); - if (Case.isCaseOpen()) { - new PerCaseProperties(Case.getCurrentCase()).setConfigSetting(ImageGalleryModule.getModuleName(), PerCaseProperties.ENABLED, Boolean.toString(enabledForCaseBox.isSelected())); - } + new PerCaseProperties(openCase).setConfigSetting(ImageGalleryModule.getModuleName(), PerCaseProperties.ENABLED, Boolean.toString(enabledForCaseBox.isSelected())); ImageGalleryPreferences.setGroupCategorizationWarningDisabled(groupCategorizationWarningBox.isSelected()); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java index 40451e8443..2145b76d3f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java @@ -35,6 +35,7 @@ import org.controlsfx.control.action.ActionUtils; import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; @@ -122,7 +123,7 @@ public class DeleteTagAction extends Action { try { List existingTagsList - = Case.getCurrentCase().getServices().getTagsManager() + = Case.getOpenCase().getServices().getTagsManager() .getContentTagsByContent(file); Collection tagNamesList @@ -138,7 +139,7 @@ public class DeleteTagAction extends Action { } } } - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(TagMenu.class.getName()) .log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java index 67d72bbeb3..f318b0d44c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015-17 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -45,6 +45,7 @@ import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.Installer; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; @@ -106,7 +107,13 @@ public final class OpenAction extends CallableSystemAction { @Override public boolean isEnabled() { - return super.isEnabled() && Case.isCaseOpen() && Installer.isJavaFxInited() && Case.getCurrentCase().hasData(); + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + return false; + } + return super.isEnabled() && Installer.isJavaFxInited() && openCase.hasData(); } /** @@ -145,10 +152,13 @@ public final class OpenAction extends CallableSystemAction { public void performAction() { //check case - if (!Case.isCaseOpen()) { + final Case currentCase; + try { + currentCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); return; } - final Case currentCase = Case.getCurrentCase(); if (tooManyFiles()) { Platform.runLater(OpenAction::showTooManyFiles); @@ -178,8 +188,8 @@ public final class OpenAction extends CallableSystemAction { private boolean tooManyFiles() { try { - return FILE_LIMIT < Case.getCurrentCase().getSleuthkitCase().countFilesWhere("1 = 1"); - } catch (IllegalStateException ex) { + return FILE_LIMIT < Case.getOpenCase().getSleuthkitCase().countFilesWhere("1 = 1"); + } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Can not open image gallery with no case open.", ex); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error counting files in the DB.", ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index 671e964372..f62bfd1bc6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -38,6 +38,7 @@ import javax.annotation.Nonnull; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.text.WordUtils; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileTypeUtils; import org.sleuthkit.autopsy.imagegallery.ThumbnailCache; @@ -73,8 +74,8 @@ public abstract class DrawableFile { : new ImageFile(abstractFileById, analyzed); } - public static DrawableFile create(Long id, boolean analyzed) throws TskCoreException, IllegalStateException { - return create(Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(id), analyzed); + public static DrawableFile create(Long id, boolean analyzed) throws TskCoreException, NoCurrentCaseException { + return create(Case.getOpenCase().getSleuthkitCase().getAbstractFileById(id), analyzed); } private SoftReference imageRef; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java index 290e5a6e75..81fc907069 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java @@ -30,6 +30,7 @@ import javafx.scene.media.Media; import javafx.scene.media.MediaException; import org.netbeans.api.progress.ProgressHandle; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.VideoUtils; @@ -45,9 +46,9 @@ public class VideoFile extends DrawableFile { /** * Instantiate a VideoFile object. - * + * * @param file The file on which to base the object. - * @param analyzed + * @param analyzed */ VideoFile(AbstractFile file, Boolean analyzed) { super(file, analyzed); @@ -55,15 +56,13 @@ public class VideoFile extends DrawableFile { /** * Get the genereric video thumbnail. - * + * * @return The thumbnail. */ public static Image getGenericVideoThumbnail() { return videoIcon; } - - @Override String getMessageTemplate(final Exception exception) { return "Failed to get image preview for video {0}: " + exception.toString(); //NON-NLS @@ -78,14 +77,15 @@ public class VideoFile extends DrawableFile { /** * Get the media associated with the VideoFile. - * + * * @return The media. - * + * * @throws IOException - * @throws MediaException + * @throws MediaException + * @throws NoCurrentCaseException */ @NbBundle.Messages({"VideoFile.getMedia.progress=writing temporary file to disk"}) - public Media getMedia() throws IOException, MediaException { + public Media getMedia() throws IOException, MediaException, NoCurrentCaseException { Media media = (mediaRef != null) ? mediaRef.get() : null; if (media != null) { @@ -104,24 +104,23 @@ public class VideoFile extends DrawableFile { media = new Media(Paths.get(cacheFile.getAbsolutePath()).toUri().toString()); mediaRef = new SoftReference<>(media); return media; - } @Override Double getWidth() { - double retValue = -1.0; - + double width = -1.0; try { - retValue = (double) getMedia().getWidth(); + width = getMedia().getWidth(); } catch (ReadContentInputStreamException ex) { - logger.log(Level.WARNING, "Error reading video file.", ex); //NON-NLS + logger.log(Level.WARNING, "Error reading video file", ex); //NON-NLS } catch (IOException ex) { - logger.log(Level.SEVERE, "Error writing video file to disk.", ex); //NON-NLS + logger.log(Level.SEVERE, "Error writing video file to disk", ex); //NON-NLS } catch (MediaException ex) { - logger.log(Level.SEVERE, "Error creating media from source file.", ex); //NON-NLS + logger.log(Level.SEVERE, "Error creating media from source file", ex); //NON-NLS + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "The current case has been closed", ex); //NON-NLS } - - return retValue; + return width; } @Override @@ -131,18 +130,18 @@ public class VideoFile extends DrawableFile { @Override Double getHeight() { - double retValue = -1.0; - + double height = -1.0; try { - retValue = (double) getMedia().getHeight(); + height = getMedia().getHeight(); } catch (ReadContentInputStreamException ex) { logger.log(Level.WARNING, "Error reading video file.", ex); //NON-NLS } catch (IOException ex) { logger.log(Level.SEVERE, "Error writing video file to disk.", ex); //NON-NLS } catch (MediaException ex) { logger.log(Level.SEVERE, "Error creating media from source file.", ex); //NON-NLS + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "The current case has been closed", ex); //NON-NLS } - - return retValue; + return height; } } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ArtifactTextExtractor.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ArtifactTextExtractor.java index 962e5ba245..61b9bb3b20 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ArtifactTextExtractor.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ArtifactTextExtractor.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,7 @@ import java.nio.charset.StandardCharsets; import java.util.logging.Level; import org.apache.commons.io.IOUtils; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.AbstractFile; @@ -57,9 +58,9 @@ class ArtifactTextExtractor implements TextExtractor { Case currentCase; try { - currentCase = Case.getCurrentCase(); - } catch (IllegalStateException ignore) { - // thorown by Case.getCurrentCase() if currentCase is null + currentCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ignore) { + // thorown by Case.getOpenCase() if currentCase is null return null; } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java index 08b2d0a7bb..88163b357c 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java @@ -31,6 +31,7 @@ import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.AdHocQueryResult; @@ -176,7 +177,7 @@ public class ExtractedContentViewer implements DataContentViewer { if (rawArtifactText != null) { sources.add(rawArtifactText); } - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Error creating RawText for " + file, ex); //NON-NLS } @@ -206,7 +207,7 @@ public class ExtractedContentViewer implements DataContentViewer { } - static private IndexedText getRawArtifactText(BlackboardArtifact artifact) throws TskCoreException { + static private IndexedText getRawArtifactText(BlackboardArtifact artifact) throws TskCoreException, NoCurrentCaseException { IndexedText rawArtifactText = null; if (null != artifact) { /* @@ -219,7 +220,7 @@ public class ExtractedContentViewer implements DataContentViewer { BlackboardAttribute attribute = artifact.getAttribute(TSK_ASSOCIATED_ARTIFACT_TYPE); if (attribute != null) { long artifactId = attribute.getValueLong(); - BlackboardArtifact associatedArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(artifactId); + BlackboardArtifact associatedArtifact = Case.getOpenCase().getSleuthkitCase().getBlackboardArtifact(artifactId); rawArtifactText = new RawText(associatedArtifact, associatedArtifact.getArtifactID()); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java index f9284e81d9..c45b70c863 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,6 +24,7 @@ import java.util.Comparator; import java.util.Optional; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -116,7 +117,12 @@ class KeywordHit implements Comparable { long getContentID() throws TskCoreException { if (isArtifactHit()) { // If the hit was in an artifact, look up the source content for the artifact. - SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase(); + SleuthkitCase caseDb; + try { + caseDb = Case.getOpenCase().getSleuthkitCase(); + } catch (NoCurrentCaseException ex) { + throw new TskCoreException("Exception while getting open case.", ex); + } try (SleuthkitCase.CaseDbQuery executeQuery = caseDb.executeQuery(GET_CONTENT_ID_FROM_ARTIFACT_ID + this.solrObjectId); ResultSet resultSet = executeQuery.getResultSet();) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java index 81ef0e614a..83cdafb88a 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java @@ -27,6 +27,7 @@ import java.util.logging.Level; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -144,7 +145,8 @@ public final class KeywordSearchIngestModule implements FileIngestModule { @Messages({ "KeywordSearchIngestModule.startupMessage.failedToGetIndexSchema=Failed to get schema version for text index.", "# {0} - Solr version number", "KeywordSearchIngestModule.startupException.indexSolrVersionNotSupported=Adding text no longer supported for Solr version {0} of the text index.", - "# {0} - schema version number", "KeywordSearchIngestModule.startupException.indexSchemaNotSupported=Adding text no longer supported for schema version {0} of the text index." + "# {0} - schema version number", "KeywordSearchIngestModule.startupException.indexSchemaNotSupported=Adding text no longer supported for schema version {0} of the text index.", + "KeywordSearchIngestModule.noOpenCase.errMsg=No open case available." }) @Override public void startUp(IngestJobContext context) throws IngestModuleException { @@ -180,11 +182,17 @@ public final class KeywordSearchIngestModule implements FileIngestModule { // increment the module reference count // if first instance of this module for this job then check the server and existence of keywords + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + throw new IngestModuleException(Bundle.KeywordSearchIngestModule_noOpenCase_errMsg(), ex); + } if (refCounter.incrementAndGet(jobId) == 1) { - if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { + if (openCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { // for multi-user cases need to verify connection to remore SOLR server KeywordSearchService kwsService = new SolrSearchService(); - Server.IndexingServerProperties properties = Server.getMultiUserServerProperties(Case.getCurrentCase().getCaseDirectory()); + Server.IndexingServerProperties properties = Server.getMultiUserServerProperties(openCase.getCaseDirectory()); int port; try { port = Integer.parseInt(properties.getPort()); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java index fd15fb0cf2..290fe8b086 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java @@ -39,6 +39,7 @@ import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode; @@ -147,8 +148,8 @@ class KeywordSearchResultFactory extends ChildFactory { } SleuthkitCase tskCase; try { - tskCase = Case.getCurrentCase().getSleuthkitCase(); - } catch (IllegalStateException ex) { + tskCase = Case.getOpenCase().getSleuthkitCase(); + } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "There was no case open.", ex); //NON-NLS return false; } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java index 585424b3ec..b4e07d0d8a 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryResults.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,6 +32,7 @@ import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.aggregate.ProgressContributor; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestMessage; @@ -212,9 +213,9 @@ class QueryResults { */ Content content = null; try { - SleuthkitCase tskCase = Case.getCurrentCase().getSleuthkitCase(); + SleuthkitCase tskCase = Case.getOpenCase().getSleuthkitCase(); content = tskCase.getContentById(hit.getContentID()); - } catch (TskCoreException | IllegalStateException tskCoreException) { + } catch (TskCoreException | NoCurrentCaseException tskCoreException) { logger.log(Level.SEVERE, "Failed to get text source object for ", tskCoreException); //NON-NLS } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java index 306502603c..ad0fc0a678 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,6 +39,7 @@ import org.apache.solr.common.params.CursorMarkParams; import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.CreditCards; @@ -590,11 +591,11 @@ final class RegexQuery implements KeywordSearchQuery { * Create an account instance. */ try { - AccountFileInstance ccAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.CREDIT_CARD, ccnAttribute.getValueString() , MODULE_NAME, content); + AccountFileInstance ccAccountInstance = Case.getOpenCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.CREDIT_CARD, ccnAttribute.getValueString() , MODULE_NAME, content); ccAccountInstance.addAttributes(attributes); - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { LOGGER.log(Level.SEVERE, "Error creating CCN account instance", ex); //NON-NLS } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java index d42f0b5b64..b2d1ef37e1 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,6 +34,7 @@ import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.response.TermsResponse.Term; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.datamodel.CreditCards; @@ -494,10 +495,9 @@ final class TermsComponentQuery implements KeywordSearchQuery { * Create an account. */ try { - AccountFileInstance ccAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.CREDIT_CARD, ccnAttribute.getValueString(), MODULE_NAME, content); + AccountFileInstance ccAccountInstance = Case.getOpenCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.CREDIT_CARD, ccnAttribute.getValueString(), MODULE_NAME, content); ccAccountInstance.addAttributes(attributes); - //newArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(ccAccountInstance.getArtifactId()); - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { LOGGER.log(Level.SEVERE, "Error creating CCN account instance", ex); //NON-NLS } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java index 5af71ecec0..4cb6eaf8e3 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2012-2014 Basis Technology Corp. + * Copyright 2012-2018 Basis Technology Corp. * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com @@ -30,6 +30,7 @@ import java.util.logging.Level; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -106,15 +107,19 @@ abstract class Extract { * * @param bbart Blackboard artifact to be indexed */ - @Messages({"Extract.indexError.message=Failed to index artifact for keyword search."}) + @Messages({"Extract.indexError.message=Failed to index artifact for keyword search.", + "Extract.noOpenCase.errMsg=No open case available."}) void indexArtifact(BlackboardArtifact bbart) { - Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard(); try { + Blackboard blackboard = Case.getOpenCase().getServices().getBlackboard(); // index the artifact for keyword search blackboard.indexArtifact(bbart); } catch (Blackboard.BlackboardException ex) { logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bbart.getDisplayName(), ex); //NON-NLS MessageNotifyUtil.Notify.error(Bundle.Extract_indexError_message(), bbart.getDisplayName()); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + MessageNotifyUtil.Notify.error(Bundle.Extract_noOpenCase_errMsg(), bbart.getDisplayName()); } } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java index a494f64f77..3e8bb2d611 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com @@ -44,6 +44,7 @@ import java.util.Scanner; import java.util.stream.Collectors; import org.openide.modules.InstalledFileLocator; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -72,9 +73,9 @@ class ExtractIE extends Extract { private Content dataSource; private IngestJobContext context; - ExtractIE() { + ExtractIE() throws NoCurrentCaseException { moduleName = NbBundle.getMessage(ExtractIE.class, "ExtractIE.moduleName.text"); - moduleTempResultsDir = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), "IE") + File.separator + "results"; //NON-NLS + moduleTempResultsDir = RAImageIngestModule.getRATempPath(Case.getOpenCase(), "IE") + File.separator + "results"; //NON-NLS JAVA_PATH = PlatformUtil.getJavaPath(); } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java index 9fdec551b4..7907db41bc 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2012-2014 Basis Technology Corp. + * Copyright 2012-2018 Basis Technology Corp. * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com @@ -27,9 +27,9 @@ import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.DataSourceIngestModule; import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; @@ -59,9 +59,14 @@ public final class RAImageIngestModule implements DataSourceIngestModule { public void startUp(IngestJobContext context) throws IngestModuleException { this.context = context; - + Extract iexplore; + try { + iexplore = new ExtractIE(); + } catch (NoCurrentCaseException ex) { + throw new IngestModuleException(ex.getMessage(), ex); + } + Extract registry = new ExtractRegistry(); - Extract iexplore = new ExtractIE(); Extract recentDocuments = new RecentDocumentsByLnk(); Extract chrome = new Chrome(); Extract firefox = new Firefox(); diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java index a69ee8edf7..9048c57da0 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2012 Basis Technology Corp. + * Copyright 2012-2018 Basis Technology Corp. * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com @@ -41,6 +41,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; @@ -190,11 +191,11 @@ class Util { int index = parent_path.lastIndexOf('/'); String name = parent_path.substring(++index); parent_path = parent_path.substring(0, index); - FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); List files = null; try { + FileManager fileManager = Case.getOpenCase().getServices().getFileManager(); files = fileManager.findFiles(dataSource, name, parent_path); - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.WARNING, "Error fetching 'index.data' files for Internet Explorer history."); //NON-NLS } diff --git a/build.xml b/build.xml index ef5ad87980..0c45446ab2 100644 --- a/build.xml +++ b/build.xml @@ -32,7 +32,7 @@ - + @@ -87,13 +87,7 @@ - - - - - - - + @@ -102,7 +96,6 @@ - diff --git a/docs/doxygen-user/images/case-properties-history-tab.PNG b/docs/doxygen-user/images/case-properties-history-tab.PNG index 0a5d8f25b7..fc0a4da441 100644 Binary files a/docs/doxygen-user/images/case-properties-history-tab.PNG and b/docs/doxygen-user/images/case-properties-history-tab.PNG differ diff --git a/docs/doxygen-user/images/live_triage_case.png b/docs/doxygen-user/images/live_triage_case.png deleted file mode 100644 index fee49485f5..0000000000 Binary files a/docs/doxygen-user/images/live_triage_case.png and /dev/null differ diff --git a/docs/doxygen-user/images/live_triage_dialog.png b/docs/doxygen-user/images/live_triage_dialog.png deleted file mode 100644 index 4768ec8245..0000000000 Binary files a/docs/doxygen-user/images/live_triage_dialog.png and /dev/null differ diff --git a/docs/doxygen-user/images/live_triage_ds.png b/docs/doxygen-user/images/live_triage_ds.png deleted file mode 100644 index f21a50aa82..0000000000 Binary files a/docs/doxygen-user/images/live_triage_ds.png and /dev/null differ diff --git a/docs/doxygen-user/images/live_triage_script.png b/docs/doxygen-user/images/live_triage_script.png deleted file mode 100644 index 2bdf7f12ae..0000000000 Binary files a/docs/doxygen-user/images/live_triage_script.png and /dev/null differ diff --git a/docs/doxygen-user/images/multi_user_case_select.png b/docs/doxygen-user/images/multi_user_case_select.png index c4ca377fc6..f87baa555a 100644 Binary files a/docs/doxygen-user/images/multi_user_case_select.png and b/docs/doxygen-user/images/multi_user_case_select.png differ diff --git a/docs/doxygen-user/live_triage.dox b/docs/doxygen-user/live_triage.dox deleted file mode 100644 index d85b54a20a..0000000000 --- a/docs/doxygen-user/live_triage.dox +++ /dev/null @@ -1,33 +0,0 @@ -/*! \page live_triage_page Live Triage - -\section live_triage_overview Overview - -The Live Triage feature allows you to load Autopsy onto a removable drive to run on target systems while making minimal changes to that target system. This will currently only work on Windows systems. - -\section live_triage_create_drive Creating a live triage drive - -To create a live triage drive, go to Tools->Make Live Triage Drive to bring up the main dialog. - -\image html live_triage_dialog.png - -Select the drive you want to use - any type of USB storage device will work. For best results use the fastest drive available. Once the process is complete the root folder will contain an Autopsy folder and a RunFromUSB.bat file. - -\section live_triage_usage Running Autopsy from the live triage drive - -Insert the drive into the target machine and browse to it in Windows Explorer. Right click on RunFromUSB.bat and select "Run as administrator". This is necessary to analyze the local drives. - -\image html live_triage_script.png - -Running the script will generate a few more directories on the USB drive. The configData directory stores all the data used by Autopsy - primarily configuration files and temporary files. You can make changes to the Autopsy settings and they will persist between runs. The cases directory is created as a recommended place to save your case data. You will need to browse to it when creating a case in Autopsy. - -Once Autopsy is running, proceed to create a case as normal, making sure to save it on the USB drive. - -\image html live_triage_case.png - -Then choose the Local Disk data source and select the desired drive. - -\image html live_triage_ds.png - -See the \ref ds_local page for more information on local disk data sources. - -*/ \ No newline at end of file diff --git a/docs/doxygen-user/main.dox b/docs/doxygen-user/main.dox index a72256c7f6..e4a1e2b3a9 100644 --- a/docs/doxygen-user/main.dox +++ b/docs/doxygen-user/main.dox @@ -60,7 +60,6 @@ The following topics are available here: - \subpage windows_authentication - \subpage multiuser_sec_page - \subpage multiuser_page -- \subpage live_triage_page - \subpage advanced_page If the topic you need is not listed, refer to the Autopsy Wiki or join the SleuthKit User List at SourceForge. diff --git a/ruleset.xml b/ruleset.xml index 88bfefaff2..ba1bfa6374 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -57,6 +57,8 @@ + + - + diff --git a/test/script/regression.py b/test/script/regression.py index df8173da88..889365ad3e 100644 --- a/test/script/regression.py +++ b/test/script/regression.py @@ -108,9 +108,6 @@ def main(): if not parse_result: Errors.print_error("The arguments were given wrong") exit(1) - # Remove the output_link_file - if file_exists(OUTPUT_DIR_LINK_FILE): - os.remove(OUTPUT_DIR_LINK_FILE) test_config = TestConfiguration(args) case_type = test_config.userCaseType.lower() @@ -883,7 +880,7 @@ class TestConfiguration(object): #write the output_dir to a html file - linkFile = open(OUTPUT_DIR_LINK_FILE, "a") + linkFile = open(os.path.join(self.args.diff_files_output_folder, OUTPUT_DIR_LINK_FILE), "a") index = self.output_dir.find("\\") linkStr = "Multi test output" + linkStr = linkStr + "\">Enterprise Viking Tests" else: - linkStr = linkStr + "\">Single test output" + linkStr = linkStr + "\">Standalone Viking Tests" linkFile.write(linkStr + "\n") linkFile.close()