mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
Merge branch 'develop' of github.com:sleuthkit/autopsy into archive_dsp_4658
This commit is contained in:
commit
cfef5cfc2b
1
.gitignore
vendored
1
.gitignore
vendored
@ -49,6 +49,7 @@ genfiles.properties
|
|||||||
!/test/input/NSRL.txt-md5.idx
|
!/test/input/NSRL.txt-md5.idx
|
||||||
/test/output/*
|
/test/output/*
|
||||||
!/test/output/gold
|
!/test/output/gold
|
||||||
|
/test/script/output_dir_link.txt
|
||||||
/test/output/gold/tmp
|
/test/output/gold/tmp
|
||||||
/test/script/ScriptLog.txt
|
/test/script/ScriptLog.txt
|
||||||
/test/script/__pycache__/
|
/test/script/__pycache__/
|
||||||
|
@ -21,7 +21,11 @@ package org.sleuthkit.autopsy.casemodule;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
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.CommandLineOptionProcessor;
|
||||||
|
import org.sleuthkit.autopsy.commandlineingest.CommandLineStartupWindow;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,6 +58,17 @@ public class StartupWindowProvider implements StartupWindowInterface {
|
|||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
if (startupWindowToUse == null) {
|
if (startupWindowToUse == null) {
|
||||||
|
// first check whether we are running from command line
|
||||||
|
if (isRunningFromCommandLine()) {
|
||||||
|
// Autopsy is running from command line
|
||||||
|
logger.log(Level.INFO, "Running from command line"); //NON-NLS
|
||||||
|
System.out.println("Running from command line");
|
||||||
|
startupWindowToUse = new CommandLineStartupWindow();
|
||||||
|
// kick off command line processing
|
||||||
|
new CommandLineIngestManager().start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//discover the registered windows
|
//discover the registered windows
|
||||||
Collection<? extends StartupWindowInterface> startupWindows
|
Collection<? extends StartupWindowInterface> startupWindows
|
||||||
= Lookup.getDefault().lookupAll(StartupWindowInterface.class);
|
= Lookup.getDefault().lookupAll(StartupWindowInterface.class);
|
||||||
@ -93,6 +108,30 @@ public class StartupWindowProvider implements StartupWindowInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether Autopsy is running from command line. There is an
|
||||||
|
* OptionProcessor that is responsible for processing command line inputs.
|
||||||
|
* If Autopsy is indeed running from command line, then use the command line
|
||||||
|
* startup window.
|
||||||
|
*
|
||||||
|
* @return True if running from command line, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean isRunningFromCommandLine() {
|
||||||
|
|
||||||
|
// 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 CommandLineOptionProcessor)) {
|
||||||
|
// check if we are running from command line
|
||||||
|
return ((CommandLineOptionProcessor) processor).isRunFromCommandLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void open() {
|
public void open() {
|
||||||
if (startupWindowToUse != null) {
|
if (startupWindowToUse != null) {
|
||||||
|
96
Core/src/org/sleuthkit/autopsy/commandlineingest/AddDataSourceCallback.java
Executable file
96
Core/src/org/sleuthkit/autopsy/commandlineingest/AddDataSourceCallback.java
Executable file
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019-2019 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.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A "callback" that collects the results of running a data source processor on
|
||||||
|
* a data source and unblocks the job processing thread when the data source
|
||||||
|
* processor finishes running in its own thread.
|
||||||
|
*/
|
||||||
|
class AddDataSourceCallback extends DataSourceProcessorCallback {
|
||||||
|
|
||||||
|
private final Case caseForJob;
|
||||||
|
private final DataSource dataSourceInfo;
|
||||||
|
private final UUID taskId;
|
||||||
|
private final Object lock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a "callback" that collects the results of running a data
|
||||||
|
* source processor on a data source and unblocks the job processing thread
|
||||||
|
* when the data source processor finishes running in its own thread.
|
||||||
|
*
|
||||||
|
* @param caseForJob The case for the current job.
|
||||||
|
* @param dataSourceInfo The data source
|
||||||
|
* @param taskId The task id to associate with ingest job events.
|
||||||
|
*/
|
||||||
|
AddDataSourceCallback(Case caseForJob, DataSource dataSourceInfo, UUID taskId, Object lock) {
|
||||||
|
this.caseForJob = caseForJob;
|
||||||
|
this.dataSourceInfo = dataSourceInfo;
|
||||||
|
this.taskId = taskId;
|
||||||
|
this.lock = lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the data source processor when it finishes running in its own
|
||||||
|
* thread.
|
||||||
|
*
|
||||||
|
* @param result The result code for the processing of the data source.
|
||||||
|
* @param errorMessages Any error messages generated during the processing
|
||||||
|
* of the data source.
|
||||||
|
* @param dataSourceContent The content produced by processing the data
|
||||||
|
* source.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errorMessages, List<Content> dataSourceContent) {
|
||||||
|
if (!dataSourceContent.isEmpty()) {
|
||||||
|
caseForJob.notifyDataSourceAdded(dataSourceContent.get(0), taskId);
|
||||||
|
} else {
|
||||||
|
caseForJob.notifyFailedAddingDataSource(taskId);
|
||||||
|
}
|
||||||
|
dataSourceInfo.setDataSourceProcessorOutput(result, errorMessages, dataSourceContent);
|
||||||
|
dataSourceContent.addAll(dataSourceContent);
|
||||||
|
synchronized (lock) {
|
||||||
|
lock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the data source processor when it finishes running in its own
|
||||||
|
* thread, if that thread is the AWT (Abstract Window Toolkit) event
|
||||||
|
* dispatch thread (EDT).
|
||||||
|
*
|
||||||
|
* @param result The result code for the processing of the data source.
|
||||||
|
* @param errorMessages Any error messages generated during the processing
|
||||||
|
* of the data source.
|
||||||
|
* @param dataSourceContent The content produced by processing the data
|
||||||
|
* source.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errorMessages, List<Content> dataSources) {
|
||||||
|
done(result, errorMessages, dataSources);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
17
Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties
Executable file
17
Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
OpenIDE-Module-Name=CommandLineAutopsy
|
||||||
|
OptionsCategory_Keywords_Command_Line_Ingest_Settings=Command Line Ingest Settings
|
||||||
|
OptionsCategory_Keywords_General=Options
|
||||||
|
OptionsCategory_Name_Command_Line_Ingest=Command Line Ingest
|
||||||
|
CommandLineIngestSettingsPanel.ResultsDirectoryUnspecified=Output folder must be set
|
||||||
|
CommandLineIngestSettingsPanel.PathInvalid=Path is not valid
|
||||||
|
CommandLineIngestSettingsPanel.CannotAccess=Cannot access
|
||||||
|
CommandLineIngestSettingsPanel.CheckPermissions=Check permissions.
|
||||||
|
CommandLineIngestSettingsPanel.jLabelSelectOutputFolder.text=Select output folder:
|
||||||
|
CommandLineIngestSettingsPanel.jLabelInvalidResultsFolder.text=jLabelInvalidOutputFolder
|
||||||
|
CommandLineIngestSettingsPanel.outputPathTextField.toolTipText=Output folder for command line processing, i.e., the location where case folder will be created by command line processing mode.
|
||||||
|
CommandLineIngestSettingsPanel.outputPathTextField.text=
|
||||||
|
CommandLineIngestSettingsPanel.browseOutputFolderButton.text=Browse
|
||||||
|
CommandLineIngestSettingsPanel.bnEditIngestSettings.toolTipText=Ingest job settings for the command line processing mode context.
|
||||||
|
CommandLineIngestSettingsPanel.bnEditIngestSettings.text=Ingest Module Settings
|
||||||
|
CommandLinePanel.jLabel1.text=Ingest is running from command line
|
||||||
|
CommandLineStartupWindow.title.text=Running in Command Line Mode
|
17
Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties-MERGED
Executable file
17
Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties-MERGED
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
OpenIDE-Module-Name=CommandLineAutopsy
|
||||||
|
OptionsCategory_Keywords_Command_Line_Ingest_Settings=Command Line Ingest Settings
|
||||||
|
OptionsCategory_Keywords_General=Options
|
||||||
|
OptionsCategory_Name_Command_Line_Ingest=Command Line Ingest
|
||||||
|
CommandLineIngestSettingsPanel.ResultsDirectoryUnspecified=Output folder must be set
|
||||||
|
CommandLineIngestSettingsPanel.PathInvalid=Path is not valid
|
||||||
|
CommandLineIngestSettingsPanel.CannotAccess=Cannot access
|
||||||
|
CommandLineIngestSettingsPanel.CheckPermissions=Check permissions.
|
||||||
|
CommandLineIngestSettingsPanel.jLabelSelectOutputFolder.text=Select output folder:
|
||||||
|
CommandLineIngestSettingsPanel.jLabelInvalidResultsFolder.text=jLabelInvalidOutputFolder
|
||||||
|
CommandLineIngestSettingsPanel.outputPathTextField.toolTipText=Output folder for command line processing, i.e., the location where case folder will be created by command line processing mode.
|
||||||
|
CommandLineIngestSettingsPanel.outputPathTextField.text=
|
||||||
|
CommandLineIngestSettingsPanel.browseOutputFolderButton.text=Browse
|
||||||
|
CommandLineIngestSettingsPanel.bnEditIngestSettings.toolTipText=Ingest job settings for the command line processing mode context.
|
||||||
|
CommandLineIngestSettingsPanel.bnEditIngestSettings.text=Ingest Module Settings
|
||||||
|
CommandLinePanel.jLabel1.text=Ingest is running from command line
|
||||||
|
CommandLineStartupWindow.title.text=Running in Command Line Mode
|
613
Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestManager.java
Executable file
613
Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestManager.java
Executable file
@ -0,0 +1,613 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019-2019 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.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FilenameFilter;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.netbeans.spi.sendopts.OptionProcessor;
|
||||||
|
import org.openide.LifecycleManager;
|
||||||
|
import org.openide.util.Lookup;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.CaseActionException;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.CaseDetails;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
|
||||||
|
import org.sleuthkit.autopsy.core.RuntimeProperties;
|
||||||
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||||
|
import static org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS;
|
||||||
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.TimeStampUtils;
|
||||||
|
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
|
||||||
|
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestJob;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestJobStartResult;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestModuleError;
|
||||||
|
import org.sleuthkit.autopsy.report.ReportProgressPanel;
|
||||||
|
import org.sleuthkit.autopsy.report.caseuco.CaseUcoFormatExporter;
|
||||||
|
import org.sleuthkit.autopsy.report.caseuco.ReportCaseUco;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows Autopsy to be invoked with a command line arguments. Causes Autopsy to
|
||||||
|
* create a case, add a specified data source, run ingest on that data source,
|
||||||
|
* produce a CASE/UCO report and exit.
|
||||||
|
*/
|
||||||
|
public class CommandLineIngestManager {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(CommandLineIngestManager.class.getName());
|
||||||
|
private Path rootOutputDirectory;
|
||||||
|
|
||||||
|
public CommandLineIngestManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
new Thread(new JobProcessingTask()).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
try {
|
||||||
|
// close current case if there is one open
|
||||||
|
Case.closeCurrentCase();
|
||||||
|
} catch (CaseActionException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Unable to close the case while shutting down command line ingest manager", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
// shut down Autopsy
|
||||||
|
LifecycleManager.getDefault().exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class JobProcessingTask implements Runnable {
|
||||||
|
|
||||||
|
private final Object ingestLock;
|
||||||
|
|
||||||
|
private JobProcessingTask() {
|
||||||
|
ingestLock = new Object();
|
||||||
|
try {
|
||||||
|
RuntimeProperties.setRunningWithGUI(false);
|
||||||
|
LOGGER.log(Level.INFO, "Set running with desktop GUI runtime property to false");
|
||||||
|
} catch (RuntimeProperties.RuntimePropertiesException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Failed to set running with desktop GUI runtime property to false", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
LOGGER.log(Level.INFO, "Job processing task started");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// read command line inputs
|
||||||
|
LOGGER.log(Level.INFO, "Autopsy is running from command line"); //NON-NLS
|
||||||
|
String dataSourcePath = "";
|
||||||
|
String baseCaseName = "";
|
||||||
|
|
||||||
|
// 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 CommandLineOptionProcessor) {
|
||||||
|
// check if we are running from command line
|
||||||
|
dataSourcePath = ((CommandLineOptionProcessor) processor).getPathToDataSource();
|
||||||
|
baseCaseName = ((CommandLineOptionProcessor) processor).getBaseCaseName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.log(Level.INFO, "Data source path = {0}", dataSourcePath); //NON-NLS
|
||||||
|
LOGGER.log(Level.INFO, "Case name = {0}", baseCaseName); //NON-NLS
|
||||||
|
System.out.println("Data source path = " + dataSourcePath);
|
||||||
|
System.out.println("Case name = " + baseCaseName);
|
||||||
|
|
||||||
|
// verify inputs
|
||||||
|
if (dataSourcePath.isEmpty()) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Data source path not specified");
|
||||||
|
System.out.println("Data source path not specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baseCaseName.isEmpty()) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Case name not specified");
|
||||||
|
System.out.println("Case name not specified");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(new File(dataSourcePath).exists())) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Data source file not found {0}", dataSourcePath);
|
||||||
|
System.out.println("Data source file not found " + dataSourcePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read options panel configuration
|
||||||
|
String rootOutputDir = UserPreferences.getCommandLineModeResultsFolder();
|
||||||
|
LOGGER.log(Level.INFO, "Output directory = {0}", rootOutputDir); //NON-NLS
|
||||||
|
System.out.println("Output directoryh = " + rootOutputDir);
|
||||||
|
|
||||||
|
if (rootOutputDir.isEmpty()) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Output directory not specified, please configure Command Line Options Panel (in Tools -> Options)");
|
||||||
|
System.out.println("Output directory not specified, please configure Command Line Options Panel (in Tools -> Options)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(new File(rootOutputDir).exists())) {
|
||||||
|
LOGGER.log(Level.SEVERE, "The output directory doesn't exist {0}", rootOutputDir);
|
||||||
|
System.out.println("The output directory doesn't exist " + rootOutputDir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rootOutputDirectory = Paths.get(rootOutputDir);
|
||||||
|
|
||||||
|
// open case
|
||||||
|
Case caseForJob;
|
||||||
|
try {
|
||||||
|
caseForJob = openCase(baseCaseName);
|
||||||
|
} catch (CaseActionException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error creating or opening case " + baseCaseName, ex);
|
||||||
|
System.out.println("Error creating or opening case " + baseCaseName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caseForJob == null) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error creating or opening case {0}", baseCaseName);
|
||||||
|
System.out.println("Error creating or opening case " + baseCaseName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataSource dataSource = new DataSource("", Paths.get(dataSourcePath));
|
||||||
|
try {
|
||||||
|
// run data source processor
|
||||||
|
runDataSourceProcessor(caseForJob, dataSource);
|
||||||
|
|
||||||
|
// run ingest manager
|
||||||
|
analyze(dataSource);
|
||||||
|
|
||||||
|
// generate CASE-UCO report
|
||||||
|
Long selectedDataSourceId = getDataSourceId(dataSource);
|
||||||
|
Path reportFolderPath = Paths.get(caseForJob.getReportDirectory(), "CASE-UCO", "Data_Source_ID_" + selectedDataSourceId.toString() + "_" + TimeStampUtils.createTimeStamp(), ReportCaseUco.getReportFileName()); //NON_NLS
|
||||||
|
ReportProgressPanel progressPanel = new ReportProgressPanel("CASE_UCO", rootOutputDir); // dummy progress panel
|
||||||
|
CaseUcoFormatExporter.generateReport(selectedDataSourceId, reportFolderPath.toString(), progressPanel);
|
||||||
|
} catch (InterruptedException | AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException | AnalysisStartupException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Unable to ingest data source " + dataSourcePath + ". Exiting...", ex);
|
||||||
|
System.out.println("Unable to ingest data source " + dataSourcePath + ". Exiting...");
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
/*
|
||||||
|
* Unexpected runtime exceptions firewall. This task is designed to
|
||||||
|
* be able to be run in an executor service thread pool without
|
||||||
|
* calling get() on the task's Future<Void>, so this ensures that
|
||||||
|
* such errors get logged.
|
||||||
|
*/
|
||||||
|
LOGGER.log(Level.SEVERE, "Unexpected error while ingesting data source " + dataSourcePath, ex);
|
||||||
|
System.out.println("Unexpected error while ingesting data source " + dataSourcePath + ". Exiting...");
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
Case.closeCurrentCase();
|
||||||
|
} catch (CaseActionException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Exception while closing case", ex);
|
||||||
|
System.out.println("Exception while closing case");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
LOGGER.log(Level.INFO, "Job processing task finished");
|
||||||
|
System.out.println("Job processing task finished");
|
||||||
|
|
||||||
|
// shut down Autopsy
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides object ID of the data source by reading it from Content
|
||||||
|
* object.
|
||||||
|
*
|
||||||
|
* @param dataSource DataSource object
|
||||||
|
* @return object ID
|
||||||
|
*/
|
||||||
|
private Long getDataSourceId(DataSource dataSource) {
|
||||||
|
Content content = dataSource.getContent().get(0);
|
||||||
|
return content.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Case openCase(String baseCaseName) throws CaseActionException {
|
||||||
|
|
||||||
|
LOGGER.log(Level.INFO, "Opening case {0}", baseCaseName);
|
||||||
|
|
||||||
|
Path caseDirectoryPath = findCaseDirectory(rootOutputDirectory, baseCaseName);
|
||||||
|
if (null != caseDirectoryPath) {
|
||||||
|
// found an existing case directory for same case name. the input case name must be unique. Exit.
|
||||||
|
LOGGER.log(Level.SEVERE, "Case {0} already exists. Case name must be unique. Exiting", baseCaseName);
|
||||||
|
throw new CaseActionException("Case " + baseCaseName + " already exists. Case name must be unique. Exiting");
|
||||||
|
} else {
|
||||||
|
caseDirectoryPath = createCaseFolderPath(rootOutputDirectory, baseCaseName);
|
||||||
|
|
||||||
|
// Create the case directory
|
||||||
|
Case.createCaseDirectory(caseDirectoryPath.toString(), Case.CaseType.SINGLE_USER_CASE);
|
||||||
|
|
||||||
|
CaseDetails caseDetails = new CaseDetails(baseCaseName);
|
||||||
|
Case.createAsCurrentCase(Case.CaseType.SINGLE_USER_CASE, caseDirectoryPath.toString(), caseDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
Case caseForJob = Case.getCurrentCase();
|
||||||
|
LOGGER.log(Level.INFO, "Opened case {0}", caseForJob.getName());
|
||||||
|
return caseForJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Passes the data source for the current job through a data source
|
||||||
|
* processor that adds it to the case database.
|
||||||
|
*
|
||||||
|
* @param dataSource The data source.
|
||||||
|
*
|
||||||
|
* @throws
|
||||||
|
* AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException
|
||||||
|
* if there was a DSP processing error
|
||||||
|
*
|
||||||
|
* @throws InterruptedException if the thread running the job processing
|
||||||
|
* task is interrupted while blocked, i.e., if auto ingest is shutting
|
||||||
|
* down.
|
||||||
|
*/
|
||||||
|
private void runDataSourceProcessor(Case caseForJob, DataSource dataSource) throws InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException {
|
||||||
|
|
||||||
|
LOGGER.log(Level.INFO, "Adding data source {0} ", dataSource.getPath().toString());
|
||||||
|
|
||||||
|
// Get an ordered list of data source processors to try
|
||||||
|
List<AutoIngestDataSourceProcessor> validDataSourceProcessors;
|
||||||
|
try {
|
||||||
|
validDataSourceProcessors = DataSourceProcessorUtility.getOrderedListOfDataSourceProcessors(dataSource.getPath());
|
||||||
|
} catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Exception while determining best data source processor for {0}", dataSource.getPath());
|
||||||
|
// rethrow the exception.
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// did we find a data source processor that can process the data source
|
||||||
|
if (validDataSourceProcessors.isEmpty()) {
|
||||||
|
// This should never happen. We should add all unsupported data sources as logical files.
|
||||||
|
LOGGER.log(Level.SEVERE, "Unsupported data source {0}", dataSource.getPath()); // NON-NLS
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataSourceProcessorProgressMonitor progressMonitor = new DoNothingDSPProgressMonitor();
|
||||||
|
synchronized (ingestLock) {
|
||||||
|
// Try each DSP in decreasing order of confidence
|
||||||
|
for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) {
|
||||||
|
UUID taskId = UUID.randomUUID();
|
||||||
|
caseForJob.notifyAddingDataSource(taskId);
|
||||||
|
DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId, ingestLock);
|
||||||
|
caseForJob.notifyAddingDataSource(taskId);
|
||||||
|
LOGGER.log(Level.INFO, "Identified data source type for {0} as {1}", new Object[]{dataSource.getPath(), selectedProcessor.getDataSourceType()});
|
||||||
|
selectedProcessor.process(dataSource.getDeviceId(), dataSource.getPath(), progressMonitor, callBack);
|
||||||
|
ingestLock.wait();
|
||||||
|
|
||||||
|
// at this point we got the content object(s) from the current DSP.
|
||||||
|
// check whether the data source was processed successfully
|
||||||
|
if ((dataSource.getResultDataSourceProcessorResultCode() == CRITICAL_ERRORS)
|
||||||
|
|| dataSource.getContent().isEmpty()) {
|
||||||
|
// move onto the the next DSP that can process this data source
|
||||||
|
logDataSourceProcessorResult(dataSource);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
logDataSourceProcessorResult(dataSource);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If we get to this point, none of the processors were successful
|
||||||
|
LOGGER.log(Level.SEVERE, "All data source processors failed to process {0}", dataSource.getPath());
|
||||||
|
// Throw an exception. It will get caught & handled upstream and will result in AIM auto-pause.
|
||||||
|
throw new AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException("Failed to process " + dataSource.getPath() + " with all data source processors");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs the results of running a data source processor on the data
|
||||||
|
* source for the current job.
|
||||||
|
*
|
||||||
|
* @param dataSource The data source.
|
||||||
|
*/
|
||||||
|
private void logDataSourceProcessorResult(DataSource dataSource) {
|
||||||
|
|
||||||
|
DataSourceProcessorCallback.DataSourceProcessorResult resultCode = dataSource.getResultDataSourceProcessorResultCode();
|
||||||
|
if (null != resultCode) {
|
||||||
|
switch (resultCode) {
|
||||||
|
case NO_ERRORS:
|
||||||
|
LOGGER.log(Level.INFO, "Added data source to case");
|
||||||
|
if (dataSource.getContent().isEmpty()) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Data source failed to produce content");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NONCRITICAL_ERRORS:
|
||||||
|
for (String errorMessage : dataSource.getDataSourceProcessorErrorMessages()) {
|
||||||
|
LOGGER.log(Level.WARNING, "Non-critical error running data source processor for {0}: {1}", new Object[]{dataSource.getPath(), errorMessage});
|
||||||
|
}
|
||||||
|
LOGGER.log(Level.INFO, "Added data source to case");
|
||||||
|
if (dataSource.getContent().isEmpty()) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Data source failed to produce content");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CRITICAL_ERRORS:
|
||||||
|
for (String errorMessage : dataSource.getDataSourceProcessorErrorMessages()) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Critical error running data source processor for {0}: {1}", new Object[]{dataSource.getPath(), errorMessage});
|
||||||
|
}
|
||||||
|
LOGGER.log(Level.SEVERE, "Failed to add data source to case");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGGER.log(Level.WARNING, "No result code for data source processor for {0}", dataSource.getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes the data source content returned by the data source
|
||||||
|
* processor using the configured set of data source level and file
|
||||||
|
* level analysis modules.
|
||||||
|
*
|
||||||
|
* @param dataSource The data source to analyze.
|
||||||
|
*
|
||||||
|
* @throws AnalysisStartupException if there is an error analyzing the
|
||||||
|
* data source.
|
||||||
|
* @throws InterruptedException if the thread running the job processing
|
||||||
|
* task is interrupted while blocked, i.e., if auto ingest is shutting
|
||||||
|
* down.
|
||||||
|
*/
|
||||||
|
private void analyze(DataSource dataSource) throws AnalysisStartupException, InterruptedException {
|
||||||
|
|
||||||
|
LOGGER.log(Level.INFO, "Starting ingest modules analysis for {0} ", dataSource.getPath());
|
||||||
|
IngestJobEventListener ingestJobEventListener = new IngestJobEventListener();
|
||||||
|
IngestManager.getInstance().addIngestJobEventListener(ingestJobEventListener);
|
||||||
|
try {
|
||||||
|
synchronized (ingestLock) {
|
||||||
|
IngestJobSettings ingestJobSettings = new IngestJobSettings(UserPreferences.getCommandLineModeIngestModuleContextString());
|
||||||
|
List<String> settingsWarnings = ingestJobSettings.getWarnings();
|
||||||
|
if (settingsWarnings.isEmpty()) {
|
||||||
|
IngestJobStartResult ingestJobStartResult = IngestManager.getInstance().beginIngestJob(dataSource.getContent(), ingestJobSettings);
|
||||||
|
IngestJob ingestJob = ingestJobStartResult.getJob();
|
||||||
|
if (null != ingestJob) {
|
||||||
|
/*
|
||||||
|
* Block until notified by the ingest job event
|
||||||
|
* listener or until interrupted because auto ingest
|
||||||
|
* is shutting down.
|
||||||
|
*/
|
||||||
|
ingestLock.wait();
|
||||||
|
LOGGER.log(Level.INFO, "Finished ingest modules analysis for {0} ", dataSource.getPath());
|
||||||
|
IngestJob.ProgressSnapshot jobSnapshot = ingestJob.getSnapshot();
|
||||||
|
for (IngestJob.ProgressSnapshot.DataSourceProcessingSnapshot snapshot : jobSnapshot.getDataSourceSnapshots()) {
|
||||||
|
if (!snapshot.isCancelled()) {
|
||||||
|
List<String> cancelledModules = snapshot.getCancelledDataSourceIngestModules();
|
||||||
|
if (!cancelledModules.isEmpty()) {
|
||||||
|
LOGGER.log(Level.WARNING, String.format("Ingest module(s) cancelled for %s", dataSource.getPath()));
|
||||||
|
for (String module : snapshot.getCancelledDataSourceIngestModules()) {
|
||||||
|
LOGGER.log(Level.WARNING, String.format("%s ingest module cancelled for %s", module, dataSource.getPath()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOGGER.log(Level.INFO, "Analysis of data source completed");
|
||||||
|
} else {
|
||||||
|
LOGGER.log(Level.WARNING, "Analysis of data source cancelled");
|
||||||
|
IngestJob.CancellationReason cancellationReason = snapshot.getCancellationReason();
|
||||||
|
if (IngestJob.CancellationReason.NOT_CANCELLED != cancellationReason && IngestJob.CancellationReason.USER_CANCELLED != cancellationReason) {
|
||||||
|
throw new AnalysisStartupException(String.format("Analysis cancelled due to %s for %s", cancellationReason.getDisplayName(), dataSource.getPath()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!ingestJobStartResult.getModuleErrors().isEmpty()) {
|
||||||
|
for (IngestModuleError error : ingestJobStartResult.getModuleErrors()) {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("%s ingest module startup error for %s", error.getModuleDisplayName(), dataSource.getPath()), error.getThrowable());
|
||||||
|
}
|
||||||
|
LOGGER.log(Level.SEVERE, "Failed to analyze data source due to ingest job startup error");
|
||||||
|
throw new AnalysisStartupException(String.format("Error(s) during ingest module startup for %s", dataSource.getPath()));
|
||||||
|
} else {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Ingest manager ingest job start error for %s", dataSource.getPath()), ingestJobStartResult.getStartupException());
|
||||||
|
throw new AnalysisStartupException("Ingest manager error starting job", ingestJobStartResult.getStartupException());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (String warning : settingsWarnings) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Ingest job settings error for {0}: {1}", new Object[]{dataSource.getPath(), warning});
|
||||||
|
}
|
||||||
|
LOGGER.log(Level.SEVERE, "Failed to analyze data source due to settings errors");
|
||||||
|
throw new AnalysisStartupException("Error(s) in ingest job settings");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
IngestManager.getInstance().removeIngestJobEventListener(ingestJobEventListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a case folder path. Does not create the folder described by
|
||||||
|
* the path.
|
||||||
|
*
|
||||||
|
* @param caseFoldersPath The root case folders path.
|
||||||
|
* @param caseName The name of the case.
|
||||||
|
*
|
||||||
|
* @return A case folder path with a time stamp suffix.
|
||||||
|
*/
|
||||||
|
Path createCaseFolderPath(Path caseFoldersPath, String caseName) {
|
||||||
|
String folderName = caseName + "_" + TimeStampUtils.createTimeStamp();
|
||||||
|
return Paths.get(caseFoldersPath.toString(), folderName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches a given folder for the most recently modified case folder
|
||||||
|
* for a case.
|
||||||
|
*
|
||||||
|
* @param folderToSearch The folder to be searched.
|
||||||
|
* @param caseName The name of the case for which a case folder is to be
|
||||||
|
* found.
|
||||||
|
*
|
||||||
|
* @return The path of the case folder, or null if it is not found.
|
||||||
|
*/
|
||||||
|
Path findCaseDirectory(Path folderToSearch, String caseName) {
|
||||||
|
File searchFolder = new File(folderToSearch.toString());
|
||||||
|
if (!searchFolder.isDirectory()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Path caseFolderPath = null;
|
||||||
|
String[] candidateFolders = searchFolder.list(new CaseFolderFilter(caseName));
|
||||||
|
long mostRecentModified = 0;
|
||||||
|
for (String candidateFolder : candidateFolders) {
|
||||||
|
File file = new File(candidateFolder);
|
||||||
|
if (file.lastModified() >= mostRecentModified) {
|
||||||
|
mostRecentModified = file.lastModified();
|
||||||
|
caseFolderPath = Paths.get(folderToSearch.toString(), file.getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return caseFolderPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ingest job event listener that allows the job processing task to
|
||||||
|
* block until the analysis of a data source by the data source level
|
||||||
|
* and file level ingest modules is completed.
|
||||||
|
* <p>
|
||||||
|
* Note that the ingest job can spawn "child" ingest jobs (e.g., if an
|
||||||
|
* embedded virtual machine is found), so the job processing task must
|
||||||
|
* remain blocked until ingest is no longer running.
|
||||||
|
*/
|
||||||
|
private class IngestJobEventListener implements PropertyChangeListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listens for local ingest job completed or cancelled events and
|
||||||
|
* notifies the job processing thread when such an event occurs and
|
||||||
|
* there are no "child" ingest jobs running.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void propertyChange(PropertyChangeEvent event) {
|
||||||
|
if (AutopsyEvent.SourceType.LOCAL == ((AutopsyEvent) event).getSourceType()) {
|
||||||
|
String eventType = event.getPropertyName();
|
||||||
|
if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|
||||||
|
synchronized (ingestLock) {
|
||||||
|
ingestLock.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data source processor progress monitor does nothing. There is
|
||||||
|
* currently no mechanism for showing or recording data source processor
|
||||||
|
* progress during an ingest job.
|
||||||
|
*/
|
||||||
|
private class DoNothingDSPProgressMonitor implements DataSourceProcessorProgressMonitor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing.
|
||||||
|
*
|
||||||
|
* @param indeterminate
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setIndeterminate(final boolean indeterminate) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing.
|
||||||
|
*
|
||||||
|
* @param progress
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setProgress(final int progress) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing.
|
||||||
|
*
|
||||||
|
* @param text
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setProgressText(final String text) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception type thrown when there is a problem analyzing a data source
|
||||||
|
* with data source level and file level ingest modules for an ingest
|
||||||
|
* job.
|
||||||
|
*/
|
||||||
|
private final class AnalysisStartupException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private AnalysisStartupException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnalysisStartupException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CaseFolderFilter implements FilenameFilter {
|
||||||
|
|
||||||
|
private final String caseName;
|
||||||
|
private final static String CASE_METADATA_EXT = CaseMetadata.getFileExtension();
|
||||||
|
|
||||||
|
CaseFolderFilter(String caseName) {
|
||||||
|
this.caseName = caseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(File folder, String fileName) {
|
||||||
|
File file = new File(folder, fileName);
|
||||||
|
if (fileName.length() > TimeStampUtils.getTimeStampLength() && file.isDirectory()) {
|
||||||
|
if (TimeStampUtils.endsWithTimeStamp(fileName)) {
|
||||||
|
if (null != caseName) {
|
||||||
|
String fileNamePrefix = fileName.substring(0, fileName.length() - TimeStampUtils.getTimeStampLength());
|
||||||
|
if (fileNamePrefix.equals(caseName)) {
|
||||||
|
return hasCaseMetadataFile(file);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return hasCaseMetadataFile(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether or not there is a case metadata file in a given
|
||||||
|
* folder.
|
||||||
|
*
|
||||||
|
* @param folder The file object representing the folder to search.
|
||||||
|
*
|
||||||
|
* @return True or false.
|
||||||
|
*/
|
||||||
|
private static boolean hasCaseMetadataFile(File folder) {
|
||||||
|
for (File file : folder.listFiles()) {
|
||||||
|
if (file.getName().toLowerCase().endsWith(CASE_METADATA_EXT) && file.isFile()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,162 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
|
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
</AuxValues>
|
||||||
|
|
||||||
|
<Layout>
|
||||||
|
<DimensionLayout dim="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Component id="nodeScrollPane" alignment="1" pref="864" max="32767" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
<DimensionLayout dim="1">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Component id="nodeScrollPane" alignment="0" pref="421" max="32767" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
</Layout>
|
||||||
|
<SubComponents>
|
||||||
|
<Container class="javax.swing.JScrollPane" name="nodeScrollPane">
|
||||||
|
<Properties>
|
||||||
|
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[0, 0]"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||||
|
<SubComponents>
|
||||||
|
<Container class="javax.swing.JPanel" name="nodePanel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[100, 100]"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
|
||||||
|
<Layout>
|
||||||
|
<DimensionLayout dim="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<Component id="outputPathTextField" min="-2" pref="630" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="browseOutputFolderButton" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<Component id="bnEditIngestSettings" alignment="0" min="-2" pref="155" max="-2" attributes="0"/>
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<Component id="jLabelSelectOutputFolder" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||||
|
<Component id="jLabelInvalidResultsFolder" min="-2" pref="544" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace pref="355" max="32767" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
<DimensionLayout dim="1">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace min="-2" pref="40" max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
|
<Component id="jLabelSelectOutputFolder" alignment="3" min="-2" pref="21" max="-2" attributes="0"/>
|
||||||
|
<Component id="jLabelInvalidResultsFolder" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace min="-2" pref="1" max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
|
<Component id="browseOutputFolderButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="outputPathTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace min="-2" pref="25" max="-2" attributes="0"/>
|
||||||
|
<Component id="bnEditIngestSettings" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace pref="389" max="32767" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
</Layout>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="javax.swing.JButton" name="bnEditIngestSettings">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="viking/commandline/Bundle.properties" key="CommandLineIngestSettingsPanel.bnEditIngestSettings.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="viking/commandline/Bundle.properties" key="CommandLineIngestSettingsPanel.bnEditIngestSettings.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="actionCommand" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commandlineingest/Bundle.properties" key="CommandLineIngestSettingsPanel.bnEditIngestSettings.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnEditIngestSettingsActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="browseOutputFolderButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="viking/commandline/Bundle.properties" key="CommandLineIngestSettingsPanel.browseOutputFolderButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<AccessibilityProperties>
|
||||||
|
<Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commandlineingest/Bundle.properties" key="CommandLineIngestSettingsPanel.browseOutputFolderButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</AccessibilityProperties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseOutputFolderButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JTextField" name="outputPathTextField">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="viking/commandline/Bundle.properties" key="CommandLineIngestSettingsPanel.outputPathTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="viking/commandline/Bundle.properties" key="CommandLineIngestSettingsPanel.outputPathTextField.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="jLabelInvalidResultsFolder">
|
||||||
|
<Properties>
|
||||||
|
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||||
|
<Color blue="0" green="0" red="ff" type="rgb"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="viking/commandline/Bundle.properties" key="CommandLineIngestSettingsPanel.jLabelInvalidResultsFolder.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<AccessibilityProperties>
|
||||||
|
<Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commandlineingest/Bundle.properties" key="CommandLineIngestSettingsPanel.jLabelInvalidResultsFolder.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</AccessibilityProperties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="jLabelSelectOutputFolder">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="viking/commandline/Bundle.properties" key="CommandLineIngestSettingsPanel.jLabelSelectOutputFolder.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="verticalAlignment" type="int" value="3"/>
|
||||||
|
</Properties>
|
||||||
|
<AccessibilityProperties>
|
||||||
|
<Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commandlineingest/Bundle.properties" key="CommandLineIngestSettingsPanel.jLabelSelectOutputFolder.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</AccessibilityProperties>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
@ -0,0 +1,395 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019-2019 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.awt.BorderLayout;
|
||||||
|
import java.awt.Cursor;
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.swing.JFileChooser;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import javax.swing.event.DocumentEvent;
|
||||||
|
import javax.swing.event.DocumentListener;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.FileUtil;
|
||||||
|
import org.openide.windows.WindowManager;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration panel for auto ingest settings.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||||
|
public class CommandLineIngestSettingsPanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
|
private final CommandLineIngestSettingsPanelController controller;
|
||||||
|
private final JFileChooser fc = new JFileChooser();
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static final Logger logger = Logger.getLogger(CommandLineIngestSettingsPanel.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new form AutoIngestSettingsPanel
|
||||||
|
*
|
||||||
|
* @param theController Controller to notify of changes.
|
||||||
|
*/
|
||||||
|
public CommandLineIngestSettingsPanel(CommandLineIngestSettingsPanelController theController) {
|
||||||
|
controller = theController;
|
||||||
|
initComponents();
|
||||||
|
|
||||||
|
load(true);
|
||||||
|
outputPathTextField.getDocument().addDocumentListener(new MyDocumentListener());
|
||||||
|
jLabelInvalidResultsFolder.setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MyDocumentListener implements DocumentListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
valid();
|
||||||
|
controller.changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUpdate(DocumentEvent e) {
|
||||||
|
valid();
|
||||||
|
controller.changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertUpdate(DocumentEvent e) {
|
||||||
|
valid();
|
||||||
|
controller.changed();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load mode from persistent storage.
|
||||||
|
*
|
||||||
|
* @param inStartup True if we're doing the initial population of the UI
|
||||||
|
*/
|
||||||
|
final void load(boolean inStartup) {
|
||||||
|
|
||||||
|
String results = org.sleuthkit.autopsy.commandlineingest.UserPreferences.getCommandLineModeResultsFolder();
|
||||||
|
if (results != null) {
|
||||||
|
outputPathTextField.setText(results);
|
||||||
|
} else {
|
||||||
|
outputPathTextField.setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save mode to persistent storage.
|
||||||
|
*/
|
||||||
|
void store() {
|
||||||
|
String resultsFolderPath = getNormalizedFolderPath(outputPathTextField.getText().trim());
|
||||||
|
org.sleuthkit.autopsy.commandlineingest.UserPreferences.setCommandLineModeResultsFolder(resultsFolderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate current panel settings.
|
||||||
|
*/
|
||||||
|
boolean valid() {
|
||||||
|
|
||||||
|
if (validateResultsPath()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes a path to make sure there are no "space" characters at the end
|
||||||
|
*
|
||||||
|
* @param path Path to a directory
|
||||||
|
*
|
||||||
|
* @return Path without "space" characters at the end
|
||||||
|
*/
|
||||||
|
String normalizePath(String path) {
|
||||||
|
|
||||||
|
while (path.length() > 0) {
|
||||||
|
if (path.charAt(path.length() - 1) == ' ') {
|
||||||
|
path = path.substring(0, path.length() - 1);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates that a path is valid and points to a folder.
|
||||||
|
*
|
||||||
|
* @param path A path to be validated
|
||||||
|
*
|
||||||
|
* @return boolean returns true if valid and points to a folder, false
|
||||||
|
* otherwise
|
||||||
|
*/
|
||||||
|
boolean isFolderPathValid(String path) {
|
||||||
|
try {
|
||||||
|
File file = new File(normalizePath(path));
|
||||||
|
|
||||||
|
// check if it's a symbolic link
|
||||||
|
if (Files.isSymbolicLink(file.toPath())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// local folder
|
||||||
|
if (file.exists() && file.isDirectory()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// Files.isSymbolicLink (and other "files" methods) throw exceptions on seemingly innocent inputs.
|
||||||
|
// For example, it will throw an exception when either " " is last character in path or
|
||||||
|
// a path starting with ":".
|
||||||
|
// We can just ignore these exceptions as they occur in process of user typing in the path.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a path that was normalized by file system.
|
||||||
|
*
|
||||||
|
* @param path A path to be normalized. Normalization occurs inside a call
|
||||||
|
* to new File().
|
||||||
|
*
|
||||||
|
* @return String returns normalized OS path
|
||||||
|
*/
|
||||||
|
String getNormalizedFolderPath(String path) {
|
||||||
|
// removes "/", "\", and " " characters at the end of path string.
|
||||||
|
// normalizePath() removes spaces at the end of path and a call to "new File()"
|
||||||
|
// internally formats the path string to remove "/" and "\" characters at the end of path.
|
||||||
|
File file = new File(normalizePath(path));
|
||||||
|
return file.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate results path. Display warnings if invalid.
|
||||||
|
*/
|
||||||
|
boolean validateResultsPath() {
|
||||||
|
|
||||||
|
String outputPath = outputPathTextField.getText().trim();
|
||||||
|
|
||||||
|
if (outputPath.isEmpty()) {
|
||||||
|
jLabelInvalidResultsFolder.setVisible(true);
|
||||||
|
jLabelInvalidResultsFolder.setText(NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.ResultsDirectoryUnspecified"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isFolderPathValid(outputPath)) {
|
||||||
|
jLabelInvalidResultsFolder.setVisible(true);
|
||||||
|
jLabelInvalidResultsFolder.setText(NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.PathInvalid"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false == permissionsAppropriate(outputPath)) {
|
||||||
|
jLabelInvalidResultsFolder.setVisible(true);
|
||||||
|
jLabelInvalidResultsFolder.setText(NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.CannotAccess")
|
||||||
|
+ " " + outputPath + " "
|
||||||
|
+ NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.CheckPermissions"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
jLabelInvalidResultsFolder.setVisible(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayIngestJobSettingsPanel() {
|
||||||
|
this.getParent().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
|
|
||||||
|
IngestJobSettings ingestJobSettings = new IngestJobSettings(org.sleuthkit.autopsy.commandlineingest.UserPreferences.getCommandLineModeIngestModuleContextString());
|
||||||
|
showWarnings(ingestJobSettings);
|
||||||
|
IngestJobSettingsPanel ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings);
|
||||||
|
|
||||||
|
add(ingestJobSettingsPanel, BorderLayout.PAGE_START);
|
||||||
|
|
||||||
|
if (JOptionPane.showConfirmDialog(this, ingestJobSettingsPanel, "Ingest Module Configuration", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) {
|
||||||
|
// store the updated settings
|
||||||
|
ingestJobSettings = ingestJobSettingsPanel.getSettings();
|
||||||
|
ingestJobSettings.save();
|
||||||
|
showWarnings(ingestJobSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getParent().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void showWarnings(IngestJobSettings ingestJobSettings) {
|
||||||
|
List<String> warnings = ingestJobSettings.getWarnings();
|
||||||
|
if (warnings.isEmpty() == false) {
|
||||||
|
StringBuilder warningMessage = new StringBuilder();
|
||||||
|
for (String warning : warnings) {
|
||||||
|
warningMessage.append(warning).append("\n");
|
||||||
|
}
|
||||||
|
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), warningMessage.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called from within the constructor to initialize the form.
|
||||||
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
|
* regenerated by the Form Editor.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
|
private void initComponents() {
|
||||||
|
|
||||||
|
nodeScrollPane = new javax.swing.JScrollPane();
|
||||||
|
nodePanel = new javax.swing.JPanel();
|
||||||
|
bnEditIngestSettings = new javax.swing.JButton();
|
||||||
|
browseOutputFolderButton = new javax.swing.JButton();
|
||||||
|
outputPathTextField = new javax.swing.JTextField();
|
||||||
|
jLabelInvalidResultsFolder = new javax.swing.JLabel();
|
||||||
|
jLabelSelectOutputFolder = new javax.swing.JLabel();
|
||||||
|
|
||||||
|
nodeScrollPane.setMinimumSize(new java.awt.Dimension(0, 0));
|
||||||
|
|
||||||
|
nodePanel.setMinimumSize(new java.awt.Dimension(100, 100));
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(bnEditIngestSettings, org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.bnEditIngestSettings.text")); // NOI18N
|
||||||
|
bnEditIngestSettings.setToolTipText(org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.bnEditIngestSettings.toolTipText")); // NOI18N
|
||||||
|
bnEditIngestSettings.setActionCommand(org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.bnEditIngestSettings.text")); // NOI18N
|
||||||
|
bnEditIngestSettings.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
bnEditIngestSettingsActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(browseOutputFolderButton, org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.browseOutputFolderButton.text")); // NOI18N
|
||||||
|
browseOutputFolderButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
browseOutputFolderButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
outputPathTextField.setText(org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.outputPathTextField.text")); // NOI18N
|
||||||
|
outputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.outputPathTextField.toolTipText")); // NOI18N
|
||||||
|
|
||||||
|
jLabelInvalidResultsFolder.setForeground(new java.awt.Color(255, 0, 0));
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidResultsFolder, org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.jLabelInvalidResultsFolder.text")); // NOI18N
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectOutputFolder, org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.jLabelSelectOutputFolder.text")); // NOI18N
|
||||||
|
jLabelSelectOutputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM);
|
||||||
|
|
||||||
|
javax.swing.GroupLayout nodePanelLayout = new javax.swing.GroupLayout(nodePanel);
|
||||||
|
nodePanel.setLayout(nodePanelLayout);
|
||||||
|
nodePanelLayout.setHorizontalGroup(
|
||||||
|
nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(nodePanelLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(nodePanelLayout.createSequentialGroup()
|
||||||
|
.addComponent(outputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 630, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(browseOutputFolderButton))
|
||||||
|
.addComponent(bnEditIngestSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addGroup(nodePanelLayout.createSequentialGroup()
|
||||||
|
.addComponent(jLabelSelectOutputFolder)
|
||||||
|
.addGap(18, 18, 18)
|
||||||
|
.addComponent(jLabelInvalidResultsFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 544, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||||
|
.addContainerGap(355, Short.MAX_VALUE))
|
||||||
|
);
|
||||||
|
nodePanelLayout.setVerticalGroup(
|
||||||
|
nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(nodePanelLayout.createSequentialGroup()
|
||||||
|
.addGap(40, 40, 40)
|
||||||
|
.addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
|
.addComponent(jLabelSelectOutputFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addComponent(jLabelInvalidResultsFolder))
|
||||||
|
.addGap(1, 1, 1)
|
||||||
|
.addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
|
.addComponent(browseOutputFolderButton)
|
||||||
|
.addComponent(outputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||||
|
.addGap(25, 25, 25)
|
||||||
|
.addComponent(bnEditIngestSettings)
|
||||||
|
.addContainerGap(389, Short.MAX_VALUE))
|
||||||
|
);
|
||||||
|
|
||||||
|
browseOutputFolderButton.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.browseOutputFolderButton.text")); // NOI18N
|
||||||
|
jLabelInvalidResultsFolder.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.jLabelInvalidResultsFolder.text")); // NOI18N
|
||||||
|
jLabelSelectOutputFolder.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.jLabelSelectOutputFolder.text")); // NOI18N
|
||||||
|
|
||||||
|
nodeScrollPane.setViewportView(nodePanel);
|
||||||
|
|
||||||
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
|
this.setLayout(layout);
|
||||||
|
layout.setHorizontalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(nodeScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 864, Short.MAX_VALUE)
|
||||||
|
);
|
||||||
|
layout.setVerticalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(nodeScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 421, Short.MAX_VALUE)
|
||||||
|
);
|
||||||
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
private void browseOutputFolderButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseOutputFolderButtonActionPerformed
|
||||||
|
String oldText = outputPathTextField.getText().trim();
|
||||||
|
// set the current directory of the FileChooser if the oldText is valid
|
||||||
|
File currentDir = new File(oldText);
|
||||||
|
if (currentDir.exists()) {
|
||||||
|
fc.setCurrentDirectory(currentDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
fc.setDialogTitle("Select case output folder:");
|
||||||
|
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||||
|
|
||||||
|
int retval = fc.showOpenDialog(this);
|
||||||
|
if (retval == JFileChooser.APPROVE_OPTION) {
|
||||||
|
String path = fc.getSelectedFile().getPath();
|
||||||
|
outputPathTextField.setText(path);
|
||||||
|
valid();
|
||||||
|
controller.changed();
|
||||||
|
}
|
||||||
|
}//GEN-LAST:event_browseOutputFolderButtonActionPerformed
|
||||||
|
|
||||||
|
private void bnEditIngestSettingsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnEditIngestSettingsActionPerformed
|
||||||
|
displayIngestJobSettingsPanel();
|
||||||
|
}//GEN-LAST:event_bnEditIngestSettingsActionPerformed
|
||||||
|
|
||||||
|
boolean permissionsAppropriate(String path) {
|
||||||
|
return FileUtil.hasReadWriteAccess(Paths.get(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetUI() {
|
||||||
|
load(true);
|
||||||
|
controller.changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setEnabledState(boolean enabled) {
|
||||||
|
bnEditIngestSettings.setEnabled(enabled);
|
||||||
|
browseOutputFolderButton.setEnabled(enabled);
|
||||||
|
jLabelInvalidResultsFolder.setEnabled(enabled);
|
||||||
|
jLabelSelectOutputFolder.setEnabled(enabled);
|
||||||
|
outputPathTextField.setEnabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JButton bnEditIngestSettings;
|
||||||
|
private javax.swing.JButton browseOutputFolderButton;
|
||||||
|
private javax.swing.JLabel jLabelInvalidResultsFolder;
|
||||||
|
private javax.swing.JLabel jLabelSelectOutputFolder;
|
||||||
|
private javax.swing.JPanel nodePanel;
|
||||||
|
private javax.swing.JScrollPane nodeScrollPane;
|
||||||
|
private javax.swing.JTextField outputPathTextField;
|
||||||
|
// End of variables declaration//GEN-END:variables
|
||||||
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019-2019 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.beans.PropertyChangeListener;
|
||||||
|
import java.beans.PropertyChangeSupport;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import org.netbeans.spi.options.OptionsPanelController;
|
||||||
|
import org.openide.util.HelpCtx;
|
||||||
|
import org.openide.util.Lookup;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
|
||||||
|
@OptionsPanelController.TopLevelRegistration(categoryName = "#OptionsCategory_Name_Command_Line_Ingest",
|
||||||
|
iconBase = "org/sleuthkit/autopsy/images/command_line_icon.png",
|
||||||
|
position = 17,
|
||||||
|
keywords = "#OptionsCategory_Keywords_Command_Line_Ingest_Settings",
|
||||||
|
keywordsCategory = "Command Line Ingest")
|
||||||
|
public final class CommandLineIngestSettingsPanelController extends OptionsPanelController {
|
||||||
|
|
||||||
|
private CommandLineIngestSettingsPanel panel;
|
||||||
|
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
|
||||||
|
private boolean changed;
|
||||||
|
private static final Logger logger = Logger.getLogger(CommandLineIngestSettingsPanelController.class.getName());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update() {
|
||||||
|
getPanel().load(false);
|
||||||
|
changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyChanges() {
|
||||||
|
getPanel().store();
|
||||||
|
changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
return getPanel().valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChanged() {
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HelpCtx getHelpCtx() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JComponent getComponent(Lookup masterLookup) {
|
||||||
|
return getPanel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addPropertyChangeListener(PropertyChangeListener l) {
|
||||||
|
if (pcs.getPropertyChangeListeners().length == 0) {
|
||||||
|
pcs.addPropertyChangeListener(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removePropertyChangeListener(PropertyChangeListener l) {
|
||||||
|
/**
|
||||||
|
* Note the NetBeans Framework does not appear to call this at all. We
|
||||||
|
* are using NetBeans 7.3.1 Build 201306052037. Perhaps in a future
|
||||||
|
* version of the Framework this will be resolved, but for now, simply
|
||||||
|
* don't unregister anything and add one time only in the
|
||||||
|
* addPropertyChangeListener() method above.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommandLineIngestSettingsPanel getPanel() {
|
||||||
|
if (panel == null) {
|
||||||
|
panel = new CommandLineIngestSettingsPanel(this);
|
||||||
|
panel.setSize(750, 600); //makes the panel large enough to hide the scroll bar
|
||||||
|
}
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void changed() {
|
||||||
|
if (!changed) {
|
||||||
|
changed = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "GeneralOptionsPanelController listener threw exception", e); //NON-NLS
|
||||||
|
MessageNotifyUtil.Notify.show(
|
||||||
|
NbBundle.getMessage(this.getClass(), "GeneralOptionsPanelController.moduleErr"),
|
||||||
|
NbBundle.getMessage(this.getClass(), "GeneralOptionsPanelController.moduleErr.msg"),
|
||||||
|
MessageNotifyUtil.MessageType.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "GeneralOptionsPanelController listener threw exception", e); //NON-NLS
|
||||||
|
MessageNotifyUtil.Notify.show(
|
||||||
|
NbBundle.getMessage(this.getClass(), "GeneralOptionsPanelController.moduleErr"),
|
||||||
|
NbBundle.getMessage(this.getClass(), "GeneralOptionsPanelController.moduleErr.msg"),
|
||||||
|
MessageNotifyUtil.MessageType.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
168
Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOptionProcessor.java
Executable file
168
Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineOptionProcessor.java
Executable file
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019-2019 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.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import org.netbeans.api.sendopts.CommandException;
|
||||||
|
import org.netbeans.spi.sendopts.Env;
|
||||||
|
import org.netbeans.spi.sendopts.Option;
|
||||||
|
import org.netbeans.spi.sendopts.OptionProcessor;
|
||||||
|
import org.openide.util.lookup.ServiceProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class can be used to add command line options to Autopsy
|
||||||
|
*/
|
||||||
|
@ServiceProvider(service = OptionProcessor.class)
|
||||||
|
public class CommandLineOptionProcessor extends OptionProcessor {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(CommandLineOptionProcessor.class.getName());
|
||||||
|
private final Option pathToDataSourceOption = Option.optionalArgument('l', "inputPath");
|
||||||
|
private final Option caseNameOption = Option.optionalArgument('2', "caseName");
|
||||||
|
private final Option runFromCommandLineOption = Option.optionalArgument('3', "runFromCommandLine");
|
||||||
|
private String pathToDataSource;
|
||||||
|
private String baseCaseName;
|
||||||
|
private boolean runFromCommandLine = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Set<Option> getOptions() {
|
||||||
|
Set<Option> set = new HashSet<>();
|
||||||
|
set.add(pathToDataSourceOption);
|
||||||
|
set.add(caseNameOption);
|
||||||
|
set.add(runFromCommandLineOption);
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void process(Env env, Map<Option, String[]> values) throws CommandException {
|
||||||
|
logger.log(Level.INFO, "Processing Autopsy command line options"); //NON-NLS
|
||||||
|
System.out.println("Processing Autopsy command line options using CommandLineOptionProcessor");
|
||||||
|
if (values.containsKey(pathToDataSourceOption) && values.containsKey(caseNameOption) && values.containsKey(runFromCommandLineOption)) {
|
||||||
|
// parse input parameters
|
||||||
|
String inputPath;
|
||||||
|
String inputCaseName;
|
||||||
|
String modeString;
|
||||||
|
if (values.size() < 3) {
|
||||||
|
logger.log(Level.SEVERE, "Insufficient number of input arguments. Exiting");
|
||||||
|
System.out.println("Insufficient number of input arguments. Exiting");
|
||||||
|
this.runFromCommandLine = false;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
String[] argDirs = values.get(pathToDataSourceOption);
|
||||||
|
if (argDirs.length < 1) {
|
||||||
|
logger.log(Level.SEVERE, "Missing argument 'inputPath'. Exiting");
|
||||||
|
System.out.println("Missing argument 'inputPath'. Exiting");
|
||||||
|
this.runFromCommandLine = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inputPath = argDirs[0];
|
||||||
|
|
||||||
|
argDirs = values.get(caseNameOption);
|
||||||
|
if (argDirs.length < 1) {
|
||||||
|
logger.log(Level.SEVERE, "Missing argument 'caseName'. Exiting");
|
||||||
|
System.out.println("Missing argument 'caseName'. Exiting");
|
||||||
|
this.runFromCommandLine = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inputCaseName = argDirs[0];
|
||||||
|
|
||||||
|
argDirs = values.get(runFromCommandLineOption);
|
||||||
|
if (argDirs.length < 1) {
|
||||||
|
logger.log(Level.SEVERE, "Missing argument 'runFromCommandLine'. Exiting");
|
||||||
|
System.out.println("Missing argument 'runFromCommandLine'. Exiting");
|
||||||
|
this.runFromCommandLine = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modeString = argDirs[0];
|
||||||
|
|
||||||
|
// verify inputs
|
||||||
|
if (modeString == null || modeString.isEmpty()) {
|
||||||
|
this.runFromCommandLine = false;
|
||||||
|
System.out.println("runFromCommandLine argument is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modeString.equalsIgnoreCase("true")) {
|
||||||
|
this.runFromCommandLine = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("runFromCommandLine = " + this.runFromCommandLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify inputs
|
||||||
|
if (inputPath == null || inputPath.isEmpty() || !(new File(inputPath).exists())) {
|
||||||
|
logger.log(Level.SEVERE, "Input file {0} doesn''t exist. Exiting", inputPath);
|
||||||
|
System.out.println("Input file " + inputPath + " doesn't exist. Exiting");
|
||||||
|
this.runFromCommandLine = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputCaseName == null || inputCaseName.isEmpty()) {
|
||||||
|
logger.log(Level.SEVERE, "Case name argument is empty. Exiting");
|
||||||
|
System.out.println("Case name argument is empty. Exiting");
|
||||||
|
this.runFromCommandLine = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the inputs
|
||||||
|
this.pathToDataSource = inputPath;
|
||||||
|
this.baseCaseName = inputCaseName;
|
||||||
|
logger.log(Level.INFO, "Input file = {0}", this.pathToDataSource); //NON-NLS
|
||||||
|
logger.log(Level.INFO, "Case name = {0}", this.baseCaseName); //NON-NLS
|
||||||
|
logger.log(Level.INFO, "runFromCommandLine = {0}", this.runFromCommandLine); //NON-NLS
|
||||||
|
System.out.println("Input file = " + this.pathToDataSource);
|
||||||
|
System.out.println("Case name = " + this.baseCaseName);
|
||||||
|
System.out.println("runFromCommandLine = " + this.runFromCommandLine);
|
||||||
|
} else {
|
||||||
|
System.out.println("Missing input arguments for CommandLineOptionProcessor. Exiting");
|
||||||
|
logger.log(Level.SEVERE, "Missing input arguments. Exiting");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns user specified path to data source
|
||||||
|
*
|
||||||
|
* @return the inputPath
|
||||||
|
*/
|
||||||
|
String getPathToDataSource() {
|
||||||
|
return pathToDataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns user specified case name
|
||||||
|
*
|
||||||
|
* @return the inputCaseName
|
||||||
|
*/
|
||||||
|
String getBaseCaseName() {
|
||||||
|
return baseCaseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether Autopsy should be running in command line mode or not.
|
||||||
|
*
|
||||||
|
* @return true if running in command line mode, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isRunFromCommandLine() {
|
||||||
|
return runFromCommandLine;
|
||||||
|
}
|
||||||
|
}
|
56
Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLinePanel.form
Executable file
56
Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLinePanel.form
Executable file
@ -0,0 +1,56 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
|
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||||
|
<Properties>
|
||||||
|
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[0, 65]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[403, 65]"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
</AuxValues>
|
||||||
|
|
||||||
|
<Layout>
|
||||||
|
<DimensionLayout dim="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" alignment="1" attributes="0">
|
||||||
|
<EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
|
||||||
|
<Component id="jLabel1" pref="305" max="32767" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
<DimensionLayout dim="1">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace pref="27" max="32767" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
</Layout>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="javax.swing.JLabel" name="jLabel1">
|
||||||
|
<Properties>
|
||||||
|
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||||
|
<Font name="Tahoma" size="18" style="0"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commandlineingest/Bundle.properties" key="CommandLinePanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
71
Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLinePanel.java
Executable file
71
Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLinePanel.java
Executable file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019-2019 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 javax.swing.JPanel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Panel that is displayed when Autopsy is running from command line.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||||
|
class CommandLinePanel extends JPanel {
|
||||||
|
|
||||||
|
CommandLinePanel() {
|
||||||
|
initComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called from within the constructor to initialize the form.
|
||||||
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
|
* regenerated by the Form Editor.
|
||||||
|
*/
|
||||||
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
|
private void initComponents() {
|
||||||
|
|
||||||
|
jLabel1 = new javax.swing.JLabel();
|
||||||
|
|
||||||
|
setMinimumSize(new java.awt.Dimension(0, 65));
|
||||||
|
setPreferredSize(new java.awt.Dimension(403, 65));
|
||||||
|
|
||||||
|
jLabel1.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(CommandLinePanel.class, "CommandLinePanel.jLabel1.text")); // NOI18N
|
||||||
|
|
||||||
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
|
this.setLayout(layout);
|
||||||
|
layout.setHorizontalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||||
|
.addGap(20, 20, 20)
|
||||||
|
.addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, 305, Short.MAX_VALUE)
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
layout.setVerticalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addComponent(jLabel1)
|
||||||
|
.addContainerGap(27, Short.MAX_VALUE))
|
||||||
|
);
|
||||||
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JLabel jLabel1;
|
||||||
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019-2019 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.awt.Dimension;
|
||||||
|
import javax.swing.JDialog;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.windows.WindowManager;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.StartupWindowInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of startup window for running Autopsy from command line.
|
||||||
|
*
|
||||||
|
* IMPORTANT: We do NOT want to register this class as ServiceProvider. We want only
|
||||||
|
* the default Autopsy StartupWindow to be found via
|
||||||
|
* Lookup.getDefault().lookupAll(StartupWindowInterface.class);
|
||||||
|
*/
|
||||||
|
public class CommandLineStartupWindow extends JDialog implements StartupWindowInterface {
|
||||||
|
|
||||||
|
private static final String TITLE = NbBundle.getMessage(CommandLineStartupWindow.class, "CommandLineStartupWindow.title.text");
|
||||||
|
private static final Dimension DIMENSIONS = new Dimension(300, 50);
|
||||||
|
|
||||||
|
public CommandLineStartupWindow() {
|
||||||
|
super(WindowManager.getDefault().getMainWindow(), TITLE, true);
|
||||||
|
setSize(DIMENSIONS);
|
||||||
|
add(new CommandLinePanel());
|
||||||
|
pack();
|
||||||
|
setResizable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void open() {
|
||||||
|
setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
||||||
|
setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
66
Core/src/org/sleuthkit/autopsy/commandlineingest/DataSource.java
Executable file
66
Core/src/org/sleuthkit/autopsy/commandlineingest/DataSource.java
Executable file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019-2019 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.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
|
||||||
|
class DataSource {
|
||||||
|
|
||||||
|
private final String deviceId;
|
||||||
|
private final Path path;
|
||||||
|
private DataSourceProcessorResult resultCode;
|
||||||
|
private List<String> errorMessages;
|
||||||
|
private List<Content> content;
|
||||||
|
|
||||||
|
DataSource(String deviceId, Path path) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path getPath() {
|
||||||
|
return this.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void setDataSourceProcessorOutput(DataSourceProcessorResult result, List<String> errorMessages, List<Content> content) {
|
||||||
|
this.resultCode = result;
|
||||||
|
this.errorMessages = new ArrayList<>(errorMessages);
|
||||||
|
this.content = new ArrayList<>(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized DataSourceProcessorResult getResultDataSourceProcessorResultCode() {
|
||||||
|
return resultCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized List<String> getDataSourceProcessorErrorMessages() {
|
||||||
|
return new ArrayList<>(errorMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized List<Content> getContent() {
|
||||||
|
return new ArrayList<>(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
121
Core/src/org/sleuthkit/autopsy/commandlineingest/DataSourceProcessorUtility.java
Executable file
121
Core/src/org/sleuthkit/autopsy/commandlineingest/DataSourceProcessorUtility.java
Executable file
@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019-2019 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.Path;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.openide.util.Lookup;
|
||||||
|
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
|
||||||
|
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility class to find Data Source Processors
|
||||||
|
*/
|
||||||
|
final class DataSourceProcessorUtility {
|
||||||
|
|
||||||
|
private DataSourceProcessorUtility() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility method to find all Data Source Processors (DSP) that are able
|
||||||
|
* to process the input data source. Only the DSPs that implement
|
||||||
|
* AutoIngestDataSourceProcessor interface are used.
|
||||||
|
*
|
||||||
|
* @param dataSourcePath Full path to the data source
|
||||||
|
* @return Hash map of all DSPs that can process the data source along with
|
||||||
|
* their confidence score
|
||||||
|
* @throws
|
||||||
|
* org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException
|
||||||
|
*/
|
||||||
|
static Map<AutoIngestDataSourceProcessor, Integer> getDataSourceProcessorForFile(Path dataSourcePath, Collection<? extends AutoIngestDataSourceProcessor> processorCandidates) throws AutoIngestDataSourceProcessorException {
|
||||||
|
Map<AutoIngestDataSourceProcessor, Integer> validDataSourceProcessorsMap = new HashMap<>();
|
||||||
|
for (AutoIngestDataSourceProcessor processor : processorCandidates) {
|
||||||
|
int confidence = processor.canProcess(dataSourcePath);
|
||||||
|
if (confidence > 0) {
|
||||||
|
validDataSourceProcessorsMap.put(processor, confidence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return validDataSourceProcessorsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility method to find all Data Source Processors (DSP) that are able
|
||||||
|
* to process the input data source. Only the DSPs that implement
|
||||||
|
* AutoIngestDataSourceProcessor interface are used. Returns ordered list of
|
||||||
|
* data source processors. DSPs are ordered in descending order from highest
|
||||||
|
* confidence to lowest.
|
||||||
|
*
|
||||||
|
* @param dataSourcePath Full path to the data source
|
||||||
|
*
|
||||||
|
* @return Ordered list of data source processors. DSPs are ordered in
|
||||||
|
* descending order from highest confidence to lowest.
|
||||||
|
*
|
||||||
|
* @throws
|
||||||
|
* org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException
|
||||||
|
*/
|
||||||
|
static List<AutoIngestDataSourceProcessor> getOrderedListOfDataSourceProcessors(Path dataSourcePath) throws AutoIngestDataSourceProcessorException {
|
||||||
|
// lookup all AutomatedIngestDataSourceProcessors
|
||||||
|
Collection<? extends AutoIngestDataSourceProcessor> processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class);
|
||||||
|
return getOrderedListOfDataSourceProcessors(dataSourcePath, processorCandidates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility method to find all Data Source Processors (DSP) that are able
|
||||||
|
* to process the input data source. Only the DSPs that implement
|
||||||
|
* AutoIngestDataSourceProcessor interface are used. Returns ordered list of
|
||||||
|
* data source processors. DSPs are ordered in descending order from highest
|
||||||
|
* confidence to lowest.
|
||||||
|
*
|
||||||
|
* @param dataSourcePath Full path to the data source
|
||||||
|
* @param processorCandidates Collection of AutoIngestDataSourceProcessor objects to use
|
||||||
|
*
|
||||||
|
* @return Ordered list of data source processors. DSPs are ordered in
|
||||||
|
* descending order from highest confidence to lowest.
|
||||||
|
*
|
||||||
|
* @throws
|
||||||
|
* org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException
|
||||||
|
*/
|
||||||
|
static List<AutoIngestDataSourceProcessor> getOrderedListOfDataSourceProcessors(Path dataSourcePath, Collection<? extends AutoIngestDataSourceProcessor> processorCandidates) throws AutoIngestDataSourceProcessorException {
|
||||||
|
Map<AutoIngestDataSourceProcessor, Integer> validDataSourceProcessorsMap = getDataSourceProcessorForFile(dataSourcePath, processorCandidates);
|
||||||
|
return orderDataSourceProcessorsByConfidence(validDataSourceProcessorsMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility method to get an ordered list of data source processors. DSPs
|
||||||
|
* are ordered in descending order from highest confidence to lowest.
|
||||||
|
*
|
||||||
|
* @param validDataSourceProcessorsMap Hash map of all DSPs that can process
|
||||||
|
* the data source along with their confidence score
|
||||||
|
* @return Ordered list of data source processors
|
||||||
|
*/
|
||||||
|
static List<AutoIngestDataSourceProcessor> orderDataSourceProcessorsByConfidence(Map<AutoIngestDataSourceProcessor, Integer> validDataSourceProcessorsMap) {
|
||||||
|
List<AutoIngestDataSourceProcessor> validDataSourceProcessors = validDataSourceProcessorsMap.entrySet().stream()
|
||||||
|
.sorted(Map.Entry.<AutoIngestDataSourceProcessor, Integer>comparingByValue().reversed())
|
||||||
|
.map(Map.Entry::getKey)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return validDataSourceProcessors;
|
||||||
|
}
|
||||||
|
}
|
64
Core/src/org/sleuthkit/autopsy/commandlineingest/UserPreferences.java
Executable file
64
Core/src/org/sleuthkit/autopsy/commandlineingest/UserPreferences.java
Executable file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019-2019 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 org.openide.util.NbPreferences;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides convenient access to a UserPreferences node for user preferences
|
||||||
|
* with default values.
|
||||||
|
*/
|
||||||
|
public final class UserPreferences {
|
||||||
|
|
||||||
|
private static final java.util.prefs.Preferences preferences = NbPreferences.forModule(UserPreferences.class);
|
||||||
|
private static final String COMMAND_LINE_MODE_RESULTS_FOLDER = "CommandLineModeResultsFolder"; // NON-NLS
|
||||||
|
private static final String COMMAND_LINE_MODE_CONTEXT_STRING = "CommandLineModeContext"; // NON-NLS
|
||||||
|
|
||||||
|
// Prevent instantiation.
|
||||||
|
private UserPreferences() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get results folder for command line mode from persistent storage.
|
||||||
|
*
|
||||||
|
* @return String Selected output folder.
|
||||||
|
*/
|
||||||
|
public static String getCommandLineModeResultsFolder() {
|
||||||
|
return preferences.get(COMMAND_LINE_MODE_RESULTS_FOLDER, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set results folder for command line mode from persistent storage.
|
||||||
|
*
|
||||||
|
* @param folder Selected output folder.
|
||||||
|
*/
|
||||||
|
public static void setCommandLineModeResultsFolder(String folder) {
|
||||||
|
preferences.put(COMMAND_LINE_MODE_RESULTS_FOLDER, folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get context string for command line mode ingest module settings.
|
||||||
|
*
|
||||||
|
* @return String Context string for command line mode ingest module
|
||||||
|
* settings.
|
||||||
|
*/
|
||||||
|
public static String getCommandLineModeIngestModuleContextString() {
|
||||||
|
return COMMAND_LINE_MODE_CONTEXT_STRING;
|
||||||
|
}
|
||||||
|
}
|
@ -32,8 +32,10 @@ GstVideoPanel.progress.buffering=Buffering...
|
|||||||
GstVideoPanel.progressLabel.bufferingErr=Error buffering file
|
GstVideoPanel.progressLabel.bufferingErr=Error buffering file
|
||||||
GstVideoPanel.progress.infoLabel.updateErr=Error updating video progress: {0}
|
GstVideoPanel.progress.infoLabel.updateErr=Error updating video progress: {0}
|
||||||
GstVideoPanel.ExtractMedia.progress.buffering=Buffering {0}
|
GstVideoPanel.ExtractMedia.progress.buffering=Buffering {0}
|
||||||
|
Html_text_display_error=The HTML text cannot be displayed, it may not be correctly formed HTML.
|
||||||
HtmlPanel_showImagesToggleButton_hide=Hide Images
|
HtmlPanel_showImagesToggleButton_hide=Hide Images
|
||||||
HtmlPanel_showImagesToggleButton_show=Show Images
|
HtmlPanel_showImagesToggleButton_show=Show Images
|
||||||
|
HtmlViewer_file_error=This file is missing or unreadable.
|
||||||
MediaFileViewer.AccessibleContext.accessibleDescription=
|
MediaFileViewer.AccessibleContext.accessibleDescription=
|
||||||
MediaFileViewer.title=Media
|
MediaFileViewer.title=Media
|
||||||
MediaFileViewer.toolTip=Displays supported multimedia files (images, videos, audio)
|
MediaFileViewer.toolTip=Displays supported multimedia files (images, videos, audio)
|
||||||
|
@ -92,20 +92,24 @@ final class HtmlPanel extends javax.swing.JPanel {
|
|||||||
*/
|
*/
|
||||||
@Messages({
|
@Messages({
|
||||||
"HtmlPanel_showImagesToggleButton_show=Show Images",
|
"HtmlPanel_showImagesToggleButton_show=Show Images",
|
||||||
"HtmlPanel_showImagesToggleButton_hide=Hide Images"
|
"HtmlPanel_showImagesToggleButton_hide=Hide Images",
|
||||||
|
"Html_text_display_error=The HTML text cannot be displayed, it may not be correctly formed HTML.",
|
||||||
})
|
})
|
||||||
private void refresh() {
|
private void refresh() {
|
||||||
if (false == htmlText.isEmpty()) {
|
if (false == htmlText.isEmpty()) {
|
||||||
if (showImagesToggleButton.isSelected()) {
|
try {
|
||||||
showImagesToggleButton.setText(Bundle.HtmlPanel_showImagesToggleButton_hide());
|
if (showImagesToggleButton.isSelected()) {
|
||||||
this.htmlbodyTextPane.setText(wrapInHtmlBody(htmlText));
|
showImagesToggleButton.setText(Bundle.HtmlPanel_showImagesToggleButton_hide());
|
||||||
} else {
|
this.htmlbodyTextPane.setText(wrapInHtmlBody(htmlText));
|
||||||
showImagesToggleButton.setText(Bundle.HtmlPanel_showImagesToggleButton_show());
|
} else {
|
||||||
this.htmlbodyTextPane.setText(wrapInHtmlBody(cleanseHTML(htmlText)));
|
showImagesToggleButton.setText(Bundle.HtmlPanel_showImagesToggleButton_show());
|
||||||
|
this.htmlbodyTextPane.setText(wrapInHtmlBody(cleanseHTML(htmlText)));
|
||||||
|
}
|
||||||
|
showImagesToggleButton.setEnabled(true);
|
||||||
|
htmlbodyTextPane.setCaretPosition(0);
|
||||||
|
} catch(Exception ex) {
|
||||||
|
this.htmlbodyTextPane.setText(wrapInHtmlBody(Bundle.Html_text_display_error()));
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlbodyTextPane.setCaretPosition(0);
|
|
||||||
showImagesToggleButton.setEnabled(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import java.awt.Cursor;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.windows.WindowManager;
|
import org.openide.windows.WindowManager;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
@ -56,6 +57,9 @@ final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer {
|
|||||||
*
|
*
|
||||||
* @return The text content of the file.
|
* @return The text content of the file.
|
||||||
*/
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"HtmlViewer_file_error=This file is missing or unreadable.",
|
||||||
|
})
|
||||||
private String getHtmlText(AbstractFile abstractFile) {
|
private String getHtmlText(AbstractFile abstractFile) {
|
||||||
try {
|
try {
|
||||||
int fileSize = (int) abstractFile.getSize();
|
int fileSize = (int) abstractFile.getSize();
|
||||||
@ -65,9 +69,8 @@ final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer {
|
|||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, String.format("Unable to read from file '%s' (id=%d).",
|
logger.log(Level.SEVERE, String.format("Unable to read from file '%s' (id=%d).",
|
||||||
abstractFile.getName(), abstractFile.getId()), ex);
|
abstractFile.getName(), abstractFile.getId()), ex);
|
||||||
|
return String.format("<p>%s</p>", Bundle.HtmlViewer_file_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
BIN
Core/src/org/sleuthkit/autopsy/images/command_line_icon.png
Executable file
BIN
Core/src/org/sleuthkit/autopsy/images/command_line_icon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 474 B |
@ -1,9 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
*
|
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2012-2018 Basis Technology Corp.
|
* Copyright 2018-2019 Basis Technology Corp.
|
||||||
* Project Contact/Architect: 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");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -17,21 +16,20 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.modules.case_uco;
|
package org.sleuthkit.autopsy.report.caseuco;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import com.fasterxml.jackson.core.JsonEncoding;
|
import com.fasterxml.jackson.core.JsonEncoding;
|
||||||
import com.fasterxml.jackson.core.JsonFactory;
|
import com.fasterxml.jackson.core.JsonFactory;
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
import com.fasterxml.jackson.core.util.DefaultIndenter;
|
import com.fasterxml.jackson.core.util.DefaultIndenter;
|
||||||
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
|
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.SimpleTimeZone;
|
import java.util.SimpleTimeZone;
|
||||||
|
import java.util.logging.Level;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
@ -39,44 +37,30 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
|||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
import org.sleuthkit.autopsy.report.GeneralReportModule;
|
|
||||||
import org.sleuthkit.autopsy.report.ReportProgressPanel;
|
import org.sleuthkit.autopsy.report.ReportProgressPanel;
|
||||||
import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.*;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ReportCaseUco generates a report in the CASE-UCO format. It saves basic
|
* Generates CASE-UCO report file for a data source
|
||||||
file info like full caseDirPath, name, MIME type, times, and hash.
|
|
||||||
*/
|
*/
|
||||||
class ReportCaseUco implements GeneralReportModule {
|
public final class CaseUcoFormatExporter {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(ReportCaseUco.class.getName());
|
private static final Logger logger = Logger.getLogger(CaseUcoFormatExporter.class.getName());
|
||||||
private static ReportCaseUco instance = null;
|
|
||||||
private ReportCaseUcoConfigPanel configPanel;
|
|
||||||
|
|
||||||
private static final String REPORT_FILE_NAME = "CASE_UCO_output.json-ld";
|
private CaseUcoFormatExporter() {
|
||||||
|
|
||||||
// Hidden constructor for the report
|
|
||||||
private ReportCaseUco() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the default implementation of this report
|
|
||||||
public static synchronized ReportCaseUco getDefault() {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new ReportCaseUco();
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a CASE-UCO format report.
|
* Generates CASE-UCO report for the selected data source.
|
||||||
*
|
*
|
||||||
* @param baseReportDir caseDirPath to save the report
|
* @param selectedDataSourceId Object ID of the data source
|
||||||
* @param progressPanel panel to update the report's progress
|
* @param reportOutputPath Full path to directory where to save CASE-UCO
|
||||||
|
* report file
|
||||||
|
* @param progressPanel ReportProgressPanel to update progress
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"ReportCaseUco.notInitialized=CASE-UCO settings panel has not been initialized",
|
|
||||||
"ReportCaseUco.noDataSourceSelected=No data source selected for CASE-UCO report",
|
|
||||||
"ReportCaseUco.noCaseOpen=Unable to open currect case",
|
"ReportCaseUco.noCaseOpen=Unable to open currect case",
|
||||||
"ReportCaseUco.unableToCreateDirectories=Unable to create directory for CASE-UCO report",
|
"ReportCaseUco.unableToCreateDirectories=Unable to create directory for CASE-UCO report",
|
||||||
"ReportCaseUco.initializing=Creating directories...",
|
"ReportCaseUco.initializing=Creating directories...",
|
||||||
@ -85,24 +69,8 @@ class ReportCaseUco implements GeneralReportModule {
|
|||||||
"ReportCaseUco.processing=Saving files in CASE-UCO format...",
|
"ReportCaseUco.processing=Saving files in CASE-UCO format...",
|
||||||
"ReportCaseUco.srcModuleName.text=CASE-UCO Report"
|
"ReportCaseUco.srcModuleName.text=CASE-UCO Report"
|
||||||
})
|
})
|
||||||
@Override
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public void generateReport(String baseReportDir, ReportProgressPanel progressPanel) {
|
public static void generateReport(Long selectedDataSourceId, String reportOutputPath, ReportProgressPanel progressPanel) {
|
||||||
|
|
||||||
if (configPanel == null) {
|
|
||||||
logger.log(Level.SEVERE, "CASE-UCO settings panel has not been initialized"); //NON-NLS
|
|
||||||
MessageNotifyUtil.Message.error(Bundle.ReportCaseUco_notInitialized());
|
|
||||||
progressPanel.complete(ReportStatus.ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Long selectedDataSourceId = configPanel.getSelectedDataSourceId();
|
|
||||||
if (selectedDataSourceId == ReportCaseUcoConfigPanel.NO_DATA_SOURCE_SELECTED) {
|
|
||||||
logger.log(Level.SEVERE, "No data source selected for CASE-UCO report"); //NON-NLS
|
|
||||||
MessageNotifyUtil.Message.error(Bundle.ReportCaseUco_noDataSourceSelected());
|
|
||||||
progressPanel.complete(ReportStatus.ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the progress bar and setup the report
|
// Start the progress bar and setup the report
|
||||||
progressPanel.setIndeterminate(false);
|
progressPanel.setIndeterminate(false);
|
||||||
@ -111,14 +79,13 @@ class ReportCaseUco implements GeneralReportModule {
|
|||||||
|
|
||||||
// Create the JSON generator
|
// Create the JSON generator
|
||||||
JsonFactory jsonGeneratorFactory = new JsonFactory();
|
JsonFactory jsonGeneratorFactory = new JsonFactory();
|
||||||
String reportPath = baseReportDir + getRelativeFilePath();
|
java.io.File reportFile = Paths.get(reportOutputPath).toFile();
|
||||||
java.io.File reportFile = Paths.get(reportPath).toFile();
|
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(Paths.get(reportFile.getParent()));
|
Files.createDirectories(Paths.get(reportFile.getParent()));
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
logger.log(Level.SEVERE, "Unable to create directory for CASE-UCO report", ex); //NON-NLS
|
logger.log(Level.SEVERE, "Unable to create directory for CASE-UCO report", ex); //NON-NLS
|
||||||
MessageNotifyUtil.Message.error(Bundle.ReportCaseUco_unableToCreateDirectories());
|
MessageNotifyUtil.Message.error(Bundle.ReportCaseUco_unableToCreateDirectories());
|
||||||
progressPanel.complete(ReportStatus.ERROR);
|
progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +94,6 @@ class ReportCaseUco implements GeneralReportModule {
|
|||||||
MessageNotifyUtil.Message.warn(Bundle.ReportCaseUco_ingestWarning());
|
MessageNotifyUtil.Message.warn(Bundle.ReportCaseUco_ingestWarning());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
JsonGenerator jsonGenerator = null;
|
JsonGenerator jsonGenerator = null;
|
||||||
SimpleTimeZone timeZone = new SimpleTimeZone(0, "GMT");
|
SimpleTimeZone timeZone = new SimpleTimeZone(0, "GMT");
|
||||||
try {
|
try {
|
||||||
@ -163,7 +129,7 @@ class ReportCaseUco implements GeneralReportModule {
|
|||||||
// Loop files and write info to CASE-UCO report
|
// Loop files and write info to CASE-UCO report
|
||||||
while (resultSet.next()) {
|
while (resultSet.next()) {
|
||||||
|
|
||||||
if (progressPanel.getStatus() == ReportStatus.CANCELED) {
|
if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,21 +151,21 @@ class ReportCaseUco implements GeneralReportModule {
|
|||||||
// create the required CASE-UCO entries at the end of the output file
|
// create the required CASE-UCO entries at the end of the output file
|
||||||
finilizeJsonOutputFile(jsonGenerator);
|
finilizeJsonOutputFile(jsonGenerator);
|
||||||
|
|
||||||
Case.getCurrentCaseThrows().addReport(reportPath, Bundle.ReportCaseUco_srcModuleName_text(), "");
|
Case.getCurrentCaseThrows().addReport(reportOutputPath, Bundle.ReportCaseUco_srcModuleName_text(), "");
|
||||||
|
|
||||||
progressPanel.complete(ReportStatus.COMPLETE);
|
progressPanel.complete(ReportProgressPanel.ReportStatus.COMPLETE);
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Failed to get list of files from case database", ex); //NON-NLS
|
logger.log(Level.SEVERE, "Failed to get list of files from case database", ex); //NON-NLS
|
||||||
progressPanel.complete(ReportStatus.ERROR);
|
progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
logger.log(Level.SEVERE, "Failed to create JSON output for the CASE-UCO report", ex); //NON-NLS
|
logger.log(Level.SEVERE, "Failed to create JSON output for the CASE-UCO report", ex); //NON-NLS
|
||||||
progressPanel.complete(ReportStatus.ERROR);
|
progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR);
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logger.log(Level.WARNING, "Unable to read result set", ex); //NON-NLS
|
logger.log(Level.WARNING, "Unable to read result set", ex); //NON-NLS
|
||||||
progressPanel.complete(ReportStatus.ERROR);
|
progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR);
|
||||||
} catch (NoCurrentCaseException ex) {
|
} catch (NoCurrentCaseException ex) {
|
||||||
logger.log(Level.SEVERE, "No current case open", ex); //NON-NLS
|
logger.log(Level.SEVERE, "No current case open", ex); //NON-NLS
|
||||||
progressPanel.complete(ReportStatus.ERROR);
|
progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR);
|
||||||
} finally {
|
} finally {
|
||||||
if (jsonGenerator != null) {
|
if (jsonGenerator != null) {
|
||||||
try {
|
try {
|
||||||
@ -211,18 +177,29 @@ class ReportCaseUco implements GeneralReportModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeJsonOutputFile(JsonGenerator catalog) throws IOException {
|
private static void initializeJsonOutputFile(JsonGenerator catalog) throws IOException {
|
||||||
catalog.writeStartObject();
|
catalog.writeStartObject();
|
||||||
catalog.writeFieldName("@graph");
|
catalog.writeFieldName("@graph");
|
||||||
catalog.writeStartArray();
|
catalog.writeStartArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finilizeJsonOutputFile(JsonGenerator catalog) throws IOException {
|
private static void finilizeJsonOutputFile(JsonGenerator catalog) throws IOException {
|
||||||
catalog.writeEndArray();
|
catalog.writeEndArray();
|
||||||
catalog.writeEndObject();
|
catalog.writeEndObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String saveCaseInfo(SleuthkitCase skCase, JsonGenerator catalog) throws TskCoreException, SQLException, IOException, NoCurrentCaseException {
|
/**
|
||||||
|
* Save info about the Autopsy case in CASE-UCo format
|
||||||
|
*
|
||||||
|
* @param skCase SleuthkitCase object
|
||||||
|
* @param catalog JsonGenerator object
|
||||||
|
* @return CASE-UCO trace ID object for the Autopsy case entry
|
||||||
|
* @throws TskCoreException
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws IOException
|
||||||
|
* @throws NoCurrentCaseException
|
||||||
|
*/
|
||||||
|
private static String saveCaseInfo(SleuthkitCase skCase, JsonGenerator catalog) throws TskCoreException, SQLException, IOException, NoCurrentCaseException {
|
||||||
|
|
||||||
// create a "trace" entry for the Autopsy case iteself
|
// create a "trace" entry for the Autopsy case iteself
|
||||||
String uniqueCaseName;
|
String uniqueCaseName;
|
||||||
@ -265,7 +242,19 @@ class ReportCaseUco implements GeneralReportModule {
|
|||||||
return caseTraceId;
|
return caseTraceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String saveDataSourceInfo(Long selectedDataSourceId, String caseTraceId, SleuthkitCase skCase, JsonGenerator jsonGenerator) throws TskCoreException, SQLException, IOException {
|
/**
|
||||||
|
* Save info about the data source in CASE-UCo format
|
||||||
|
*
|
||||||
|
* @param selectedDataSourceId Object ID of the data source
|
||||||
|
* @param caseTraceId CASE-UCO trace ID object for the Autopsy case entry
|
||||||
|
* @param skCase SleuthkitCase object
|
||||||
|
* @param catalog JsonGenerator object
|
||||||
|
* @return
|
||||||
|
* @throws TskCoreException
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private static String saveDataSourceInfo(Long selectedDataSourceId, String caseTraceId, SleuthkitCase skCase, JsonGenerator jsonGenerator) throws TskCoreException, SQLException, IOException {
|
||||||
|
|
||||||
Long imageSize = (long) 0;
|
Long imageSize = (long) 0;
|
||||||
String imageName = "";
|
String imageName = "";
|
||||||
@ -307,10 +296,10 @@ class ReportCaseUco implements GeneralReportModule {
|
|||||||
return saveDataSourceInCaseUcoFormat(jsonGenerator, imageName, imageSize, selectedDataSourceId, caseTraceId);
|
return saveDataSourceInCaseUcoFormat(jsonGenerator, imageName, imageSize, selectedDataSourceId, caseTraceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String saveDataSourceInCaseUcoFormat(JsonGenerator catalog, String imageName, Long imageSize, Long selectedDataSourceId, String caseTraceId) throws IOException {
|
private static String saveDataSourceInCaseUcoFormat(JsonGenerator catalog, String imageName, Long imageSize, Long selectedDataSourceId, String caseTraceId) throws IOException {
|
||||||
|
|
||||||
// create a "trace" entry for the data source
|
// create a "trace" entry for the data source
|
||||||
String dataSourceTraceId = "data-source-"+selectedDataSourceId;
|
String dataSourceTraceId = "data-source-" + selectedDataSourceId;
|
||||||
catalog.writeStartObject();
|
catalog.writeStartObject();
|
||||||
catalog.writeStringField("@id", dataSourceTraceId);
|
catalog.writeStringField("@id", dataSourceTraceId);
|
||||||
catalog.writeStringField("@type", "Trace");
|
catalog.writeStringField("@type", "Trace");
|
||||||
@ -359,7 +348,7 @@ class ReportCaseUco implements GeneralReportModule {
|
|||||||
return dataSourceTraceId;
|
return dataSourceTraceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveFileInCaseUcoFormat(Long objectId, String fileName, String parent_path, String md5Hash, String mime_type, long size, String ctime,
|
private static void saveFileInCaseUcoFormat(Long objectId, String fileName, String parent_path, String md5Hash, String mime_type, long size, String ctime,
|
||||||
String atime, String mtime, String extension, JsonGenerator catalog, String dataSourceTraceId) throws IOException {
|
String atime, String mtime, String extension, JsonGenerator catalog, String dataSourceTraceId) throws IOException {
|
||||||
|
|
||||||
String fileTraceId = "file-" + objectId;
|
String fileTraceId = "file-" + objectId;
|
||||||
@ -433,33 +422,4 @@ class ReportCaseUco implements GeneralReportModule {
|
|||||||
|
|
||||||
catalog.writeEndObject();
|
catalog.writeEndObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
String name = NbBundle.getMessage(this.getClass(), "ReportCaseUco.getName.text");
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getRelativeFilePath() {
|
|
||||||
return REPORT_FILE_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
String desc = NbBundle.getMessage(this.getClass(), "ReportCaseUco.getDesc.text");
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JPanel getConfigurationPanel() {
|
|
||||||
try {
|
|
||||||
configPanel = new ReportCaseUcoConfigPanel();
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Failed to initialize CASE-UCO settings panel", ex); //NON-NLS
|
|
||||||
MessageNotifyUtil.Message.error(Bundle.ReportCaseUco_notInitialized());
|
|
||||||
configPanel = null;
|
|
||||||
}
|
|
||||||
return configPanel;
|
|
||||||
}
|
|
||||||
}
|
}
|
128
Core/src/org/sleuthkit/autopsy/report/caseuco/ReportCaseUco.java
Executable file
128
Core/src/org/sleuthkit/autopsy/report/caseuco/ReportCaseUco.java
Executable file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2018-2019 Basis Technology Corp.
|
||||||
|
* Project Contact/Architect: 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.report.caseuco;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
|
import org.sleuthkit.autopsy.report.GeneralReportModule;
|
||||||
|
import org.sleuthkit.autopsy.report.ReportProgressPanel;
|
||||||
|
import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus;
|
||||||
|
import org.sleuthkit.datamodel.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ReportCaseUco generates a report in the CASE-UCO format. It saves basic file
|
||||||
|
* info like full caseDirPath, name, MIME type, times, and hash.
|
||||||
|
*/
|
||||||
|
public final class ReportCaseUco implements GeneralReportModule {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(ReportCaseUco.class.getName());
|
||||||
|
private static ReportCaseUco instance = null;
|
||||||
|
private ReportCaseUcoConfigPanel configPanel;
|
||||||
|
|
||||||
|
private static final String REPORT_FILE_NAME = "CASE_UCO_output.json-ld";
|
||||||
|
|
||||||
|
// Hidden constructor for the report
|
||||||
|
private ReportCaseUco() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the default implementation of this report
|
||||||
|
public static synchronized ReportCaseUco getDefault() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new ReportCaseUco();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
String name = NbBundle.getMessage(this.getClass(), "ReportCaseUco.getName.text");
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRelativeFilePath() {
|
||||||
|
return REPORT_FILE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
String desc = NbBundle.getMessage(this.getClass(), "ReportCaseUco.getDesc.text");
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JPanel getConfigurationPanel() {
|
||||||
|
try {
|
||||||
|
configPanel = new ReportCaseUcoConfigPanel();
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to initialize CASE-UCO settings panel", ex); //NON-NLS
|
||||||
|
MessageNotifyUtil.Message.error(Bundle.ReportCaseUco_notInitialized());
|
||||||
|
configPanel = null;
|
||||||
|
}
|
||||||
|
return configPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns CASE-UCO report file name
|
||||||
|
*
|
||||||
|
* @return the REPORT_FILE_NAME
|
||||||
|
*/
|
||||||
|
public static String getReportFileName() {
|
||||||
|
return REPORT_FILE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a CASE-UCO format report.
|
||||||
|
*
|
||||||
|
* @param baseReportDir caseDirPath to save the report
|
||||||
|
* @param progressPanel panel to update the report's progress
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"ReportCaseUco.notInitialized=CASE-UCO settings panel has not been initialized",
|
||||||
|
"ReportCaseUco.noDataSourceSelected=No data source selected for CASE-UCO report"
|
||||||
|
})
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public void generateReport(String baseReportDir, ReportProgressPanel progressPanel) {
|
||||||
|
|
||||||
|
if (configPanel == null) {
|
||||||
|
logger.log(Level.SEVERE, "CASE-UCO settings panel has not been initialized"); //NON-NLS
|
||||||
|
MessageNotifyUtil.Message.error(Bundle.ReportCaseUco_notInitialized());
|
||||||
|
progressPanel.complete(ReportStatus.ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Long selectedDataSourceId = configPanel.getSelectedDataSourceId();
|
||||||
|
if (selectedDataSourceId == ReportCaseUcoConfigPanel.NO_DATA_SOURCE_SELECTED) {
|
||||||
|
logger.log(Level.SEVERE, "No data source selected for CASE-UCO report"); //NON-NLS
|
||||||
|
MessageNotifyUtil.Message.error(Bundle.ReportCaseUco_noDataSourceSelected());
|
||||||
|
progressPanel.complete(ReportStatus.ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String reportPath = baseReportDir + getRelativeFilePath();
|
||||||
|
CaseUcoFormatExporter.generateReport(selectedDataSourceId, reportPath, progressPanel);
|
||||||
|
}
|
||||||
|
}
|
@ -56,7 +56,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="jLabelSelectDataSource">
|
<Component class="javax.swing.JLabel" name="jLabelSelectDataSource">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/modules/case_uco/Bundle.properties" key="ReportCaseUcoConfigPanel.jLabelSelectDataSource.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/report/caseuco/Bundle.properties" key="ReportCaseUcoConfigPanel.jLabelSelectDataSource.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<AuxValues>
|
<AuxValues>
|
@ -2,7 +2,7 @@
|
|||||||
*
|
*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2018 Basis Technology Corp.
|
* Copyright 2019-2019 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");
|
||||||
@ -17,7 +17,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.modules.case_uco;
|
package org.sleuthkit.autopsy.report.caseuco;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.sleuthkit.autopsy.experimental.configuration;
|
|
||||||
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface to run an ingest job in the background.
|
|
||||||
*/
|
|
||||||
public interface IngestJobRunningService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts the service
|
|
||||||
*/
|
|
||||||
void start();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops the service
|
|
||||||
*/
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a panel to be displayed while using this service
|
|
||||||
*
|
|
||||||
* @return panel to be displayed while using this service
|
|
||||||
*/
|
|
||||||
JPanel getStartupWindow();
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user