From 2cad38f9c708adafecf73fec198a02bb11963a78 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 11 Aug 2020 09:55:35 -0400 Subject: [PATCH] Added support for new command -runUI --- .../casemodule/StartupWindowProvider.java | 28 ++++++ .../commandlineingest/CommandLineCommand.java | 3 +- .../CommandLineIngestManager.java | 59 +----------- .../commandlineingest/CommandLineManager.java | 87 +++++++++++++++++ .../CommandLineOpenCaseManager.java | 93 +++++++++++++++++++ .../CommandLineOptionProcessor.java | 31 ++++++- .../report/infrastructure/Bundle.properties | 1 + .../infrastructure/Bundle.properties-MERGED | 1 + ...tWizardPortableCaseOptionsVisualPanel.form | 39 +++++--- ...tWizardPortableCaseOptionsVisualPanel.java | 69 +++++++++----- .../portablecase/Bundle.properties-MERGED | 1 + .../PortableCaseReportModule.java | 82 ++++++++++++++++ .../PortableCaseReportModuleSettings.java | 11 ++- 13 files changed, 415 insertions(+), 90 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineManager.java create mode 100755 Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOpenCaseManager.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java b/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java index 8bec55f53c..1eaa6612a0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java @@ -24,6 +24,7 @@ import java.util.logging.Level; import org.netbeans.spi.sendopts.OptionProcessor; import org.openide.util.Lookup; import org.sleuthkit.autopsy.commandlineingest.CommandLineIngestManager; +import org.sleuthkit.autopsy.commandlineingest.CommandLineOpenCaseManager; import org.sleuthkit.autopsy.commandlineingest.CommandLineOptionProcessor; import org.sleuthkit.autopsy.commandlineingest.CommandLineStartupWindow; import org.sleuthkit.autopsy.coreutils.Logger; @@ -58,6 +59,12 @@ public class StartupWindowProvider implements StartupWindowInterface { private void init() { if (startupWindowToUse == null) { + + if (openCaseInUI()) { + new CommandLineOpenCaseManager().start(); + return; + } + // first check whether we are running from command line if (isRunningFromCommandLine()) { // Autopsy is running from command line @@ -131,6 +138,27 @@ public class StartupWindowProvider implements StartupWindowInterface { return false; } + /** + * Checks whether Autopsy was launched from the command line with the option + * to open an existing case. + * + * @return True if opening an existing case. + */ + private boolean openCaseInUI() { + // first look up all OptionProcessors and see if running from command line option is set + Collection optionProcessors = Lookup.getDefault().lookupAll(OptionProcessor.class); + Iterator optionsIterator = optionProcessors.iterator(); + while (optionsIterator.hasNext()) { + // find CommandLineOptionProcessor + OptionProcessor processor = optionsIterator.next(); + if ((processor instanceof CommandLineOptionProcessor)) { + // check if we are running from command line + return ((CommandLineOptionProcessor) processor).openCaseInUI(); + } + } + return false; + } + @Override public void open() { if (startupWindowToUse != null) { diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineCommand.java b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineCommand.java index 29d3a2e9c5..d9a0c04234 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineCommand.java +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineCommand.java @@ -34,7 +34,8 @@ class CommandLineCommand { ADD_DATA_SOURCE, RUN_INGEST, LIST_ALL_DATA_SOURCES, - GENERATE_REPORTS; + GENERATE_REPORTS, + OPEN_CASE_IN_UI; } /** diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestManager.java b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestManager.java index f5d9a5c641..a608d4a770 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestManager.java @@ -74,7 +74,7 @@ import org.sleuthkit.datamodel.TskCoreException; * cause Autopsy to create a case, add a specified data source, run ingest on * that data source, list all data sources in the case, and generate reports. */ -public class CommandLineIngestManager { +public class CommandLineIngestManager extends CommandLineManager{ private static final Logger LOGGER = Logger.getLogger(CommandLineIngestManager.class.getName()); private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.CANCELLED, IngestManager.IngestJobEvent.COMPLETED); @@ -184,7 +184,7 @@ public class CommandLineIngestManager { // open the case, if it hasn't been already opened by CREATE_CASE command if (caseForJob == null) { String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name()); - openCase(caseDirPath); + caseForJob = CommandLineIngestManager.this.openCase(caseDirPath); } String dataSourcePath = inputs.get(CommandLineCommand.InputType.DATA_SOURCE_PATH.name()); @@ -210,7 +210,7 @@ public class CommandLineIngestManager { // open the case, if it hasn't been already opened by CREATE_CASE or ADD_DATA_SOURCE commands if (caseForJob == null) { String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name()); - openCase(caseDirPath); + caseForJob = CommandLineIngestManager.this.openCase(caseDirPath); } // populate the AutoIngestDataSource structure, if that hasn't been done by ADD_DATA_SOURCE command @@ -265,7 +265,7 @@ public class CommandLineIngestManager { // open the case, if it hasn't been already opened by previous command if (caseForJob == null) { String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name()); - openCase(caseDirPath); + caseForJob = CommandLineIngestManager.this.openCase(caseDirPath); } String outputDirPath = getOutputDirPath(caseForJob); @@ -288,7 +288,7 @@ public class CommandLineIngestManager { // open the case, if it hasn't been already opened by previous command if (caseForJob == null) { String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name()); - openCase(caseDirPath); + caseForJob = CommandLineIngestManager.this.openCase(caseDirPath); } // generate reports @@ -369,55 +369,6 @@ public class CommandLineIngestManager { LOGGER.log(Level.INFO, "Opened case {0}", caseForJob.getName()); } - /** - * Opens existing case. - * - * @param caseFolderPath full path to case directory - * - * @throws CaseActionException - */ - private void openCase(String caseFolderPath) throws CaseActionException { - - LOGGER.log(Level.INFO, "Opening case in directory {0}", caseFolderPath); - - String metadataFilePath = findAutFile(caseFolderPath); - Case.openAsCurrentCase(metadataFilePath); - - caseForJob = Case.getCurrentCase(); - LOGGER.log(Level.INFO, "Opened case {0}", caseForJob.getName()); - } - - /** - * Finds the path to the .aut file for the specified case directory. - * - * @param caseDirectory the directory to check for a .aut file - * - * @return the path to the first .aut file found in the directory - * - * @throws CaseActionException if there was an issue finding a .aut file - */ - private String findAutFile(String caseDirectory) throws CaseActionException { - File caseFolder = Paths.get(caseDirectory).toFile(); - if (caseFolder.exists()) { - /* - * Search for '*.aut' files. - */ - File[] fileArray = caseFolder.listFiles(); - if (fileArray == null) { - throw new CaseActionException("No files found in case directory"); - } - String autFilePath = null; - for (File file : fileArray) { - String name = file.getName().toLowerCase(); - if (autFilePath == null && name.endsWith(getFileExtension())) { - return file.getAbsolutePath(); - } - } - throw new CaseActionException("No .aut files found in case directory"); - } - throw new CaseActionException("Case directory was not found"); - } - /** * Passes the data source for the current job through a data source * processor that adds it to the case database. diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineManager.java b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineManager.java new file mode 100755 index 0000000000..cb1d638772 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineManager.java @@ -0,0 +1,87 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 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.commandlineingest; + +import java.io.File; +import java.nio.file.Paths; +import java.util.logging.Level; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.CaseActionException; +import static org.sleuthkit.autopsy.casemodule.CaseMetadata.getFileExtension; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * Base class for the command line managers. + */ +abstract class CommandLineManager { + + private static final Logger LOGGER = Logger.getLogger(CommandLineOpenCaseManager.class.getName()); + + /** + * Opens existing case. + * + * @param caseFolderPath full path to case directory + * + * @throws CaseActionException + */ + Case openCase(String caseFolderPath) throws CaseActionException { + + LOGGER.log(Level.INFO, "Opening case in directory {0}", caseFolderPath); + + String metadataFilePath = findAutFile(caseFolderPath); + Case.openAsCurrentCase(metadataFilePath); + + Case newCase = Case.getCurrentCase(); + LOGGER.log(Level.INFO, "Opened case {0}", newCase.getName()); + + return newCase; + } + + /** + * Finds the path to the .aut file for the specified case directory. + * + * @param caseDirectory the directory to check for a .aut file + * + * @return the path to the first .aut file found in the directory + * + * @throws CaseActionException if there was an issue finding a .aut file + */ + private String findAutFile(String caseDirectory) throws CaseActionException { + File caseFolder = Paths.get(caseDirectory).toFile(); + if (caseFolder.exists()) { + /* + * Search for '*.aut' files. + */ + File[] fileArray = caseFolder.listFiles(); + if (fileArray == null) { + throw new CaseActionException("No files found in case directory"); + } + String autFilePath = null; + for (File file : fileArray) { + String name = file.getName().toLowerCase(); + if (autFilePath == null && name.endsWith(getFileExtension())) { + return file.getAbsolutePath(); + } + } + throw new CaseActionException("No .aut files found in case directory"); + } + throw new CaseActionException("Case directory was not found"); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOpenCaseManager.java b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOpenCaseManager.java new file mode 100755 index 0000000000..0a32168711 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOpenCaseManager.java @@ -0,0 +1,93 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 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.commandlineingest; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import org.netbeans.spi.sendopts.OptionProcessor; +import org.openide.util.Lookup; +import org.sleuthkit.autopsy.casemodule.CaseActionException; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * Handles the opening of a case from the command line. + * + */ +public class CommandLineOpenCaseManager extends CommandLineManager{ + + private static final Logger LOGGER = Logger.getLogger(CommandLineOpenCaseManager.class.getName()); + + /** + * Starts the thread to open the case. + */ + public void start() { + new Thread(new CommandLineOpenCaseManager.JobProcessingTask()).start(); + } + + /** + * A runnable class that open the given class in the list of command line + * options. + */ + private final class JobProcessingTask implements Runnable { + + @Override + public void run() { + List commands = null; + + // first look up all OptionProcessors and get input data from CommandLineOptionProcessor + Collection optionProcessors = Lookup.getDefault().lookupAll(OptionProcessor.class); + Iterator optionsIterator = optionProcessors.iterator(); + while (optionsIterator.hasNext()) { + // find CommandLineOptionProcessor + OptionProcessor processor = optionsIterator.next(); + if (processor instanceof CommandLineOptionProcessor) { + // check if we are running from command line + commands = ((CommandLineOptionProcessor) processor).getCommands(); + break; + } + } + + if (commands == null || commands.isEmpty()) { + LOGGER.log(Level.SEVERE, "No command line commands specified"); + System.err.println("No command line commands specified"); + return; + } + + String casePath; + for (CommandLineCommand command : commands) { + CommandLineCommand.CommandType type = command.getType(); + if(type.equals(CommandLineCommand.CommandType.OPEN_CASE_IN_UI)) { + try { + Map inputs = command.getInputs(); + casePath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name()); + CommandLineOpenCaseManager.this.openCase(casePath); + } catch (CaseActionException ex) { + String baseCaseName = command.getInputs().get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name()); + LOGGER.log(Level.SEVERE, "Error opening case " + baseCaseName, ex); + System.err.println("Error opening case " + baseCaseName); + } + } + } + } + + } +} diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOptionProcessor.java b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOptionProcessor.java index f23bd5f483..5e3f7cf74d 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOptionProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOptionProcessor.java @@ -52,8 +52,10 @@ public class CommandLineOptionProcessor extends OptionProcessor { private final Option ingestProfileOption = Option.requiredArgument('p', "ingestProfile"); private final Option listAllDataSourcesCommandOption = Option.withoutArgument('l', "listAllDataSources"); private final Option generateReportsOption = Option.withoutArgument('g', "generateReports"); + private final Option runUICommandOption = Option.requiredArgument('u', "runUI"); private boolean runFromCommandLine = false; + private boolean openCaseInUI = false; private final List commands = new ArrayList<>(); @@ -75,6 +77,7 @@ public class CommandLineOptionProcessor extends OptionProcessor { set.add(ingestProfileOption); set.add(listAllDataSourcesCommandOption); set.add(generateReportsOption); + set.add(runUICommandOption); return set; } @@ -87,7 +90,8 @@ public class CommandLineOptionProcessor extends OptionProcessor { // input arguments must contain at least one command if (!(values.containsKey(createCaseCommandOption) || values.containsKey(addDataSourceCommandOption) || values.containsKey(runIngestCommandOption) || values.containsKey(listAllDataSourcesCommandOption) - || values.containsKey(generateReportsOption))) { + || values.containsKey(generateReportsOption) + || values.containsKey(runUICommandOption))) { // not running from command line logger.log(Level.INFO, "No command line commands passed in as inputs. Not running from command line."); //NON-NLS System.err.println("No command line commands passed in as inputs. Not running from command line."); @@ -373,7 +377,21 @@ public class CommandLineOptionProcessor extends OptionProcessor { newCommand.addInputValue(CommandLineCommand.InputType.CASE_FOLDER_PATH.name(), caseDir); commands.add(newCommand); runFromCommandLine = true; - } + } + + if(values.containsKey(runUICommandOption)) { + argDirs = values.get(runUICommandOption); + if (argDirs.length < 1) { + logger.log(Level.SEVERE, "Missing argument 'runUI'"); + System.err.println("Missing argument 'runUI'"); + return; + } + String casePath = argDirs[0]; + CommandLineCommand newCommand = new CommandLineCommand(CommandLineCommand.CommandType.OPEN_CASE_IN_UI); + newCommand.addInputValue(CommandLineCommand.InputType.CASE_FOLDER_PATH.name(), casePath); + commands.add(newCommand); + openCaseInUI = true; + } } /** @@ -384,6 +402,15 @@ public class CommandLineOptionProcessor extends OptionProcessor { public boolean isRunFromCommandLine() { return runFromCommandLine; } + + /** + * Returns whether Autopsy should open existing case in the user interface. + * + * @return true if opening an existing case, false otherwise. + */ + public boolean openCaseInUI() { + return openCaseInUI; + } /** * Returns list of all commands passed in via command line. diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties index cdab8b0cfa..3c5130c22e 100755 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties @@ -199,3 +199,4 @@ FileReportDataTypes.hash.text=Hash Value FileReportDataTypes.knownStatus.text=Known Status FileReportDataTypes.perms.text=Permissions FileReportDataTypes.path.text=Full Path +ReportWizardPortableCaseOptionsVisualPanel.includeAppCheckbox.text=Include application in folder (may add up to 1GB of files) diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties-MERGED index 40dc146e1d..5dcbb7f7dd 100755 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/Bundle.properties-MERGED @@ -220,4 +220,5 @@ FileReportDataTypes.knownStatus.text=Known Status FileReportDataTypes.perms.text=Permissions FileReportDataTypes.path.text=Full Path ReportWizardPortableCaseOptionsVisualPanel.getName.title=Choose Portable Case settings +ReportWizardPortableCaseOptionsVisualPanel.includeAppCheckbox.text=Include application in folder (may add up to 1GB of files) TableReportGenerator.StatusColumn.Header=Review Status diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.form b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.form index 9359e187d4..4d404676e0 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.form +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.form @@ -18,7 +18,7 @@ - + @@ -26,27 +26,32 @@ - + - + - + + - - - - - + + + + + + + + + + - @@ -60,6 +65,8 @@ + + @@ -106,11 +113,21 @@ - + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.java index 72ffd4b8de..989e6adb90 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.java @@ -119,6 +119,15 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { } } + /** + * Update the include application option. + */ + private void updateIncludeApplication() { + if (settings != null) { + settings.setIncludeApplication(includeAppCheckbox.isSelected()); + } + } + /** * Get the user-selected settings. * @@ -137,11 +146,12 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { // //GEN-BEGIN:initComponents private void initComponents() { - jPanel1 = new javax.swing.JPanel(); + mainPanel = new javax.swing.JPanel(); chunkSizeComboBox = new javax.swing.JComboBox<>(); compressCheckbox = new javax.swing.JCheckBox(); errorLabel = new javax.swing.JLabel(); listPanel = new javax.swing.JPanel(); + includeAppCheckbox = new javax.swing.JCheckBox(); chunkSizeComboBox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -168,32 +178,44 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { ); listPanelLayout.setVerticalGroup( listPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 217, Short.MAX_VALUE) + .addGap(0, 190, Short.MAX_VALUE) ); - javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); - jPanel1.setLayout(jPanel1Layout); - jPanel1Layout.setHorizontalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(compressCheckbox) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(chunkSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 187, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(errorLabel) - .addContainerGap(41, Short.MAX_VALUE)) + org.openide.awt.Mnemonics.setLocalizedText(includeAppCheckbox, org.openide.util.NbBundle.getMessage(ReportWizardPortableCaseOptionsVisualPanel.class, "ReportWizardPortableCaseOptionsVisualPanel.includeAppCheckbox.text")); // NOI18N + includeAppCheckbox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + includeAppCheckboxActionPerformed(evt); + } + }); + + javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel); + mainPanel.setLayout(mainPanelLayout); + mainPanelLayout.setHorizontalGroup( + mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(listPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(mainPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(mainPanelLayout.createSequentialGroup() + .addComponent(compressCheckbox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(chunkSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 187, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(errorLabel)) + .addComponent(includeAppCheckbox)) + .addContainerGap(41, Short.MAX_VALUE)) ); - jPanel1Layout.setVerticalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() + mainPanelLayout.setVerticalGroup( + mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(mainPanelLayout.createSequentialGroup() .addComponent(listPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(compressCheckbox) .addComponent(chunkSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(errorLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(includeAppCheckbox) .addContainerGap()) ); @@ -203,13 +225,13 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 463, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(mainPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 259, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(mainPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -222,12 +244,17 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { updateCompression(); }//GEN-LAST:event_compressCheckboxActionPerformed + private void includeAppCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_includeAppCheckboxActionPerformed + updateIncludeApplication(); + }//GEN-LAST:event_includeAppCheckboxActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JComboBox chunkSizeComboBox; private javax.swing.JCheckBox compressCheckbox; private javax.swing.JLabel errorLabel; - private javax.swing.JPanel jPanel1; + private javax.swing.JCheckBox includeAppCheckbox; private javax.swing.JPanel listPanel; + private javax.swing.JPanel mainPanel; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/Bundle.properties-MERGED index ba4b89820d..43f2c32af4 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/Bundle.properties-MERGED @@ -24,6 +24,7 @@ PortableCaseReportModule.generateReport.copyingFiles=Copying files tagged as {0} PortableCaseReportModule.generateReport.copyingTags=Copying tags... PortableCaseReportModule.generateReport.creatingCase=Creating portable case database... PortableCaseReportModule.generateReport.errorCopyingArtifacts=Error copying tagged artifacts +PortableCaseReportModule.generateReport.errorCopyingAutopsy=Error copying application PortableCaseReportModule.generateReport.errorCopyingFiles=Error copying tagged files PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java index c97183c31a..fcb97af98a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java @@ -29,6 +29,7 @@ import java.util.logging.Level; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; +import java.io.FileWriter; import java.io.InputStreamReader; import java.io.IOException; import java.io.OutputStream; @@ -50,6 +51,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager; +import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; @@ -206,6 +208,7 @@ public class PortableCaseReportModule implements ReportModule { "PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files", "PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results", "PortableCaseReportModule.generateReport.errorCreatingImageTagTable=Error creating image tags table", + "PortableCaseReportModule.generateReport.errorCopyingAutopsy=Error copying application", "# {0} - attribute type name", "PortableCaseReportModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}", "PortableCaseReportModule.generateReport.compressingCase=Compressing case..." @@ -436,6 +439,15 @@ public class PortableCaseReportModule implements ReportModule { return; } } + + if(options.includeApplication()) { + try { + copyApplication(getApplicationBasePath(), reportPath, "autopsy"); + createAppLaunchBatFile(reportPath); + } catch (IOException ex) { + handleError("Error copying autopsy", Bundle.PortableCaseReportModule_generateReport_errorCopyingAutopsy(), ex, progressPanel); // NON-NLS + } + } // Close the case connections and clear out the maps cleanup(); @@ -1142,6 +1154,76 @@ public class PortableCaseReportModule implements ReportModule { } return UNKNOWN_FILE_TYPE_FOLDER; } + + /** + * Returns base path of the users autopsy installation. + * + * @return Path of autopsy installation. + */ + private Path getApplicationBasePath() { + return getAutopsyExePath().getParent().getParent(); + } + + /** + * Find the path of the installed version of autopsy. + * + * @return Path to the installed autopsy.exe. + */ + private Path getAutopsyExePath() { + // If this is an installed version, there should be an 64.exe file in the bin folder + String exeName = getAutopsyExeName(); + String installPath = PlatformUtil.getInstallPath(); + + return Paths.get(installPath, "bin", exeName); + } + + /** + * Generate the name of the autopsy exe. + * + * @return The name of the autopsy exe. + */ + private String getAutopsyExeName() { + String appName = UserPreferences.getAppName(); + return appName + "64.exe"; + } + + /** + * Copy the sorceFolder to destBaseFolder\appName. + * + * @param sourceFolder Autopsy installation directory. + * @param destBaseFolder Report base direction. + * @param appName Name of the application being copied. + * + * @throws IOException + */ + private void copyApplication(Path sourceFolder, String destBaseFolder, String appName) throws IOException { + + // Create an appName folder in the destination + Path destAppFolder = Paths.get(destBaseFolder, appName); + if (!destAppFolder.toFile().exists()) { + if (!destAppFolder.toFile().mkdirs()) { + throw new IOException("Failed to create directory " + destAppFolder.toString()); + } + } + + // Now copy the files + FileUtils.copyDirectory(sourceFolder.toFile(), destAppFolder.toFile()); + } + + /** + * Create a bat file at destBaseFolder that will launch the portable case. + * + * @param destBaseFolder + * @throws IOException + */ + private void createAppLaunchBatFile(String destBaseFolder) throws IOException { + Path filePath = Paths.get(destBaseFolder, "open.bat"); + String exePath = "\"%~dp0autopsy\\bin\\" + getAutopsyExeName() + "\""; + String casePath = ".\\" + caseName ; + try(FileWriter writer = new FileWriter(filePath.toFile())) { + writer.write(exePath + " --caseDir \" " + casePath + "\""); + } + } /** * Clear out the maps and other fields and close the database connections. diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModuleSettings.java b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModuleSettings.java index b3d1dea9e0..1c0cab5d2b 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModuleSettings.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModuleSettings.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,6 +36,7 @@ public class PortableCaseReportModuleSettings implements ReportModuleSettings { private ChunkSize chunkSize; private boolean allTagsSelected; private boolean allSetsSelected; + private boolean includeApplication; /** * Enum for storing the display name for each chunk type and the @@ -141,6 +142,10 @@ public class PortableCaseReportModuleSettings implements ReportModuleSettings { public boolean areAllSetsSelected() { return allSetsSelected; } + + public boolean includeApplication() { + return includeApplication; + } /** * @param allTagsSelected the allTagsSelected to set @@ -155,5 +160,9 @@ public class PortableCaseReportModuleSettings implements ReportModuleSettings { public void setAllSetsSelected(boolean allSetsSelected) { this.allSetsSelected = allSetsSelected; } + + public void setIncludeApplication(boolean includeApplication) { + this.includeApplication = includeApplication; + } }