Merge pull request #6174 from kellykelly3/6682-autopsy-in-portable-case

6682 autopsy in portable case
This commit is contained in:
Richard Cordovano 2020-08-20 10:16:26 -04:00 committed by GitHub
commit f9007c481d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 457 additions and 149 deletions

View File

@ -24,6 +24,7 @@ import java.util.logging.Level;
import org.netbeans.spi.sendopts.OptionProcessor; import org.netbeans.spi.sendopts.OptionProcessor;
import org.openide.util.Lookup; import org.openide.util.Lookup;
import org.sleuthkit.autopsy.commandlineingest.CommandLineIngestManager; import org.sleuthkit.autopsy.commandlineingest.CommandLineIngestManager;
import org.sleuthkit.autopsy.commandlineingest.CommandLineOpenCaseManager;
import org.sleuthkit.autopsy.commandlineingest.CommandLineOptionProcessor; import org.sleuthkit.autopsy.commandlineingest.CommandLineOptionProcessor;
import org.sleuthkit.autopsy.commandlineingest.CommandLineStartupWindow; import org.sleuthkit.autopsy.commandlineingest.CommandLineStartupWindow;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -58,6 +59,12 @@ public class StartupWindowProvider implements StartupWindowInterface {
private void init() { private void init() {
if (startupWindowToUse == null) { if (startupWindowToUse == null) {
if (openCaseInUI()) {
new CommandLineOpenCaseManager().start();
return;
}
// first check whether we are running from command line // first check whether we are running from command line
if (isRunningFromCommandLine()) { if (isRunningFromCommandLine()) {
// Autopsy is running from command line // Autopsy is running from command line
@ -131,6 +138,28 @@ public class StartupWindowProvider implements StartupWindowInterface {
return false; 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<? extends OptionProcessor> optionProcessors = Lookup.getDefault().lookupAll(OptionProcessor.class);
Iterator<? extends OptionProcessor> optionsIterator = optionProcessors.iterator();
while (optionsIterator.hasNext()) {
// find CommandLineOptionProcessor
OptionProcessor processor = optionsIterator.next();
if ((processor instanceof OpenFromArguments)) {
// check if we are running from command line
String arg = ((OpenFromArguments) processor).getDefaultArg();
return arg != null && !arg.isEmpty();
}
}
return false;
}
@Override @Override
public void open() { public void open() {
if (startupWindowToUse != null) { if (startupWindowToUse != null) {

View File

@ -34,7 +34,8 @@ class CommandLineCommand {
ADD_DATA_SOURCE, ADD_DATA_SOURCE,
RUN_INGEST, RUN_INGEST,
LIST_ALL_DATA_SOURCES, LIST_ALL_DATA_SOURCES,
GENERATE_REPORTS; GENERATE_REPORTS,
OPEN_CASE_IN_UI;
} }
/** /**

View File

@ -74,7 +74,7 @@ import org.sleuthkit.datamodel.TskCoreException;
* cause Autopsy to create a case, add a specified data source, run ingest on * 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. * 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 Logger LOGGER = Logger.getLogger(CommandLineIngestManager.class.getName());
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.CANCELLED, IngestManager.IngestJobEvent.COMPLETED); private static final Set<IngestManager.IngestJobEvent> 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 // open the case, if it hasn't been already opened by CREATE_CASE command
if (caseForJob == null) { if (caseForJob == null) {
String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name()); 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()); 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 // open the case, if it hasn't been already opened by CREATE_CASE or ADD_DATA_SOURCE commands
if (caseForJob == null) { if (caseForJob == null) {
String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name()); 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 // 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 // open the case, if it hasn't been already opened by previous command
if (caseForJob == null) { if (caseForJob == null) {
String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name()); String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name());
openCase(caseDirPath); caseForJob = CommandLineIngestManager.this.openCase(caseDirPath);
} }
String outputDirPath = getOutputDirPath(caseForJob); String outputDirPath = getOutputDirPath(caseForJob);
@ -288,7 +288,7 @@ public class CommandLineIngestManager {
// open the case, if it hasn't been already opened by previous command // open the case, if it hasn't been already opened by previous command
if (caseForJob == null) { if (caseForJob == null) {
String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name()); String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name());
openCase(caseDirPath); caseForJob = CommandLineIngestManager.this.openCase(caseDirPath);
} }
// generate reports // generate reports
@ -369,55 +369,6 @@ public class CommandLineIngestManager {
LOGGER.log(Level.INFO, "Opened case {0}", caseForJob.getName()); 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 * Passes the data source for the current job through a data source
* processor that adds it to the case database. * processor that adds it to the case database.

View File

@ -0,0 +1,87 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.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.
*/
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");
}
}

View File

@ -0,0 +1,85 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.commandlineingest;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Iterator;
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 {
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() {
String casePath = "";
// first look up all OptionProcessors and get input data from CommandLineOptionProcessor
Collection<? extends OptionProcessor> optionProcessors = Lookup.getDefault().lookupAll(OptionProcessor.class);
Iterator<? extends OptionProcessor> optionsIterator = optionProcessors.iterator();
while (optionsIterator.hasNext()) {
// find CommandLineOptionProcessor
OptionProcessor processor = optionsIterator.next();
if (processor instanceof OpenFromArguments) {
// check if we are running from command line
casePath = Paths.get(((OpenFromArguments) processor).getDefaultArg()).toAbsolutePath().toString();
break;
}
}
if (casePath == null || casePath.isEmpty()) {
LOGGER.log(Level.SEVERE, "No command line commands specified");
System.err.println("No command line commands specified");
return;
}
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 ");
}
}
}
}

View File

@ -52,6 +52,7 @@ public class CommandLineOptionProcessor extends OptionProcessor {
private final Option ingestProfileOption = Option.requiredArgument('p', "ingestProfile"); private final Option ingestProfileOption = Option.requiredArgument('p', "ingestProfile");
private final Option listAllDataSourcesCommandOption = Option.withoutArgument('l', "listAllDataSources"); private final Option listAllDataSourcesCommandOption = Option.withoutArgument('l', "listAllDataSources");
private final Option generateReportsOption = Option.withoutArgument('g', "generateReports"); private final Option generateReportsOption = Option.withoutArgument('g', "generateReports");
private final Option runUICommandOption = Option.requiredArgument('u', "runUI");
private boolean runFromCommandLine = false; private boolean runFromCommandLine = false;
@ -75,6 +76,7 @@ public class CommandLineOptionProcessor extends OptionProcessor {
set.add(ingestProfileOption); set.add(ingestProfileOption);
set.add(listAllDataSourcesCommandOption); set.add(listAllDataSourcesCommandOption);
set.add(generateReportsOption); set.add(generateReportsOption);
set.add(runUICommandOption);
return set; return set;
} }
@ -373,7 +375,7 @@ public class CommandLineOptionProcessor extends OptionProcessor {
newCommand.addInputValue(CommandLineCommand.InputType.CASE_FOLDER_PATH.name(), caseDir); newCommand.addInputValue(CommandLineCommand.InputType.CASE_FOLDER_PATH.name(), caseDir);
commands.add(newCommand); commands.add(newCommand);
runFromCommandLine = true; runFromCommandLine = true;
} }
} }
/** /**

View File

@ -199,3 +199,4 @@ FileReportDataTypes.hash.text=Hash Value
FileReportDataTypes.knownStatus.text=Known Status FileReportDataTypes.knownStatus.text=Known Status
FileReportDataTypes.perms.text=Permissions FileReportDataTypes.perms.text=Permissions
FileReportDataTypes.path.text=Full Path FileReportDataTypes.path.text=Full Path
ReportWizardPortableCaseOptionsVisualPanel.includeAppCheckbox.text=Include application in folder (may add up to 1GB of files)

View File

@ -220,4 +220,5 @@ FileReportDataTypes.knownStatus.text=Known Status
FileReportDataTypes.perms.text=Permissions FileReportDataTypes.perms.text=Permissions
FileReportDataTypes.path.text=Full Path FileReportDataTypes.path.text=Full Path
ReportWizardPortableCaseOptionsVisualPanel.getName.title=Choose Portable Case settings 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 TableReportGenerator.StatusColumn.Header=Review Status

View File

@ -18,7 +18,7 @@
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="463" max="32767" attributes="0"/> <EmptySpace min="0" pref="463" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0"> <Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="jPanel1" alignment="0" max="32767" attributes="0"/> <Component id="mainPanel" alignment="0" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -26,27 +26,32 @@
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="259" max="32767" attributes="0"/> <EmptySpace min="0" pref="259" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0"> <Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="jPanel1" alignment="0" max="32767" attributes="0"/> <Component id="mainPanel" alignment="0" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
</Layout> </Layout>
<SubComponents> <SubComponents>
<Container class="javax.swing.JPanel" name="jPanel1"> <Container class="javax.swing.JPanel" name="mainPanel">
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Component id="listPanel" alignment="1" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="compressCheckbox" min="-2" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/> <Group type="102" alignment="0" attributes="0">
<Component id="chunkSizeComboBox" min="-2" pref="187" max="-2" attributes="0"/> <Component id="compressCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="errorLabel" min="-2" max="-2" attributes="0"/> <Component id="chunkSizeComboBox" min="-2" pref="187" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="includeAppCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="41" max="32767" attributes="0"/> <EmptySpace pref="41" max="32767" attributes="0"/>
</Group> </Group>
<Component id="listPanel" alignment="1" max="32767" attributes="0"/>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
<DimensionLayout dim="1"> <DimensionLayout dim="1">
@ -60,6 +65,8 @@
<Component id="errorLabel" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="errorLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="includeAppCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -106,11 +113,21 @@
</DimensionLayout> </DimensionLayout>
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="217" max="32767" attributes="0"/> <EmptySpace min="0" pref="190" max="32767" attributes="0"/>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
</Layout> </Layout>
</Container> </Container>
<Component class="javax.swing.JCheckBox" name="includeAppCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/report/infrastructure/Bundle.properties" key="ReportWizardPortableCaseOptionsVisualPanel.includeAppCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="includeAppCheckboxActionPerformed"/>
</Events>
</Component>
</SubComponents> </SubComponents>
</Container> </Container>
</SubComponents> </SubComponents>

View File

@ -33,11 +33,13 @@ import org.sleuthkit.autopsy.report.modules.portablecase.PortableCaseReportModul
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel { class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private final ReportWizardPortableCaseOptionsPanel wizPanel; private final ReportWizardPortableCaseOptionsPanel wizPanel;
private PortableCaseReportModuleSettings settings = null; private PortableCaseReportModuleSettings settings = null;
private Map<String, ReportModuleConfig> moduleConfigs; private final Map<String, ReportModuleConfig> moduleConfigs;
private final boolean useCaseSpecificData; private final boolean useCaseSpecificData;
/** /**
* Creates new form ReportWizardPortableCaseOptionsVisualPanel * Creates new form ReportWizardPortableCaseOptionsVisualPanel
*/ */
@ -48,9 +50,9 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel {
initComponents(); initComponents();
customizeComponents(); customizeComponents();
} }
private void customizeComponents() { private void customizeComponents() {
if (!PlatformUtil.isWindowsOS()) { if (!PlatformUtil.isWindowsOS()) {
errorLabel.setVisible(true); errorLabel.setVisible(true);
compressCheckbox.setEnabled(false); compressCheckbox.setEnabled(false);
@ -61,7 +63,7 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel {
for (ChunkSize chunkSize : ChunkSize.values()) { for (ChunkSize chunkSize : ChunkSize.values()) {
chunkSizeComboBox.addItem(chunkSize); chunkSizeComboBox.addItem(chunkSize);
} }
// initialize settings // initialize settings
if (moduleConfigs != null) { if (moduleConfigs != null) {
// get configuration for this module // get configuration for this module
@ -75,42 +77,42 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel {
} }
} }
} }
if (settings == null) { if (settings == null) {
// get default module configuration // get default module configuration
settings = new PortableCaseReportModuleSettings(); settings = new PortableCaseReportModuleSettings();
} }
// update according to input configuration // update according to input configuration
compressCheckbox.setSelected(settings.shouldCompress()); compressCheckbox.setSelected(settings.shouldCompress());
chunkSizeComboBox.setEnabled(settings.shouldCompress()); chunkSizeComboBox.setEnabled(settings.shouldCompress());
chunkSizeComboBox.setSelectedItem(settings.getChunkSize()); chunkSizeComboBox.setSelectedItem(settings.getChunkSize());
// initialize other panels and pass them the settings // 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 PortableCaseTagsListPanel(wizPanel, settings, useCaseSpecificData));
listPanel.add(new PortableCaseInterestingItemsListPanel(wizPanel, settings, useCaseSpecificData)); listPanel.add(new PortableCaseInterestingItemsListPanel(wizPanel, settings, useCaseSpecificData));
} }
@NbBundle.Messages({ @NbBundle.Messages({
"ReportWizardPortableCaseOptionsVisualPanel.getName.title=Choose Portable Case settings", "ReportWizardPortableCaseOptionsVisualPanel.getName.title=Choose Portable Case settings",})
})
@Override @Override
public String getName() { public String getName() {
return Bundle.ReportWizardPortableCaseOptionsVisualPanel_getName_title(); return Bundle.ReportWizardPortableCaseOptionsVisualPanel_getName_title();
} }
/** /**
* Get the selected chunk size * Get the selected chunk size
* *
* @return the chunk size that was selected * @return the chunk size that was selected
*/ */
private ChunkSize getChunkSize() { private ChunkSize getChunkSize() {
return (ChunkSize) chunkSizeComboBox.getSelectedItem(); 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() { private void updateCompression() {
if (settings != null) { if (settings != null) {
@ -118,7 +120,16 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel {
wizPanel.setFinish(settings.isValid()); wizPanel.setFinish(settings.isValid());
} }
} }
/**
* Update the include application option.
*/
private void updateIncludeApplication() {
if (settings != null) {
settings.setIncludeApplication(includeAppCheckbox.isSelected());
}
}
/** /**
* Get the user-selected settings. * Get the user-selected settings.
* *
@ -126,7 +137,7 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel {
*/ */
PortableCaseReportModuleSettings getPortableCaseReportSettings() { PortableCaseReportModuleSettings getPortableCaseReportSettings() {
return settings; return settings;
} }
/** /**
* This method is called from within the constructor to initialize the form. * This method is called from within the constructor to initialize the form.
@ -137,11 +148,12 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel {
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() { private void initComponents() {
jPanel1 = new javax.swing.JPanel(); mainPanel = new javax.swing.JPanel();
chunkSizeComboBox = new javax.swing.JComboBox<>(); chunkSizeComboBox = new javax.swing.JComboBox<>();
compressCheckbox = new javax.swing.JCheckBox(); compressCheckbox = new javax.swing.JCheckBox();
errorLabel = new javax.swing.JLabel(); errorLabel = new javax.swing.JLabel();
listPanel = new javax.swing.JPanel(); listPanel = new javax.swing.JPanel();
includeAppCheckbox = new javax.swing.JCheckBox();
chunkSizeComboBox.addActionListener(new java.awt.event.ActionListener() { chunkSizeComboBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -168,32 +180,44 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel {
); );
listPanelLayout.setVerticalGroup( listPanelLayout.setVerticalGroup(
listPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 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); org.openide.awt.Mnemonics.setLocalizedText(includeAppCheckbox, org.openide.util.NbBundle.getMessage(ReportWizardPortableCaseOptionsVisualPanel.class, "ReportWizardPortableCaseOptionsVisualPanel.includeAppCheckbox.text")); // NOI18N
jPanel1.setLayout(jPanel1Layout); includeAppCheckbox.addActionListener(new java.awt.event.ActionListener() {
jPanel1Layout.setHorizontalGroup( public void actionPerformed(java.awt.event.ActionEvent evt) {
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) includeAppCheckboxActionPerformed(evt);
.addGroup(jPanel1Layout.createSequentialGroup() }
.addContainerGap() });
.addComponent(compressCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
.addComponent(chunkSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 187, javax.swing.GroupLayout.PREFERRED_SIZE) mainPanel.setLayout(mainPanelLayout);
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) mainPanelLayout.setHorizontalGroup(
.addComponent(errorLabel) mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addContainerGap(41, Short.MAX_VALUE))
.addComponent(listPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .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( mainPanelLayout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup() .addGroup(mainPanelLayout.createSequentialGroup()
.addComponent(listPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(listPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .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(compressCheckbox)
.addComponent(chunkSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(chunkSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(errorLabel)) .addComponent(errorLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(includeAppCheckbox)
.addContainerGap()) .addContainerGap())
); );
@ -203,13 +227,13 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel {
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 463, Short.MAX_VALUE) .addGap(0, 463, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .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.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 259, Short.MAX_VALUE) .addGap(0, 259, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .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))
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
@ -218,16 +242,27 @@ class ReportWizardPortableCaseOptionsVisualPanel extends javax.swing.JPanel {
}//GEN-LAST:event_chunkSizeComboBoxActionPerformed }//GEN-LAST:event_chunkSizeComboBoxActionPerformed
private void compressCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_compressCheckboxActionPerformed private void compressCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_compressCheckboxActionPerformed
chunkSizeComboBox.setEnabled(compressCheckbox.isSelected()); chunkSizeComboBox.setEnabled(compressCheckbox.isSelected() && !includeAppCheckbox.isSelected());
updateCompression(); updateCompression();
}//GEN-LAST:event_compressCheckboxActionPerformed }//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
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JComboBox<ChunkSize> chunkSizeComboBox; private javax.swing.JComboBox<ChunkSize> chunkSizeComboBox;
private javax.swing.JCheckBox compressCheckbox; private javax.swing.JCheckBox compressCheckbox;
private javax.swing.JLabel errorLabel; private javax.swing.JLabel errorLabel;
private javax.swing.JPanel jPanel1; private javax.swing.JCheckBox includeAppCheckbox;
private javax.swing.JPanel listPanel; private javax.swing.JPanel listPanel;
private javax.swing.JPanel mainPanel;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }

View File

@ -24,6 +24,7 @@ PortableCaseReportModule.generateReport.copyingFiles=Copying files tagged as {0}
PortableCaseReportModule.generateReport.copyingTags=Copying tags... PortableCaseReportModule.generateReport.copyingTags=Copying tags...
PortableCaseReportModule.generateReport.creatingCase=Creating portable case database... PortableCaseReportModule.generateReport.creatingCase=Creating portable case database...
PortableCaseReportModule.generateReport.errorCopyingArtifacts=Error copying tagged artifacts PortableCaseReportModule.generateReport.errorCopyingArtifacts=Error copying tagged artifacts
PortableCaseReportModule.generateReport.errorCopyingAutopsy=Error copying application
PortableCaseReportModule.generateReport.errorCopyingFiles=Error copying tagged files PortableCaseReportModule.generateReport.errorCopyingFiles=Error copying tagged files
PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files
PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results
@ -42,3 +43,4 @@ PortableCaseReportModule.generateReport.outputDirIsNotDir=Output folder {0} is n
PortableCaseReportModule.generateReport.verifying=Verifying selected parameters... PortableCaseReportModule.generateReport.verifying=Verifying selected parameters...
PortableCaseReportModule.getDescription.description=Copies selected items to a new single-user case that can be easily shared PortableCaseReportModule.getDescription.description=Copies selected items to a new single-user case that can be easily shared
PortableCaseReportModule.getName.name=Portable Case PortableCaseReportModule.getName.name=Portable Case
PortableCaseReportModule_generateReport_copyingAutopsy=Copying application...

View File

@ -29,6 +29,7 @@ import java.util.logging.Level;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; 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.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager; 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.FileUtil;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil;
@ -167,9 +169,9 @@ public class PortableCaseReportModule implements ReportModule {
* exception is supplied then the error is SEVERE. Otherwise it is logged as * exception is supplied then the error is SEVERE. Otherwise it is logged as
* a WARNING. * 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 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 * @param progressPanel The report progress panel
*/ */
private void handleError(String logWarning, String dialogWarning, Exception ex, ReportProgressPanel progressPanel) { private void handleError(String logWarning, String dialogWarning, Exception ex, ReportProgressPanel progressPanel) {
@ -206,9 +208,11 @@ public class PortableCaseReportModule implements ReportModule {
"PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files", "PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files",
"PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results", "PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results",
"PortableCaseReportModule.generateReport.errorCreatingImageTagTable=Error creating image tags table", "PortableCaseReportModule.generateReport.errorCreatingImageTagTable=Error creating image tags table",
"PortableCaseReportModule.generateReport.errorCopyingAutopsy=Error copying application",
"# {0} - attribute type name", "# {0} - attribute type name",
"PortableCaseReportModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}", "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) { public void generateReport(String reportPath, PortableCaseReportModuleSettings options, ReportProgressPanel progressPanel) {
@ -244,6 +248,10 @@ public class PortableCaseReportModule implements ReportModule {
return; 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 // Check that there will be something to copy
List<TagName> tagNames; List<TagName> tagNames;
if (options.areAllTagsSelected()) { if (options.areAllTagsSelected()) {
@ -419,22 +427,30 @@ public class PortableCaseReportModule implements ReportModule {
//Attempt to generate and included the CASE-UCO report. //Attempt to generate and included the CASE-UCO report.
generateCaseUcoReport(tagNames, setNames, progressPanel); 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) // Compress the case (if desired)
if (options.shouldCompress()) { if (options.shouldCompress()) {
progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_compressingCase()); progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_compressingCase());
boolean success = compressCase(progressPanel); if(!compressCase(progressPanel, options.includeApplication() ? outputDir.getAbsolutePath() : caseFolder.getAbsolutePath())){
// Errors have been handled already
return;
}
// Check for cancellation // Check for cancellation
if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
handleCancellation(progressPanel); handleCancellation(progressPanel);
return; return;
} }
if (!success) {
// Errors have been handled already
return;
}
} }
// Close the case connections and clear out the maps // Close the case connections and clear out the maps
@ -451,8 +467,8 @@ public class PortableCaseReportModule implements ReportModule {
* Only one copy of the file will be saved in the report if it is the source * Only one copy of the file will be saved in the report if it is the source
* of more than one of the above. * of more than one of the above.
* *
* @param tagNames TagNames to included in the report. * @param tagNames TagNames to included in the report.
* @param setNames SET_NAMEs to include in the report. * @param setNames SET_NAMEs to include in the report.
* @param progressPanel ProgressPanel to relay progress messages. * @param progressPanel ProgressPanel to relay progress messages.
*/ */
@NbBundle.Messages({ @NbBundle.Messages({
@ -506,7 +522,7 @@ public class PortableCaseReportModule implements ReportModule {
// Helper flag to ensure each data source is only written once in // Helper flag to ensure each data source is only written once in
// a report. // a report.
boolean dataSourceHasBeenIncluded = false; boolean dataSourceHasBeenIncluded = false;
//Search content tags and artifact tags that match //Search content tags and artifact tags that match
for (TagName tagName : tagNames) { for (TagName tagName : tagNames) {
for (ContentTag ct : tagsManager.getContentTagsByTagName(tagName, dataSource.getId())) { for (ContentTag ct : tagsManager.getContentTagsByTagName(tagName, dataSource.getId())) {
@ -565,16 +581,19 @@ public class PortableCaseReportModule implements ReportModule {
/** /**
* Adds the content if and only if it has not already been seen. * Adds the content if and only if it has not already been seen.
* *
* @param content Content to add to the report. * @param content Content to add to the report.
* @param dataSource Parent dataSource of the content instance. * @param dataSource Parent dataSource of the content
* @param tmpDir Path to the tmpDir to enforce uniqueness * instance.
* @param tmpDir Path to the tmpDir to enforce uniqueness
* @param gson * @param gson
* @param exporter * @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 * @param dataSourceHasBeenIncluded Flag determining if the data source
* should be written to the report (false indicates that it should be written). * should be written to the report (false
* * indicates that it should be written).
* @throws IOException If an I/O error occurs. *
* @throws IOException If an I/O error occurs.
* @throws TskCoreException If an internal database error occurs. * @throws TskCoreException If an internal database error occurs.
* *
* return True if the file was written during this operation. * return True if the file was written during this operation.
@ -630,7 +649,7 @@ public class PortableCaseReportModule implements ReportModule {
* Create the case directory and case database. portableSkCase will be set * Create the case directory and case database. portableSkCase will be set
* if this completes without error. * if this completes without error.
* *
* @param outputDir The parent for the case folder * @param outputDir The parent for the case folder
* @param progressPanel * @param progressPanel
*/ */
@NbBundle.Messages({ @NbBundle.Messages({
@ -734,7 +753,7 @@ public class PortableCaseReportModule implements ReportModule {
/** /**
* Add all files with a given tag to the portable case. * 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 * @param progressPanel The progress panel
* *
* @throws TskCoreException * @throws TskCoreException
@ -779,7 +798,7 @@ public class PortableCaseReportModule implements ReportModule {
* @param tag The ContentTag in the current case * @param tag The ContentTag in the current case
* *
* @return The app_data string for this content tag or an empty string if * @return The app_data string for this content tag or an empty string if
* there was none * there was none
* *
* @throws TskCoreException * @throws TskCoreException
*/ */
@ -828,7 +847,7 @@ public class PortableCaseReportModule implements ReportModule {
* Add an image tag to the portable case. * Add an image tag to the portable case.
* *
* @param newContentTag The content tag in 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 * @throws TskCoreException
*/ */
@ -840,7 +859,7 @@ public class PortableCaseReportModule implements ReportModule {
/** /**
* Add all artifacts with a given tag to the portable case. * 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 * @param progressPanel The progress panel
* *
* @throws TskCoreException * @throws TskCoreException
@ -876,8 +895,8 @@ public class PortableCaseReportModule implements ReportModule {
* Copy an artifact into the new case. Will also copy any associated * Copy an artifact into the new case. Will also copy any associated
* artifacts * artifacts
* *
* @param newContentId The content ID (in the portable case) of the source * @param newContentId The content ID (in the portable case) of the source
* content * content
* @param artifactToCopy The artifact to copy * @param artifactToCopy The artifact to copy
* *
* @return The new artifact in the portable case * @return The new artifact in the portable case
@ -1000,7 +1019,7 @@ public class PortableCaseReportModule implements ReportModule {
/** /**
* Top level method to copy a content object to the portable case. * 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 * @param progressPanel The progress panel
* *
* @return The object ID of the copied content in the portable case * @return The object ID of the copied content in the portable case
@ -1143,6 +1162,76 @@ public class PortableCaseReportModule implements ReportModule {
return UNKNOWN_FILE_TYPE_FOLDER; 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 <appName>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) throws IOException {
// Create an appName folder in the destination
Path destAppFolder = Paths.get(destBaseFolder, UserPreferences.getAppName());
if (!destAppFolder.toFile().exists() && !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 Folder to create the bat file in.
*
* @throws IOException
*/
private void createAppLaunchBatFile(String destBaseFolder) throws IOException {
Path filePath = Paths.get(destBaseFolder, "open.bat");
String appName = UserPreferences.getAppName();
String exePath = "\"%~dp0" + appName + "\\bin\\" + getAutopsyExeName() + "\"";
String casePath = "..\\" + caseName;
try (FileWriter writer = new FileWriter(filePath.toFile())) {
writer.write(exePath + " \"" + casePath + "\"");
}
}
/** /**
* Clear out the maps and other fields and close the database connections. * Clear out the maps and other fields and close the database connections.
*/ */
@ -1171,11 +1260,10 @@ public class PortableCaseReportModule implements ReportModule {
} }
} }
/*@Override /*
public JPanel getConfigurationPanel() { * @Override public JPanel getConfigurationPanel() { configPanel = new
configPanel = new CreatePortableCasePanel(); * CreatePortableCasePanel(); return configPanel; }
return configPanel; */
} */
private class StoreMaxIdCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { private class StoreMaxIdCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
private final String tableName; private final String tableName;
@ -1213,14 +1301,14 @@ public class PortableCaseReportModule implements ReportModule {
"PortableCaseReportModule.compressCase.errorCreatingTempFolder=Could not create temporary folder {0}", "PortableCaseReportModule.compressCase.errorCreatingTempFolder=Could not create temporary folder {0}",
"PortableCaseReportModule.compressCase.errorCompressingCase=Error compressing case", "PortableCaseReportModule.compressCase.errorCompressingCase=Error compressing case",
"PortableCaseReportModule.compressCase.canceled=Compression canceled by user",}) "PortableCaseReportModule.compressCase.canceled=Compression canceled by user",})
private boolean compressCase(ReportProgressPanel progressPanel) { private boolean compressCase(ReportProgressPanel progressPanel, String folderToCompress) {
// Close the portable case database (we still need some of the variables that would be cleared by cleanup())
closePortableCaseDatabase(); closePortableCaseDatabase();
// Make a temporary folder for the compressed case // Make a temporary folder for the compressed case
File tempZipFolder = Paths.get(currentCase.getTempDirectory(), "portableCase" + System.currentTimeMillis()).toFile(); // NON-NLS Path dirToCompress = Paths.get(folderToCompress);
if (!tempZipFolder.mkdir()) { File tempZipFolder = Paths.get(dirToCompress.getParent().toString(), "temp", "portableCase" + System.currentTimeMillis()).toFile();
if (!tempZipFolder.mkdirs()) {
handleError("Error creating temporary folder " + tempZipFolder.toString(), handleError("Error creating temporary folder " + tempZipFolder.toString(),
Bundle.PortableCaseReportModule_compressCase_errorCreatingTempFolder(tempZipFolder.toString()), null, progressPanel); // NON-NLS Bundle.PortableCaseReportModule_compressCase_errorCreatingTempFolder(tempZipFolder.toString()), null, progressPanel); // NON-NLS
return false; return false;
@ -1245,7 +1333,7 @@ public class PortableCaseReportModule implements ReportModule {
sevenZipExe.getAbsolutePath(), sevenZipExe.getAbsolutePath(),
"a", // Add to archive "a", // Add to archive
zipFile.getAbsolutePath(), zipFile.getAbsolutePath(),
caseFolder.getAbsolutePath(), dirToCompress.toAbsolutePath().toString(),
chunkOption chunkOption
); );
@ -1280,9 +1368,9 @@ public class PortableCaseReportModule implements ReportModule {
// Delete everything in the case folder then copy over the compressed file(s) // Delete everything in the case folder then copy over the compressed file(s)
try { try {
FileUtils.cleanDirectory(caseFolder); FileUtils.cleanDirectory(dirToCompress.toFile());
FileUtils.copyDirectory(tempZipFolder, caseFolder); FileUtils.copyDirectory(tempZipFolder, dirToCompress.toFile());
FileUtils.deleteDirectory(tempZipFolder); FileUtils.deleteDirectory(new File(tempZipFolder.getParent()));
} catch (IOException ex) { } catch (IOException ex) {
handleError("Error compressing case", Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), ex, progressPanel); // NON-NLS handleError("Error compressing case", Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), ex, progressPanel); // NON-NLS
return false; return false;

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2019 Basis Technology Corp. * Copyright 2019-2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -36,6 +36,7 @@ public class PortableCaseReportModuleSettings implements ReportModuleSettings {
private ChunkSize chunkSize; private ChunkSize chunkSize;
private boolean allTagsSelected; private boolean allTagsSelected;
private boolean allSetsSelected; private boolean allSetsSelected;
private boolean shouldIncludeApplication;
/** /**
* Enum for storing the display name for each chunk type and the * Enum for storing the display name for each chunk type and the
@ -141,6 +142,10 @@ public class PortableCaseReportModuleSettings implements ReportModuleSettings {
public boolean areAllSetsSelected() { public boolean areAllSetsSelected() {
return allSetsSelected; return allSetsSelected;
} }
public boolean includeApplication() {
return shouldIncludeApplication;
}
/** /**
* @param allTagsSelected the allTagsSelected to set * @param allTagsSelected the allTagsSelected to set
@ -155,5 +160,9 @@ public class PortableCaseReportModuleSettings implements ReportModuleSettings {
public void setAllSetsSelected(boolean allSetsSelected) { public void setAllSetsSelected(boolean allSetsSelected) {
this.allSetsSelected = allSetsSelected; this.allSetsSelected = allSetsSelected;
} }
public void setIncludeApplication(boolean includeApplication) {
this.shouldIncludeApplication = includeApplication;
}
} }