From 2cad38f9c708adafecf73fec198a02bb11963a78 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 11 Aug 2020 09:55:35 -0400 Subject: [PATCH 1/6] 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; + } } From 0112be1cbce8bcc5b8e0bf6f2179e7eaddbf9b26 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 12 Aug 2020 12:05:36 -0400 Subject: [PATCH 2/6] Made changes to code per Brian's requests --- .../casemodule/StartupWindowProvider.java | 5 +- .../CommandLineOpenCaseManager.java | 42 +++-- .../CommandLineOptionProcessor.java | 27 +--- .../portablecase/Bundle.properties-MERGED | 1 + .../PortableCaseReportModule.java | 144 ++++++++++-------- 5 files changed, 99 insertions(+), 120 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java b/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java index 1eaa6612a0..907f4bdcd6 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java @@ -151,9 +151,10 @@ public class StartupWindowProvider implements StartupWindowInterface { while (optionsIterator.hasNext()) { // find CommandLineOptionProcessor OptionProcessor processor = optionsIterator.next(); - if ((processor instanceof CommandLineOptionProcessor)) { + if ((processor instanceof OpenFromArguments)) { // check if we are running from command line - return ((CommandLineOptionProcessor) processor).openCaseInUI(); + String arg = ((OpenFromArguments) processor).getDefaultArg(); + return arg != null && !arg.isEmpty(); } } return false; diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOpenCaseManager.java b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOpenCaseManager.java index 0a32168711..d990f2a1cf 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOpenCaseManager.java +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOpenCaseManager.java @@ -18,24 +18,24 @@ */ package org.sleuthkit.autopsy.commandlineingest; +import java.nio.file.Paths; 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.casemodule.OpenFromArguments; import org.sleuthkit.autopsy.coreutils.Logger; /** * Handles the opening of a case from the command line. - * + * */ -public class CommandLineOpenCaseManager extends CommandLineManager{ +public class CommandLineOpenCaseManager extends CommandLineManager { private static final Logger LOGGER = Logger.getLogger(CommandLineOpenCaseManager.class.getName()); - + /** * Starts the thread to open the case. */ @@ -51,7 +51,7 @@ public class CommandLineOpenCaseManager extends CommandLineManager{ @Override public void run() { - List commands = null; + String casePath = ""; // first look up all OptionProcessors and get input data from CommandLineOptionProcessor Collection optionProcessors = Lookup.getDefault().lookupAll(OptionProcessor.class); @@ -59,33 +59,25 @@ public class CommandLineOpenCaseManager extends CommandLineManager{ 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(); + if (processor instanceof OpenFromArguments) { + // check if we are running from command line + casePath = Paths.get(((OpenFromArguments) processor).getDefaultArg()).toAbsolutePath().toString(); break; } } - if (commands == null || commands.isEmpty()) { + if (casePath == null || casePath.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); - } - } + + try { + CommandLineOpenCaseManager.this.openCase(casePath); + LOGGER.log(Level.INFO, "Opening case at " + casePath); + } catch (CaseActionException ex) { + LOGGER.log(Level.SEVERE, "Error opening case from command line ", ex); + System.err.println("Error opening case "); } } diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOptionProcessor.java b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOptionProcessor.java index 5e3f7cf74d..4658158314 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOptionProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOptionProcessor.java @@ -55,7 +55,6 @@ public class CommandLineOptionProcessor extends OptionProcessor { private final Option runUICommandOption = Option.requiredArgument('u', "runUI"); private boolean runFromCommandLine = false; - private boolean openCaseInUI = false; private final List commands = new ArrayList<>(); @@ -90,8 +89,7 @@ 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(runUICommandOption))) { + || values.containsKey(generateReportsOption))) { // 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."); @@ -378,20 +376,6 @@ public class CommandLineOptionProcessor extends OptionProcessor { 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; - } } /** @@ -402,15 +386,6 @@ 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/modules/portablecase/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/Bundle.properties-MERGED index 43f2c32af4..d114cbad3b 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 @@ -43,3 +43,4 @@ PortableCaseReportModule.generateReport.outputDirIsNotDir=Output folder {0} is n PortableCaseReportModule.generateReport.verifying=Verifying selected parameters... PortableCaseReportModule.getDescription.description=Copies selected items to a new single-user case that can be easily shared PortableCaseReportModule.getName.name=Portable Case +PortableCaseReportModule_generateReport_copyingAutopsy=Copying application... 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 fcb97af98a..9128bbce35 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java @@ -169,9 +169,9 @@ public class PortableCaseReportModule implements ReportModule { * exception is supplied then the error is SEVERE. Otherwise it is logged as * a WARNING. * - * @param logWarning Warning to write to the log + * @param logWarning Warning to write to the log * @param dialogWarning Warning to write to a pop-up window - * @param ex The exception (can be null) + * @param ex The exception (can be null) * @param progressPanel The report progress panel */ private void handleError(String logWarning, String dialogWarning, Exception ex, ReportProgressPanel progressPanel) { @@ -211,7 +211,8 @@ public class PortableCaseReportModule implements ReportModule { "PortableCaseReportModule.generateReport.errorCopyingAutopsy=Error copying application", "# {0} - attribute type name", "PortableCaseReportModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}", - "PortableCaseReportModule.generateReport.compressingCase=Compressing case..." + "PortableCaseReportModule.generateReport.compressingCase=Compressing case...", + "PortableCaseReportModule_generateReport_copyingAutopsy=Copying application..." }) public void generateReport(String reportPath, PortableCaseReportModuleSettings options, ReportProgressPanel progressPanel) { @@ -247,6 +248,10 @@ public class PortableCaseReportModule implements ReportModule { return; } + // If the applciation is included add an extra level to the directory structure + if (options.includeApplication()) { + outputDir = Paths.get(outputDir.toString(), caseName).toFile(); + } // Check that there will be something to copy List tagNames; if (options.areAllTagsSelected()) { @@ -422,11 +427,21 @@ public class PortableCaseReportModule implements ReportModule { //Attempt to generate and included the CASE-UCO report. generateCaseUcoReport(tagNames, setNames, progressPanel); + if (options.includeApplication()) { + try { + progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingAutopsy()); + copyApplication(getApplicationBasePath(), outputDir.getAbsolutePath()); + createAppLaunchBatFile(outputDir.getAbsolutePath()); + } catch (IOException ex) { + handleError("Error copying autopsy", Bundle.PortableCaseReportModule_generateReport_errorCopyingAutopsy(), ex, progressPanel); // NON-NLS + } + } + // Compress the case (if desired) if (options.shouldCompress()) { progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_compressingCase()); - boolean success = compressCase(progressPanel); + boolean success = compressCase(progressPanel, options.includeApplication() ? outputDir.getAbsolutePath() : caseFolder.getAbsolutePath()); // Check for cancellation if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { @@ -439,15 +454,6 @@ 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(); @@ -463,8 +469,8 @@ public class PortableCaseReportModule implements ReportModule { * Only one copy of the file will be saved in the report if it is the source * of more than one of the above. * - * @param tagNames TagNames to included in the report. - * @param setNames SET_NAMEs to include in the report. + * @param tagNames TagNames to included in the report. + * @param setNames SET_NAMEs to include in the report. * @param progressPanel ProgressPanel to relay progress messages. */ @NbBundle.Messages({ @@ -518,7 +524,7 @@ public class PortableCaseReportModule implements ReportModule { // Helper flag to ensure each data source is only written once in // a report. boolean dataSourceHasBeenIncluded = false; - + //Search content tags and artifact tags that match for (TagName tagName : tagNames) { for (ContentTag ct : tagsManager.getContentTagsByTagName(tagName, dataSource.getId())) { @@ -577,16 +583,19 @@ public class PortableCaseReportModule implements ReportModule { /** * Adds the content if and only if it has not already been seen. * - * @param content Content to add to the report. - * @param dataSource Parent dataSource of the content instance. - * @param tmpDir Path to the tmpDir to enforce uniqueness + * @param content Content to add to the report. + * @param dataSource Parent dataSource of the content + * instance. + * @param tmpDir Path to the tmpDir to enforce uniqueness * @param gson * @param exporter - * @param reportWriter Report generator instance to add the content to + * @param reportWriter Report generator instance to add the + * content to * @param dataSourceHasBeenIncluded Flag determining if the data source - * should be written to the report (false indicates that it should be written). - * - * @throws IOException If an I/O error occurs. + * should be written to the report (false + * indicates that it should be written). + * + * @throws IOException If an I/O error occurs. * @throws TskCoreException If an internal database error occurs. * * return True if the file was written during this operation. @@ -642,7 +651,7 @@ public class PortableCaseReportModule implements ReportModule { * Create the case directory and case database. portableSkCase will be set * if this completes without error. * - * @param outputDir The parent for the case folder + * @param outputDir The parent for the case folder * @param progressPanel */ @NbBundle.Messages({ @@ -746,7 +755,7 @@ public class PortableCaseReportModule implements ReportModule { /** * Add all files with a given tag to the portable case. * - * @param oldTagName The TagName object from the current case + * @param oldTagName The TagName object from the current case * @param progressPanel The progress panel * * @throws TskCoreException @@ -791,7 +800,7 @@ public class PortableCaseReportModule implements ReportModule { * @param tag The ContentTag in the current case * * @return The app_data string for this content tag or an empty string if - * there was none + * there was none * * @throws TskCoreException */ @@ -840,7 +849,7 @@ public class PortableCaseReportModule implements ReportModule { * Add an image tag to the portable case. * * @param newContentTag The content tag in the portable case - * @param appData The string to copy into app_data + * @param appData The string to copy into app_data * * @throws TskCoreException */ @@ -852,7 +861,7 @@ public class PortableCaseReportModule implements ReportModule { /** * Add all artifacts with a given tag to the portable case. * - * @param oldTagName The TagName object from the current case + * @param oldTagName The TagName object from the current case * @param progressPanel The progress panel * * @throws TskCoreException @@ -888,8 +897,8 @@ public class PortableCaseReportModule implements ReportModule { * Copy an artifact into the new case. Will also copy any associated * artifacts * - * @param newContentId The content ID (in the portable case) of the source - * content + * @param newContentId The content ID (in the portable case) of the source + * content * @param artifactToCopy The artifact to copy * * @return The new artifact in the portable case @@ -1012,7 +1021,7 @@ public class PortableCaseReportModule implements ReportModule { /** * Top level method to copy a content object to the portable case. * - * @param content The content object to copy + * @param content The content object to copy * @param progressPanel The progress panel * * @return The object ID of the copied content in the portable case @@ -1154,19 +1163,19 @@ 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() { @@ -1176,30 +1185,30 @@ public class PortableCaseReportModule implements ReportModule { return Paths.get(installPath, "bin", exeName); } - + /** * Generate the name of the autopsy exe. - * - * @return 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 sourceFolder Autopsy installation directory. * @param destBaseFolder Report base direction. - * @param appName Name of the application being copied. - * - * @throws IOException + * @param appName Name of the application being copied. + * + * @throws IOException */ - private void copyApplication(Path sourceFolder, String destBaseFolder, String appName) throws IOException { + private void copyApplication(Path sourceFolder, String destBaseFolder) throws IOException { // Create an appName folder in the destination - Path destAppFolder = Paths.get(destBaseFolder, appName); + Path destAppFolder = Paths.get(destBaseFolder, UserPreferences.getAppName()); if (!destAppFolder.toFile().exists()) { if (!destAppFolder.toFile().mkdirs()) { throw new IOException("Failed to create directory " + destAppFolder.toString()); @@ -1209,19 +1218,21 @@ public class PortableCaseReportModule implements ReportModule { // 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 + * + * @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 + "\""); + String appName = UserPreferences.getAppName(); + String exePath = "\"%~dp0" + appName + "\\bin\\" + getAutopsyExeName() + "\""; + String casePath = "..\\" + caseName; + try (FileWriter writer = new FileWriter(filePath.toFile())) { + writer.write(exePath + " \"" + casePath + "\""); } } @@ -1253,11 +1264,10 @@ public class PortableCaseReportModule implements ReportModule { } } - /*@Override - public JPanel getConfigurationPanel() { - configPanel = new CreatePortableCasePanel(); - return configPanel; - } */ + /* + * @Override public JPanel getConfigurationPanel() { configPanel = new + * CreatePortableCasePanel(); return configPanel; } + */ private class StoreMaxIdCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { private final String tableName; @@ -1295,14 +1305,14 @@ public class PortableCaseReportModule implements ReportModule { "PortableCaseReportModule.compressCase.errorCreatingTempFolder=Could not create temporary folder {0}", "PortableCaseReportModule.compressCase.errorCompressingCase=Error compressing case", "PortableCaseReportModule.compressCase.canceled=Compression canceled by user",}) - private boolean compressCase(ReportProgressPanel progressPanel) { - - // Close the portable case database (we still need some of the variables that would be cleared by cleanup()) + private boolean compressCase(ReportProgressPanel progressPanel, String folderToCompress) { + closePortableCaseDatabase(); // Make a temporary folder for the compressed case - File tempZipFolder = Paths.get(currentCase.getTempDirectory(), "portableCase" + System.currentTimeMillis()).toFile(); // NON-NLS - if (!tempZipFolder.mkdir()) { + Path dirToCompress = Paths.get(folderToCompress); + File tempZipFolder = Paths.get(dirToCompress.getParent().toString(), "temp", "portableCase" + System.currentTimeMillis()).toFile(); + if (!tempZipFolder.mkdirs()) { handleError("Error creating temporary folder " + tempZipFolder.toString(), Bundle.PortableCaseReportModule_compressCase_errorCreatingTempFolder(tempZipFolder.toString()), null, progressPanel); // NON-NLS return false; @@ -1327,7 +1337,7 @@ public class PortableCaseReportModule implements ReportModule { sevenZipExe.getAbsolutePath(), "a", // Add to archive zipFile.getAbsolutePath(), - caseFolder.getAbsolutePath(), + dirToCompress.toAbsolutePath().toString(), chunkOption ); @@ -1362,9 +1372,9 @@ public class PortableCaseReportModule implements ReportModule { // Delete everything in the case folder then copy over the compressed file(s) try { - FileUtils.cleanDirectory(caseFolder); - FileUtils.copyDirectory(tempZipFolder, caseFolder); - FileUtils.deleteDirectory(tempZipFolder); + FileUtils.cleanDirectory(dirToCompress.toFile()); + FileUtils.copyDirectory(tempZipFolder, dirToCompress.toFile()); + FileUtils.deleteDirectory(new File(tempZipFolder.getParent())); } catch (IOException ex) { handleError("Error compressing case", Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), ex, progressPanel); // NON-NLS return false; From 6ec48296f6a85b0e139a096d0fe1204c22650224 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 12 Aug 2020 14:16:31 -0400 Subject: [PATCH 3/6] Fixed codacy issues --- .../autopsy/commandlineingest/CommandLineManager.java | 6 +++--- .../modules/portablecase/PortableCaseReportModule.java | 6 ++---- .../portablecase/PortableCaseReportModuleSettings.java | 6 +++--- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineManager.java b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineManager.java index cb1d638772..b14dc7f387 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineManager.java +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineManager.java @@ -29,8 +29,8 @@ import org.sleuthkit.autopsy.coreutils.Logger; /** * Base class for the command line managers. */ -abstract class CommandLineManager { - +class CommandLineManager { + private static final Logger LOGGER = Logger.getLogger(CommandLineOpenCaseManager.class.getName()); /** @@ -49,7 +49,7 @@ abstract class CommandLineManager { Case newCase = Case.getCurrentCase(); LOGGER.log(Level.INFO, "Opened case {0}", newCase.getName()); - + return newCase; } 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 9128bbce35..42d086b1d5 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java @@ -1209,10 +1209,8 @@ public class PortableCaseReportModule implements ReportModule { // Create an appName folder in the destination Path destAppFolder = Paths.get(destBaseFolder, UserPreferences.getAppName()); - if (!destAppFolder.toFile().exists()) { - if (!destAppFolder.toFile().mkdirs()) { - throw new IOException("Failed to create directory " + destAppFolder.toString()); - } + if (!destAppFolder.toFile().exists() && !destAppFolder.toFile().mkdirs()) { + throw new IOException("Failed to create directory " + destAppFolder.toString()); } // Now copy the files 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 1c0cab5d2b..1f37b7fd9d 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModuleSettings.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModuleSettings.java @@ -36,7 +36,7 @@ public class PortableCaseReportModuleSettings implements ReportModuleSettings { private ChunkSize chunkSize; private boolean allTagsSelected; private boolean allSetsSelected; - private boolean includeApplication; + private boolean shouldIncludeApplication; /** * Enum for storing the display name for each chunk type and the @@ -144,7 +144,7 @@ public class PortableCaseReportModuleSettings implements ReportModuleSettings { } public boolean includeApplication() { - return includeApplication; + return shouldIncludeApplication; } /** @@ -162,7 +162,7 @@ public class PortableCaseReportModuleSettings implements ReportModuleSettings { } public void setIncludeApplication(boolean includeApplication) { - this.includeApplication = includeApplication; + this.shouldIncludeApplication = includeApplication; } } From c9500e0c8f0d637de233089f7f9c67ab45a837d3 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 12 Aug 2020 14:46:39 -0400 Subject: [PATCH 4/6] More codacy changes --- .../modules/portablecase/PortableCaseReportModule.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) 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 42d086b1d5..a63121a33c 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java @@ -441,18 +441,16 @@ public class PortableCaseReportModule implements ReportModule { if (options.shouldCompress()) { progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_compressingCase()); - boolean success = compressCase(progressPanel, options.includeApplication() ? outputDir.getAbsolutePath() : caseFolder.getAbsolutePath()); + if(!compressCase(progressPanel, options.includeApplication() ? outputDir.getAbsolutePath() : caseFolder.getAbsolutePath())){ + // Errors have been handled already + return; + } // Check for cancellation if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { handleCancellation(progressPanel); return; } - - if (!success) { - // Errors have been handled already - return; - } } // Close the case connections and clear out the maps From 9468830300e6fcd2c65b9b9fd3db380a503ebcb9 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 13 Aug 2020 16:22:40 -0400 Subject: [PATCH 5/6] Changed new checkbox behavior --- ...tWizardPortableCaseOptionsVisualPanel.java | 46 +++++++++++-------- .../PortableCaseReportModule.java | 2 +- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.java index 989e6adb90..fd179189c6 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.java @@ -33,11 +33,13 @@ import org.sleuthkit.autopsy.report.modules.portablecase.PortableCaseReportModul @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { + private static final long serialVersionUID = 1L; + private final ReportWizardPortableCaseOptionsPanel wizPanel; private PortableCaseReportModuleSettings settings = null; - private Map moduleConfigs; + private final Map moduleConfigs; private final boolean useCaseSpecificData; - + /** * Creates new form ReportWizardPortableCaseOptionsVisualPanel */ @@ -48,9 +50,9 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { initComponents(); customizeComponents(); } - + private void customizeComponents() { - + if (!PlatformUtil.isWindowsOS()) { errorLabel.setVisible(true); compressCheckbox.setEnabled(false); @@ -61,7 +63,7 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { for (ChunkSize chunkSize : ChunkSize.values()) { chunkSizeComboBox.addItem(chunkSize); } - + // initialize settings if (moduleConfigs != null) { // get configuration for this module @@ -75,42 +77,42 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { } } } - + if (settings == null) { // get default module configuration settings = new PortableCaseReportModuleSettings(); } - + // update according to input configuration compressCheckbox.setSelected(settings.shouldCompress()); chunkSizeComboBox.setEnabled(settings.shouldCompress()); chunkSizeComboBox.setSelectedItem(settings.getChunkSize()); - + // initialize other panels and pass them the settings - listPanel.setLayout(new GridLayout(1,2)); + listPanel.setLayout(new GridLayout(1, 2)); listPanel.add(new PortableCaseTagsListPanel(wizPanel, settings, useCaseSpecificData)); listPanel.add(new PortableCaseInterestingItemsListPanel(wizPanel, settings, useCaseSpecificData)); } - + @NbBundle.Messages({ - "ReportWizardPortableCaseOptionsVisualPanel.getName.title=Choose Portable Case settings", - }) + "ReportWizardPortableCaseOptionsVisualPanel.getName.title=Choose Portable Case settings",}) @Override public String getName() { return Bundle.ReportWizardPortableCaseOptionsVisualPanel_getName_title(); } - + /** * Get the selected chunk size - * + * * @return the chunk size that was selected */ private ChunkSize getChunkSize() { return (ChunkSize) chunkSizeComboBox.getSelectedItem(); } - + /** - * Update the selected compression options and enable/disable the finish button + * Update the selected compression options and enable/disable the finish + * button */ private void updateCompression() { if (settings != null) { @@ -118,7 +120,7 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { wizPanel.setFinish(settings.isValid()); } } - + /** * Update the include application option. */ @@ -127,7 +129,7 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { settings.setIncludeApplication(includeAppCheckbox.isSelected()); } } - + /** * Get the user-selected settings. * @@ -135,7 +137,7 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { */ PortableCaseReportModuleSettings getPortableCaseReportSettings() { return settings; - } + } /** * This method is called from within the constructor to initialize the form. @@ -245,6 +247,12 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { }//GEN-LAST:event_compressCheckboxActionPerformed private void includeAppCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_includeAppCheckboxActionPerformed + if (includeAppCheckbox.isSelected()) { + chunkSizeComboBox.setEnabled(false); + chunkSizeComboBox.setSelectedItem(ChunkSize.NONE); + } else { + chunkSizeComboBox.setEnabled(compressCheckbox.isSelected()); + } updateIncludeApplication(); }//GEN-LAST:event_includeAppCheckboxActionPerformed 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 a63121a33c..3843eb29f4 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java @@ -1218,7 +1218,7 @@ public class PortableCaseReportModule implements ReportModule { /** * Create a bat file at destBaseFolder that will launch the portable case. * - * @param destBaseFolder + * @param destBaseFolder Folder to create the bat file in. * * @throws IOException */ From 95cbeb2530987c6470dc785e60d638b00fd8b8bd Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 19 Aug 2020 15:19:27 -0400 Subject: [PATCH 6/6] Small changed based on review comment --- .../ReportWizardPortableCaseOptionsVisualPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.java index fd179189c6..4967431884 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardPortableCaseOptionsVisualPanel.java @@ -242,7 +242,7 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { }//GEN-LAST:event_chunkSizeComboBoxActionPerformed private void compressCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_compressCheckboxActionPerformed - chunkSizeComboBox.setEnabled(compressCheckbox.isSelected()); + chunkSizeComboBox.setEnabled(compressCheckbox.isSelected() && !includeAppCheckbox.isSelected()); updateCompression(); }//GEN-LAST:event_compressCheckboxActionPerformed