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/output/*
|
||||
!/test/output/gold
|
||||
/test/script/output_dir_link.txt
|
||||
/test/output/gold/tmp
|
||||
/test/script/ScriptLog.txt
|
||||
/test/script/__pycache__/
|
||||
|
@ -21,7 +21,11 @@ package org.sleuthkit.autopsy.casemodule;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.logging.Level;
|
||||
import org.netbeans.spi.sendopts.OptionProcessor;
|
||||
import org.openide.util.Lookup;
|
||||
import org.sleuthkit.autopsy.commandlineingest.CommandLineIngestManager;
|
||||
import org.sleuthkit.autopsy.commandlineingest.CommandLineOptionProcessor;
|
||||
import org.sleuthkit.autopsy.commandlineingest.CommandLineStartupWindow;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
/**
|
||||
@ -54,6 +58,17 @@ public class StartupWindowProvider implements StartupWindowInterface {
|
||||
|
||||
private void init() {
|
||||
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
|
||||
Collection<? extends StartupWindowInterface> startupWindows
|
||||
= 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
|
||||
public void open() {
|
||||
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.progress.infoLabel.updateErr=Error updating video progress: {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_show=Show Images
|
||||
HtmlViewer_file_error=This file is missing or unreadable.
|
||||
MediaFileViewer.AccessibleContext.accessibleDescription=
|
||||
MediaFileViewer.title=Media
|
||||
MediaFileViewer.toolTip=Displays supported multimedia files (images, videos, audio)
|
||||
|
@ -92,20 +92,24 @@ final class HtmlPanel extends javax.swing.JPanel {
|
||||
*/
|
||||
@Messages({
|
||||
"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() {
|
||||
if (false == htmlText.isEmpty()) {
|
||||
if (showImagesToggleButton.isSelected()) {
|
||||
showImagesToggleButton.setText(Bundle.HtmlPanel_showImagesToggleButton_hide());
|
||||
this.htmlbodyTextPane.setText(wrapInHtmlBody(htmlText));
|
||||
} else {
|
||||
showImagesToggleButton.setText(Bundle.HtmlPanel_showImagesToggleButton_show());
|
||||
this.htmlbodyTextPane.setText(wrapInHtmlBody(cleanseHTML(htmlText)));
|
||||
try {
|
||||
if (showImagesToggleButton.isSelected()) {
|
||||
showImagesToggleButton.setText(Bundle.HtmlPanel_showImagesToggleButton_hide());
|
||||
this.htmlbodyTextPane.setText(wrapInHtmlBody(htmlText));
|
||||
} else {
|
||||
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.List;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
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.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"HtmlViewer_file_error=This file is missing or unreadable.",
|
||||
})
|
||||
private String getHtmlText(AbstractFile abstractFile) {
|
||||
try {
|
||||
int fileSize = (int) abstractFile.getSize();
|
||||
@ -65,9 +69,8 @@ final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Unable to read from file '%s' (id=%d).",
|
||||
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,37 +1,35 @@
|
||||
/*
|
||||
*
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012-2018 Basis Technology Corp.
|
||||
* Project Contact/Architect: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
*
|
||||
* Copyright 2018-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.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.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.util.DefaultIndenter;
|
||||
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.SQLException;
|
||||
import java.util.SimpleTimeZone;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
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.datamodel.ContentUtils;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.report.GeneralReportModule;
|
||||
import org.sleuthkit.autopsy.report.ReportProgressPanel;
|
||||
import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus;
|
||||
import org.sleuthkit.datamodel.*;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* ReportCaseUco generates a report in the CASE-UCO format. It saves basic
|
||||
file info like full caseDirPath, name, MIME type, times, and hash.
|
||||
* Generates CASE-UCO report file for a data source
|
||||
*/
|
||||
class ReportCaseUco implements GeneralReportModule {
|
||||
public final class CaseUcoFormatExporter {
|
||||
|
||||
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() {
|
||||
}
|
||||
private static final Logger logger = Logger.getLogger(CaseUcoFormatExporter.class.getName());
|
||||
|
||||
// Get the default implementation of this report
|
||||
public static synchronized ReportCaseUco getDefault() {
|
||||
if (instance == null) {
|
||||
instance = new ReportCaseUco();
|
||||
}
|
||||
return instance;
|
||||
private CaseUcoFormatExporter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a CASE-UCO format report.
|
||||
* Generates CASE-UCO report for the selected data source.
|
||||
*
|
||||
* @param baseReportDir caseDirPath to save the report
|
||||
* @param progressPanel panel to update the report's progress
|
||||
* @param selectedDataSourceId Object ID of the data source
|
||||
* @param reportOutputPath Full path to directory where to save CASE-UCO
|
||||
* report file
|
||||
* @param progressPanel ReportProgressPanel to update progress
|
||||
*/
|
||||
@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.unableToCreateDirectories=Unable to create directory for CASE-UCO report",
|
||||
"ReportCaseUco.initializing=Creating directories...",
|
||||
@ -85,88 +69,70 @@ class ReportCaseUco implements GeneralReportModule {
|
||||
"ReportCaseUco.processing=Saving files in CASE-UCO format...",
|
||||
"ReportCaseUco.srcModuleName.text=CASE-UCO Report"
|
||||
})
|
||||
@Override
|
||||
@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
|
||||
progressPanel.setIndeterminate(false);
|
||||
progressPanel.start();
|
||||
progressPanel.updateStatusLabel(Bundle.ReportCaseUco_initializing());
|
||||
|
||||
|
||||
// Create the JSON generator
|
||||
JsonFactory jsonGeneratorFactory = new JsonFactory();
|
||||
String reportPath = baseReportDir + getRelativeFilePath();
|
||||
java.io.File reportFile = Paths.get(reportPath).toFile();
|
||||
java.io.File reportFile = Paths.get(reportOutputPath).toFile();
|
||||
try {
|
||||
Files.createDirectories(Paths.get(reportFile.getParent()));
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, "Unable to create directory for CASE-UCO report", ex); //NON-NLS
|
||||
MessageNotifyUtil.Message.error(Bundle.ReportCaseUco_unableToCreateDirectories());
|
||||
progressPanel.complete(ReportStatus.ERROR);
|
||||
progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Check if ingest has finished
|
||||
if (IngestManager.getInstance().isIngestRunning()) {
|
||||
MessageNotifyUtil.Message.warn(Bundle.ReportCaseUco_ingestWarning());
|
||||
}
|
||||
|
||||
|
||||
JsonGenerator jsonGenerator = null;
|
||||
SimpleTimeZone timeZone = new SimpleTimeZone(0, "GMT");
|
||||
try {
|
||||
jsonGenerator = jsonGeneratorFactory.createGenerator(reportFile, JsonEncoding.UTF8);
|
||||
// instert \n after each field for more readable formatting
|
||||
jsonGenerator.setPrettyPrinter(new DefaultPrettyPrinter().withObjectIndenter(new DefaultIndenter(" ", "\n")));
|
||||
|
||||
|
||||
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
|
||||
|
||||
|
||||
progressPanel.updateStatusLabel(Bundle.ReportCaseUco_querying());
|
||||
|
||||
|
||||
// create the required CASE-UCO entries at the beginning of the output file
|
||||
initializeJsonOutputFile(jsonGenerator);
|
||||
|
||||
|
||||
// create CASE-UCO entry for the Autopsy case
|
||||
String caseTraceId = saveCaseInfo(skCase, jsonGenerator);
|
||||
|
||||
|
||||
// create CASE-UCO data source entry
|
||||
String dataSourceTraceId = saveDataSourceInfo(selectedDataSourceId, caseTraceId, skCase, jsonGenerator);
|
||||
|
||||
|
||||
// Run getAllFilesQuery to get all files, exclude directories
|
||||
final String getAllFilesQuery = "select obj_id, name, size, crtime, atime, mtime, md5, parent_path, mime_type, extension from tsk_files where "
|
||||
+ "data_source_obj_id = " + Long.toString(selectedDataSourceId)
|
||||
+ " AND ((meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_UNDEF.getValue()
|
||||
+ ") OR (meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()
|
||||
+ ") OR (meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT.getValue() + "))"; //NON-NLS
|
||||
|
||||
|
||||
try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getAllFilesQuery)) {
|
||||
ResultSet resultSet = queryResult.getResultSet();
|
||||
|
||||
|
||||
progressPanel.updateStatusLabel(Bundle.ReportCaseUco_processing());
|
||||
|
||||
|
||||
// Loop files and write info to CASE-UCO report
|
||||
while (resultSet.next()) {
|
||||
|
||||
if (progressPanel.getStatus() == ReportStatus.CANCELED) {
|
||||
|
||||
if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Long objectId = resultSet.getLong(1);
|
||||
String fileName = resultSet.getString(2);
|
||||
long size = resultSet.getLong("size");
|
||||
@ -177,29 +143,29 @@ class ReportCaseUco implements GeneralReportModule {
|
||||
String parent_path = resultSet.getString("parent_path");
|
||||
String mime_type = resultSet.getString("mime_type");
|
||||
String extension = resultSet.getString("extension");
|
||||
|
||||
|
||||
saveFileInCaseUcoFormat(objectId, fileName, parent_path, md5Hash, mime_type, size, crtime, atime, mtime, extension, jsonGenerator, dataSourceTraceId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// create the required CASE-UCO entries at the end of the output file
|
||||
finilizeJsonOutputFile(jsonGenerator);
|
||||
|
||||
Case.getCurrentCaseThrows().addReport(reportPath, Bundle.ReportCaseUco_srcModuleName_text(), "");
|
||||
|
||||
progressPanel.complete(ReportStatus.COMPLETE);
|
||||
|
||||
Case.getCurrentCaseThrows().addReport(reportOutputPath, Bundle.ReportCaseUco_srcModuleName_text(), "");
|
||||
|
||||
progressPanel.complete(ReportProgressPanel.ReportStatus.COMPLETE);
|
||||
} catch (TskCoreException ex) {
|
||||
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) {
|
||||
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) {
|
||||
logger.log(Level.WARNING, "Unable to read result set", ex); //NON-NLS
|
||||
progressPanel.complete(ReportStatus.ERROR);
|
||||
progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "No current case open", ex); //NON-NLS
|
||||
progressPanel.complete(ReportStatus.ERROR);
|
||||
progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR);
|
||||
} finally {
|
||||
if (jsonGenerator != null) {
|
||||
try {
|
||||
@ -210,20 +176,31 @@ class ReportCaseUco implements GeneralReportModule {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeJsonOutputFile(JsonGenerator catalog) throws IOException {
|
||||
|
||||
private static void initializeJsonOutputFile(JsonGenerator catalog) throws IOException {
|
||||
catalog.writeStartObject();
|
||||
catalog.writeFieldName("@graph");
|
||||
catalog.writeStartArray();
|
||||
}
|
||||
|
||||
private void finilizeJsonOutputFile(JsonGenerator catalog) throws IOException {
|
||||
|
||||
private static void finilizeJsonOutputFile(JsonGenerator catalog) throws IOException {
|
||||
catalog.writeEndArray();
|
||||
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
|
||||
String uniqueCaseName;
|
||||
String dbFileName;
|
||||
@ -235,7 +212,7 @@ class ReportCaseUco implements GeneralReportModule {
|
||||
uniqueCaseName = skCase.getDatabaseName();
|
||||
dbFileName = "";
|
||||
}
|
||||
|
||||
|
||||
String caseDirPath = skCase.getDbDirPath();
|
||||
String caseTraceId = "case-" + uniqueCaseName;
|
||||
catalog.writeStartObject();
|
||||
@ -243,19 +220,19 @@ class ReportCaseUco implements GeneralReportModule {
|
||||
catalog.writeStringField("@type", "Trace");
|
||||
|
||||
catalog.writeFieldName("propertyBundle");
|
||||
catalog.writeStartArray();
|
||||
catalog.writeStartArray();
|
||||
catalog.writeStartObject();
|
||||
|
||||
|
||||
// replace double slashes with single ones
|
||||
caseDirPath = caseDirPath.replaceAll("\\\\", "/");
|
||||
|
||||
|
||||
catalog.writeStringField("@type", "File");
|
||||
if (dbType == TskData.DbType.SQLITE) {
|
||||
catalog.writeStringField("filePath", caseDirPath + "/" + dbFileName);
|
||||
catalog.writeBooleanField("isDirectory", false);
|
||||
} else {
|
||||
catalog.writeStringField("filePath", caseDirPath);
|
||||
catalog.writeBooleanField("isDirectory", true);
|
||||
catalog.writeBooleanField("isDirectory", true);
|
||||
}
|
||||
catalog.writeEndObject();
|
||||
|
||||
@ -264,12 +241,24 @@ class ReportCaseUco implements GeneralReportModule {
|
||||
|
||||
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;
|
||||
String imageName = "";
|
||||
boolean isImageDataSource = false;
|
||||
String imageName = "";
|
||||
boolean isImageDataSource = false;
|
||||
String getImageDataSourceQuery = "select size from tsk_image_info where obj_id = " + selectedDataSourceId;
|
||||
try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getImageDataSourceQuery)) {
|
||||
ResultSet resultSet = queryResult.getResultSet();
|
||||
@ -281,7 +270,7 @@ class ReportCaseUco implements GeneralReportModule {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isImageDataSource) {
|
||||
// get caseDirPath to image file
|
||||
String getPathToDataSourceQuery = "select name from tsk_image_names where obj_id = " + selectedDataSourceId;
|
||||
@ -303,40 +292,40 @@ class ReportCaseUco implements GeneralReportModule {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
String dataSourceTraceId = "data-source-"+selectedDataSourceId;
|
||||
String dataSourceTraceId = "data-source-" + selectedDataSourceId;
|
||||
catalog.writeStartObject();
|
||||
catalog.writeStringField("@id", dataSourceTraceId);
|
||||
catalog.writeStringField("@type", "Trace");
|
||||
|
||||
|
||||
catalog.writeFieldName("propertyBundle");
|
||||
catalog.writeStartArray();
|
||||
|
||||
|
||||
catalog.writeStartObject();
|
||||
catalog.writeStringField("@type", "File");
|
||||
|
||||
|
||||
// replace double back slashes with single ones
|
||||
imageName = imageName.replaceAll("\\\\", "/");
|
||||
|
||||
|
||||
catalog.writeStringField("filePath", imageName);
|
||||
catalog.writeEndObject();
|
||||
|
||||
|
||||
if (imageSize > 0) {
|
||||
catalog.writeStartObject();
|
||||
catalog.writeStringField("@type", "ContentData");
|
||||
catalog.writeStringField("sizeInBytes", Long.toString(imageSize));
|
||||
catalog.writeEndObject();
|
||||
}
|
||||
|
||||
|
||||
catalog.writeEndArray();
|
||||
catalog.writeEndObject();
|
||||
|
||||
|
||||
// create a "relationship" entry between the case and the data source
|
||||
catalog.writeStartObject();
|
||||
catalog.writeStringField("@id", "relationship-" + caseTraceId);
|
||||
@ -345,33 +334,33 @@ class ReportCaseUco implements GeneralReportModule {
|
||||
catalog.writeStringField("target", caseTraceId);
|
||||
catalog.writeStringField("kindOfRelationship", "contained-within");
|
||||
catalog.writeBooleanField("isDirectional", true);
|
||||
|
||||
|
||||
catalog.writeFieldName("propertyBundle");
|
||||
catalog.writeStartArray();
|
||||
catalog.writeStartArray();
|
||||
catalog.writeStartObject();
|
||||
catalog.writeStringField("@type", "PathRelation");
|
||||
catalog.writeStringField("path", imageName);
|
||||
catalog.writeEndObject();
|
||||
catalog.writeEndArray();
|
||||
|
||||
|
||||
catalog.writeEndObject();
|
||||
|
||||
|
||||
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 fileTraceId = "file-" + objectId;
|
||||
|
||||
|
||||
// create a "trace" entry for the file
|
||||
catalog.writeStartObject();
|
||||
catalog.writeStringField("@id", fileTraceId);
|
||||
catalog.writeStringField("@type", "Trace");
|
||||
|
||||
|
||||
catalog.writeFieldName("propertyBundle");
|
||||
catalog.writeStartArray();
|
||||
|
||||
|
||||
catalog.writeStartObject();
|
||||
catalog.writeStringField("@type", "File");
|
||||
catalog.writeStringField("createdTime", ctime);
|
||||
@ -385,9 +374,9 @@ class ReportCaseUco implements GeneralReportModule {
|
||||
catalog.writeStringField("filePath", parent_path + fileName);
|
||||
}
|
||||
catalog.writeBooleanField("isDirectory", false);
|
||||
catalog.writeStringField("sizeInBytes", Long.toString(size));
|
||||
catalog.writeStringField("sizeInBytes", Long.toString(size));
|
||||
catalog.writeEndObject();
|
||||
|
||||
|
||||
catalog.writeStartObject();
|
||||
catalog.writeStringField("@type", "ContentData");
|
||||
if (mime_type != null) {
|
||||
@ -406,10 +395,10 @@ class ReportCaseUco implements GeneralReportModule {
|
||||
catalog.writeStringField("sizeInBytes", Long.toString(size));
|
||||
|
||||
catalog.writeEndObject();
|
||||
|
||||
|
||||
catalog.writeEndArray();
|
||||
catalog.writeEndObject();
|
||||
|
||||
|
||||
// create a "relationship" entry between the file and the data source
|
||||
catalog.writeStartObject();
|
||||
catalog.writeStringField("@id", "relationship-" + objectId);
|
||||
@ -418,9 +407,9 @@ class ReportCaseUco implements GeneralReportModule {
|
||||
catalog.writeStringField("target", dataSourceTraceId);
|
||||
catalog.writeStringField("kindOfRelationship", "contained-within");
|
||||
catalog.writeBooleanField("isDirectional", true);
|
||||
|
||||
|
||||
catalog.writeFieldName("propertyBundle");
|
||||
catalog.writeStartArray();
|
||||
catalog.writeStartArray();
|
||||
catalog.writeStartObject();
|
||||
catalog.writeStringField("@type", "PathRelation");
|
||||
if (parent_path != null) {
|
||||
@ -428,38 +417,9 @@ class ReportCaseUco implements GeneralReportModule {
|
||||
} else {
|
||||
catalog.writeStringField("path", fileName);
|
||||
}
|
||||
catalog.writeEndObject();
|
||||
catalog.writeEndObject();
|
||||
catalog.writeEndArray();
|
||||
|
||||
|
||||
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">
|
||||
<Properties>
|
||||
<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>
|
||||
</Properties>
|
||||
<AuxValues>
|
@ -2,7 +2,7 @@
|
||||
*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Copyright 2019-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -17,7 +17,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.modules.case_uco;
|
||||
package org.sleuthkit.autopsy.report.caseuco;
|
||||
|
||||
import java.sql.SQLException;
|
||||
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