Did pull request prep and merge bug fixing

This commit is contained in:
Richard Cordovano 2014-03-20 12:49:34 -04:00
parent ff0b814225
commit 8c433c12a1
50 changed files with 938 additions and 1017 deletions

View File

@ -74,7 +74,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
this.dataSourcePanel = dsPanel; this.dataSourcePanel = dsPanel;
ingestConfig = new IngestJobLauncher(AddImageWizardIngestConfigPanel.class.getCanonicalName()); ingestConfig = new IngestJobLauncher(AddImageWizardIngestConfigPanel.class.getCanonicalName());
List<String> messages = ingestConfig.getMissingIngestModuleMessages(); List<String> messages = ingestConfig.getContextSettingsWarnings();
if (messages.isEmpty() == false) { if (messages.isEmpty() == false) {
StringBuilder warning = new StringBuilder(); StringBuilder warning = new StringBuilder();
for (String message : messages) { for (String message : messages) {

View File

@ -57,7 +57,7 @@ class SampleDataSourceIngestModule extends IngestModuleAdapter implements DataSo
private static final Logger logger = Logger.getLogger(SampleDataSourceIngestModule.class); private static final Logger logger = Logger.getLogger(SampleDataSourceIngestModule.class);
@Override @Override
public ResultCode process(Content dataSource, DataSourceIngestModuleStatusHelper statusHelper) { public ProcessResult process(Content dataSource, DataSourceIngestModuleStatusHelper statusHelper) {
Case case1 = Case.getCurrentCase(); Case case1 = Case.getCurrentCase();
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
@ -76,9 +76,9 @@ class SampleDataSourceIngestModule extends IngestModuleAdapter implements DataSo
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.fatal("Error retrieving files from database: " + ex.getLocalizedMessage()); logger.fatal("Error retrieving files from database: " + ex.getLocalizedMessage());
return IngestModule.ResultCode.OK; return IngestModule.ProcessResult.OK;
} }
return IngestModule.ResultCode.OK; return IngestModule.ProcessResult.OK;
} }
} }

View File

@ -89,16 +89,16 @@ class SampleFileIngestModule extends IngestModuleAdapter implements FileIngestMo
} }
@Override @Override
public IngestModule.ResultCode process(AbstractFile abstractFile) { public IngestModule.ProcessResult process(AbstractFile abstractFile) {
// skip non-files // skip non-files
if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
|| (abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) { || (abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) {
return IngestModule.ResultCode.OK; return IngestModule.ProcessResult.OK;
} }
// skip NSRL / known files // skip NSRL / known files
if (abstractFile.getKnown() == TskData.FileKnown.KNOWN) { if (abstractFile.getKnown() == TskData.FileKnown.KNOWN) {
return IngestModule.ResultCode.OK; return IngestModule.ProcessResult.OK;
} }
/* Do a non-sensical calculation of the number of 0x00 bytes /* Do a non-sensical calculation of the number of 0x00 bytes
@ -117,7 +117,7 @@ class SampleFileIngestModule extends IngestModuleAdapter implements FileIngestMo
if (attrId != -1) { if (attrId != -1) {
// Make an attribute using the ID for the private type that we previously created. // Make an attribute using the ID for the private type that we previously created.
BlackboardAttribute attr = new BlackboardAttribute(attrId, "SampleFileIngestModule", count); // RJCTODO: Set up with name as exmaple BlackboardAttribute attr = new BlackboardAttribute(attrId, "SampleFileIngestModule", count); // RJCTODO: Set up with module name as example
/* add it to the general info artifact. In real modules, you would likely have /* add it to the general info artifact. In real modules, you would likely have
* more complex data types and be making more specific artifacts. * more complex data types and be making more specific artifacts.
@ -126,10 +126,10 @@ class SampleFileIngestModule extends IngestModuleAdapter implements FileIngestMo
art.addAttribute(attr); art.addAttribute(attr);
} }
return IngestModule.ResultCode.OK; return IngestModule.ProcessResult.OK;
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
Exceptions.printStackTrace(ex); Exceptions.printStackTrace(ex);
return IngestModule.ResultCode.ERROR; return IngestModule.ProcessResult.ERROR;
} }
} }

View File

@ -24,9 +24,6 @@ IngestJobLauncher.modName.tbirdParser.text=Thunderbird Parser
IngestJobLauncher.modName.mboxParser.text=MBox Parser IngestJobLauncher.modName.mboxParser.text=MBox Parser
IngestJobLauncher.modName.emailParser.text=Email Parser IngestJobLauncher.modName.emailParser.text=Email Parser
IngestJobLauncher.enabledMods.notFound.msg={0} was previously enabled, but could not be found IngestJobLauncher.enabledMods.notFound.msg={0} was previously enabled, but could not be found
DataSourceTaskWorker.displayName.text={0} dataSource id\:{1}
DataSourceTaskWorker.progress.pending={0} (Pending...)
DataSourceTaskWorker.progress.cancelling={0} (Cancelling...)
IngestDialog.title.text=Ingest Modules IngestDialog.title.text=Ingest Modules
IngestDialog.startButton.title=Start IngestDialog.startButton.title=Start
IngestDialog.closeButton.title=Close IngestDialog.closeButton.title=Close
@ -49,10 +46,13 @@ IngestManager.toHtmlStr.totalErrs.text=Total errors\: {0}
IngestManager.toHtmlStr.module.text=Module IngestManager.toHtmlStr.module.text=Module
IngestManager.toHtmlStr.time.text=Time IngestManager.toHtmlStr.time.text=Time
IngestManager.toHtmlStr.errors.text=Errors IngestManager.toHtmlStr.errors.text=Errors
IngestManager.IngestAbstractFileProcessor.displayName=File Ingest IngestManager.FileTaskWorker.displayName=File Ingest
IngestManager.IngestAbstractFileProcessor.process.cancelling={0} (Cancelling...) IngestManager.FileTaskWorker.process.cancelling={0} (Cancelling...)
IngestManager.EnqueueWorker.displayName.text=Queueing Ingest IngestManager.EnqueueWorker.displayName.text=Queueing Ingest
IngestManager.EnqueueWorker.process.cancelling={0} (Cancelling...) IngestManager.EnqueueWorker.process.cancelling={0} (Cancelling...)
IngestManager.DataSourceTaskWorker.displayName.text={0} dataSource id\:{1}
IngestManager.DataSourceTaskWorker.progress.pending={0} (Pending...)
IngestManager.DataSourceTaskWorker.progress.cancelling={0} (Cancelling...)
IngestManager.datatSourceIngest.progress.text=DataSource Ingest {0} IngestManager.datatSourceIngest.progress.text=DataSource Ingest {0}
IngestManager.fileIngest.progress.text=File Ingest {0} IngestManager.fileIngest.progress.text=File Ingest {0}
IngestMessage.toString.type.text=type\: {0} IngestMessage.toString.type.text=type\: {0}

View File

@ -36,5 +36,5 @@ public interface DataSourceIngestModule extends IngestModule {
* detect cancellation. * detect cancellation.
* @return A result code indicating success or failure of the processing. * @return A result code indicating success or failure of the processing.
*/ */
ResultCode process(Content dataSource, DataSourceIngestModuleStatusHelper statusHelper); ProcessResult process(Content dataSource, DataSourceIngestModuleStatusHelper statusHelper);
} }

View File

@ -33,5 +33,5 @@ public interface FileIngestModule extends IngestModule {
* @param file The file * @param file The file
* @return A result code indicating success or failure. * @return A result code indicating success or failure.
*/ */
ResultCode process(AbstractFile file); ProcessResult process(AbstractFile file);
} }

View File

@ -35,9 +35,6 @@ import org.sleuthkit.datamodel.VolumeSystem;
/** /**
* Abstract visitor for getting all the files from content. * Abstract visitor for getting all the files from content.
*/ */
// RJCTODO: Could this be moved to utility package, is there another version of this
// somewhere? An old comment said something about circular dependencies. Note: will use
// this for per ingest job progress bars.
abstract class GetFilesContentVisitor implements ContentVisitor<Collection<AbstractFile>> { abstract class GetFilesContentVisitor implements ContentVisitor<Collection<AbstractFile>> {
private static final Logger logger = Logger.getLogger(GetFilesContentVisitor.class.getName()); private static final Logger logger = Logger.getLogger(GetFilesContentVisitor.class.getName());

View File

@ -36,7 +36,6 @@ import javax.swing.JPanel;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
// RJCTODO: Rename to RunIngestModulesDialog after internationalization.
/** /**
* Dialog box that allows ingest modules to be run on a data source. * Dialog box that allows ingest modules to be run on a data source.
* Used outside of the wizards. * Used outside of the wizards.
@ -50,7 +49,7 @@ public final class IngestDialog extends JDialog {
public IngestDialog(JFrame frame, String title, boolean modal) { public IngestDialog(JFrame frame, String title, boolean modal) {
super(frame, title, modal); super(frame, title, modal);
ingestConfigurator = new IngestJobLauncher(IngestDialog.class.getCanonicalName()); ingestConfigurator = new IngestJobLauncher(IngestDialog.class.getCanonicalName());
List<String> messages = ingestConfigurator.getMissingIngestModuleMessages(); List<String> messages = ingestConfigurator.getContextSettingsWarnings();
if (messages.isEmpty() == false) { if (messages.isEmpty() == false) {
StringBuilder warning = new StringBuilder(); StringBuilder warning = new StringBuilder();
for (String message : messages) { for (String message : messages) {

View File

@ -92,7 +92,7 @@ final class IngestJob {
dataSourceIngestPipelines.put(threadId, pipeline); dataSourceIngestPipelines.put(threadId, pipeline);
} else if (!dataSourceIngestPipelines.containsKey(threadId)) { } else if (!dataSourceIngestPipelines.containsKey(threadId)) {
pipeline = new DataSourceIngestPipeline(this, ingestModuleTemplates); pipeline = new DataSourceIngestPipeline(this, ingestModuleTemplates);
pipeline.startUp(); // RJCTODO: Get errors and log pipeline.startUp();
dataSourceIngestPipelines.put(threadId, pipeline); dataSourceIngestPipelines.put(threadId, pipeline);
} else { } else {
pipeline = dataSourceIngestPipelines.get(threadId); pipeline = dataSourceIngestPipelines.get(threadId);
@ -138,7 +138,6 @@ final class IngestJob {
return (dataSourceIngestPipelines.isEmpty() && fileIngestPipelines.isEmpty()); return (dataSourceIngestPipelines.isEmpty() && fileIngestPipelines.isEmpty());
} }
// RJCTODO: Write story in JIRA for removing code dunplication
/** /**
* A data source ingest pipeline composed of a sequence of data source ingest * A data source ingest pipeline composed of a sequence of data source ingest
* modules constructed from ingest module templates. * modules constructed from ingest module templates.
@ -250,12 +249,12 @@ final class IngestJob {
} }
@Override @Override
public void startUp(IngestJobContext context) throws Exception { public void startUp(IngestJobContext context) throws IngestModuleException {
module.startUp(context); module.startUp(context);
} }
@Override @Override
public IngestModule.ResultCode process(Content dataSource, DataSourceIngestModuleStatusHelper statusHelper) { public IngestModule.ProcessResult process(Content dataSource, DataSourceIngestModuleStatusHelper statusHelper) {
return module.process(dataSource, statusHelper); return module.process(dataSource, statusHelper);
} }
@ -376,12 +375,12 @@ final class IngestJob {
} }
@Override @Override
public void startUp(IngestJobContext context) throws Exception { public void startUp(IngestJobContext context) throws IngestModuleException {
module.startUp(context); module.startUp(context);
} }
@Override @Override
public IngestModule.ResultCode process(AbstractFile file) { public IngestModule.ProcessResult process(AbstractFile file) {
return module.process(file); return module.process(file);
} }

View File

@ -58,7 +58,7 @@ class IngestJobConfigurationPanel extends javax.swing.JPanel {
for (IngestModuleModel module : modules) { for (IngestModuleModel module : modules) {
IngestModuleTemplate moduleTemplate = module.getIngestModuleTemplate(); IngestModuleTemplate moduleTemplate = module.getIngestModuleTemplate();
if (module.hasIngestOptionsPanel()) { if (module.hasIngestOptionsPanel()) {
IngestModuleSettings options = module.getIngestOptionsPanel().getIngestJobOptions(); IngestModuleSettings options = module.getIngestOptionsPanel().getSettings();
moduleTemplate.setIngestOptions(options); moduleTemplate.setIngestOptions(options);
} }
moduleTemplates.add(moduleTemplate); moduleTemplates.add(moduleTemplate);
@ -295,7 +295,7 @@ class IngestJobConfigurationPanel extends javax.swing.JPanel {
private final IngestModuleTemplate moduleTemplate; private final IngestModuleTemplate moduleTemplate;
private IngestModuleGlobalSetttingsPanel resourcesConfigPanel = null; private IngestModuleGlobalSetttingsPanel resourcesConfigPanel = null;
private IngestModuleJobSettingsPanel ingestJobOptionsPanel = null; private IngestModuleSettingsPanel ingestJobOptionsPanel = null;
IngestModuleModel(IngestModuleTemplate moduleTemplate) { IngestModuleModel(IngestModuleTemplate moduleTemplate) {
this.moduleTemplate = moduleTemplate; this.moduleTemplate = moduleTemplate;
@ -334,7 +334,7 @@ class IngestJobConfigurationPanel extends javax.swing.JPanel {
return moduleTemplate.getIngestModuleFactory().providesModuleSettingsPanel(); return moduleTemplate.getIngestModuleFactory().providesModuleSettingsPanel();
} }
IngestModuleJobSettingsPanel getIngestOptionsPanel() { IngestModuleSettingsPanel getIngestOptionsPanel() {
return ingestJobOptionsPanel; return ingestJobOptionsPanel;
} }
@ -347,7 +347,7 @@ class IngestJobConfigurationPanel extends javax.swing.JPanel {
} }
void saveResourcesConfig() { void saveResourcesConfig() {
resourcesConfigPanel.store(); resourcesConfigPanel.saveSettings();
} }
} }

View File

@ -18,109 +18,28 @@
*/ */
package org.sleuthkit.autopsy.ingest; package org.sleuthkit.autopsy.ingest;
import java.io.File;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.SleuthkitCase;
/** /**
* Acts as a facade for the parts of the ingest framework that make up the * Provides an instance of an ingest module with services specific to the ingest
* processing context of an ingest module. * job and the ingest pipeline of which the module is a part.
*/ */
public final class IngestJobContext { public final class IngestJobContext {
private final IngestJob ingestJob; private final IngestJob ingestJob;
private final IngestModuleFactory moduleFactory;
private final IngestManager ingestManager;
private final IngestScheduler scheduler;
private final Case autopsyCase;
private final SleuthkitCase sleuthkitCase;
IngestJobContext(IngestJob ingestJob, IngestModuleFactory moduleFactory) { IngestJobContext(IngestJob ingestJob, IngestModuleFactory moduleFactory) {
this.ingestJob = ingestJob; this.ingestJob = ingestJob;
this.moduleFactory = moduleFactory;
ingestManager = IngestManager.getDefault();
scheduler = IngestScheduler.getInstance();
autopsyCase = Case.getCurrentCase();
sleuthkitCase = this.autopsyCase.getSleuthkitCase();
} }
public boolean isIngestJobCancelled() { public boolean isIngestJobCancelled() {
return this.ingestJob.isCancelled(); return this.ingestJob.isCancelled();
} }
public Case getCase() {
return autopsyCase;
}
public SleuthkitCase getSleuthkitCase() { public void addFilesToPipeline(List<AbstractFile> files) {
return sleuthkitCase;
}
public String getOutputDirectoryAbsolutePath() {
return autopsyCase.getCaseDirectory() + File.separator + Case.getModulesOutputDirRelPath() + File.separator + moduleFactory.getModuleDisplayName();
}
public String getOutputDirectoryRelativePath() {
return "ModuleOutput" + File.separator + moduleFactory.getModuleDisplayName();
}
public void submitFilesForIngest(List<AbstractFile> files) {
for (AbstractFile file : files) { for (AbstractFile file : files) {
ingestManager.scheduleFileTask(ingestJob.getId(), file); IngestManager.getDefault().scheduleFile(ingestJob.getId(), file); // RJCTODO: Should this API be just AbstractFile?
} }
} }
public void postIngestMessage(long ID, IngestMessage.MessageType messageType, String subject, String detailsHtml) {
IngestMessage message = IngestMessage.createMessage(ID, messageType, moduleFactory.getModuleDisplayName(), subject, detailsHtml);
ingestManager.postIngestMessage(message);
}
public void postIngestMessage(long ID, IngestMessage.MessageType messageType, String subject) {
IngestMessage message = IngestMessage.createMessage(ID, messageType, moduleFactory.getModuleDisplayName(), subject);
ingestManager.postIngestMessage(message);
}
public void postErrorIngestMessage(long ID, String subject, String detailsHtml) {
IngestMessage message = IngestMessage.createErrorMessage(ID, moduleFactory.getModuleDisplayName(), subject, detailsHtml);
ingestManager.postIngestMessage(message);
}
public void postWarningIngestMessage(long ID, String subject, String detailsHtml) {
IngestMessage message = IngestMessage.createWarningMessage(ID, moduleFactory.getModuleDisplayName(), subject, detailsHtml);
ingestManager.postIngestMessage(message);
}
public void postDataMessage(long ID, String subject, String detailsHtml, String uniqueKey, BlackboardArtifact data) {
IngestMessage message = IngestMessage.createDataMessage(ID, moduleFactory.getModuleDisplayName(), subject, detailsHtml, uniqueKey, data);
ingestManager.postIngestMessage(message);
}
public void fireDataEvent(BlackboardArtifact.ARTIFACT_TYPE artifactType) {
ModuleDataEvent event = new ModuleDataEvent(moduleFactory.getModuleDisplayName(), artifactType);
IngestManager.fireModuleDataEvent(event);
}
public void fireDataEvent(BlackboardArtifact.ARTIFACT_TYPE artifactType, Collection<BlackboardArtifact> artifactIDs) {
ModuleDataEvent event = new ModuleDataEvent(moduleFactory.getModuleDisplayName(), artifactType, artifactIDs);
IngestManager.fireModuleDataEvent(event);
}
// RJCTODO: Make story to convert existing core modules to use logging methods, address sloppy use of level...
public void logInfo(Class moduleClass, String message, Throwable ex) {
Logger.getLogger(moduleClass.getName()).log(Level.INFO, message, ex);
}
public void logWarning(Class moduleClass, String message, Throwable ex) {
Logger.getLogger(moduleClass.getName()).log(Level.WARNING, message, ex);
}
public void logError(Class moduleClass, String message, Throwable ex) {
Logger.getLogger(moduleClass.getName()).log(Level.SEVERE, message, ex);
}
} }

View File

@ -25,16 +25,27 @@ import javax.swing.JPanel;
import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
/**
* Provides a mechanism for creating and persisting a context-sensitive ingest
* pipeline configuration and launching ingest jobs to process one or more data
* sources.
*/
public final class IngestJobLauncher { public final class IngestJobLauncher {
private static final String ENABLED_INGEST_MODULES_KEY = "Enabled_Ingest_Modules"; private static final String ENABLED_INGEST_MODULES_KEY = "Enabled_Ingest_Modules";
private static final String DISABLED_INGEST_MODULES_KEY = "Disabled_Ingest_Modules"; private static final String DISABLED_INGEST_MODULES_KEY = "Disabled_Ingest_Modules";
private static final String PARSE_UNALLOC_SPACE_KEY = "Process_Unallocated_Space"; private static final String PARSE_UNALLOC_SPACE_KEY = "Process_Unallocated_Space";
private final String launcherContext; private final String launcherContext;
private final List<String> missingIngestModuleErrorMessages = new ArrayList<>(); private final List<String> contextSettingsWarnings = new ArrayList<>();
private final List<Content> dataSourcesToIngest = new ArrayList<>(); private final List<Content> dataSourcesToIngest = new ArrayList<>();
private IngestJobConfigurationPanel ingestConfigPanel; private IngestJobConfigurationPanel ingestConfigPanel;
/**
* Constructs an ingest job launcher that loads and updates the ingest job
* and ingest pipeline for a particular context.
*
* @param launcherContext The context identifier.
*/
public IngestJobLauncher(String launcherContext) { public IngestJobLauncher(String launcherContext) {
this.launcherContext = launcherContext; this.launcherContext = launcherContext;
@ -48,12 +59,30 @@ public final class IngestJobLauncher {
} }
// Get the enabled and disabled ingest modules settings for the current // Get the enabled and disabled ingest modules settings for the current
// context. The default settings make all ingest modules enabled. // context. Observe that the default settings make all loaded ingest
// modules enabled.
HashSet<String> enabledModuleNames = getModulesNamesFromSetting(ENABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(loadedModuleNames)); HashSet<String> enabledModuleNames = getModulesNamesFromSetting(ENABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(loadedModuleNames));
HashSet<String> disabledModuleNames = getModulesNamesFromSetting(DISABLED_INGEST_MODULES_KEY, ""); HashSet<String> disabledModuleNames = getModulesNamesFromSetting(DISABLED_INGEST_MODULES_KEY, "");
// Create ingest module templates for the current context. // Check for missing modules.
HashSet<String> knownModuleNames = new HashSet<>(); List<String> missingModuleNames = new ArrayList<>();
for (String moduleName : enabledModuleNames) {
if (!loadedModuleNames.contains(moduleName)) {
missingModuleNames.add(moduleName);
}
}
for (String moduleName : disabledModuleNames) {
if (!loadedModuleNames.contains(moduleName)) {
missingModuleNames.add(moduleName);
}
}
for (String moduleName : missingModuleNames) {
enabledModuleNames.remove(moduleName);
disabledModuleNames.remove(moduleName);
contextSettingsWarnings.add(String.format("Previously loaded %s module could not be found", moduleName));
}
// Create ingest module templates.
List<IngestModuleTemplate> moduleTemplates = new ArrayList<>(); List<IngestModuleTemplate> moduleTemplates = new ArrayList<>();
for (IngestModuleFactory moduleFactory : moduleFactories) { for (IngestModuleFactory moduleFactory : moduleFactories) {
// RJCTODO: Make sure there is a story in JIRA for this. // RJCTODO: Make sure there is a story in JIRA for this.
@ -75,18 +104,10 @@ public final class IngestJobLauncher {
enabledModuleNames.add(moduleName); enabledModuleNames.add(moduleName);
} }
moduleTemplates.add(moduleTemplate); moduleTemplates.add(moduleTemplate);
knownModuleNames.add(moduleName);
} }
// Check for missing modules and update the enabled/disabled ingest // Update the enabled/disabled ingest module settings to reflect any
// module settings for any missing modules. // missing modules or newly discovered modules.
for (String moduleName : enabledModuleNames) {
if (!knownModuleNames.contains(moduleName)) {
missingIngestModuleErrorMessages.add(moduleName + " was previously enabled, but could not be found");
enabledModuleNames.remove(moduleName);
disabledModuleNames.add(moduleName);
}
}
ModuleSettings.setConfigSetting(launcherContext, ENABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(enabledModuleNames)); ModuleSettings.setConfigSetting(launcherContext, ENABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(enabledModuleNames));
ModuleSettings.setConfigSetting(launcherContext, DISABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(disabledModuleNames)); ModuleSettings.setConfigSetting(launcherContext, DISABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(disabledModuleNames));
@ -97,12 +118,12 @@ public final class IngestJobLauncher {
} }
boolean processUnallocatedSpace = Boolean.parseBoolean(ModuleSettings.getConfigSetting(launcherContext, PARSE_UNALLOC_SPACE_KEY)); boolean processUnallocatedSpace = Boolean.parseBoolean(ModuleSettings.getConfigSetting(launcherContext, PARSE_UNALLOC_SPACE_KEY));
// Make the configuration panel for the current context (view). // Make the configuration panel for the context.
ingestConfigPanel = new IngestJobConfigurationPanel(moduleTemplates, processUnallocatedSpace); ingestConfigPanel = new IngestJobConfigurationPanel(moduleTemplates, processUnallocatedSpace);
} }
public List<String> getMissingIngestModuleMessages() { public List<String> getContextSettingsWarnings() {
return missingIngestModuleErrorMessages; return contextSettingsWarnings;
} }
public JPanel getIngestJobConfigPanel() { public JPanel getIngestJobConfigPanel() {
@ -134,7 +155,7 @@ public final class IngestJobLauncher {
// options for each ingest module for the current launch context. // options for each ingest module for the current launch context.
} }
public void setDataSourcesToIngest(List<Content> dataSourcesToIngest) { public void setDataSourcesToIngest(List<Content> dataSourcesToIngest) { // RJCTODO: This should really be handled by passing the data sources to startIngestJobs()
this.dataSourcesToIngest.clear(); this.dataSourcesToIngest.clear();
this.dataSourcesToIngest.addAll(dataSourcesToIngest); this.dataSourcesToIngest.addAll(dataSourcesToIngest);
} }
@ -168,7 +189,7 @@ public final class IngestJobLauncher {
csvList.append(list.get(list.size() - 1)); csvList.append(list.get(list.size() - 1));
return csvList.toString(); return csvList.toString();
} }
private HashSet<String> getModulesNamesFromSetting(String key, String defaultSetting) { private HashSet<String> getModulesNamesFromSetting(String key, String defaultSetting) {
// Get the ingest modules setting from the user's config file. // Get the ingest modules setting from the user's config file.
// If there is no such setting yet, create the default setting. // If there is no such setting yet, create the default setting.
@ -180,7 +201,7 @@ public final class IngestJobLauncher {
if (!modulesSetting.isEmpty()) { if (!modulesSetting.isEmpty()) {
String[] settingNames = modulesSetting.split(", "); String[] settingNames = modulesSetting.split(", ");
for (String name : settingNames) { for (String name : settingNames) {
// Map some old core module names to the current core module names. // Map some old core module names to the current core module names. // RJCTODO: Do we have the right names?
switch (name) { switch (name) {
case "Thunderbird Parser": case "Thunderbird Parser":
case "MBox Parser": case "MBox Parser":

View File

@ -60,7 +60,7 @@ public class IngestManager {
private long nextDataSourceTaskId = 0; private long nextDataSourceTaskId = 0;
private long nextThreadId = 0; private long nextThreadId = 0;
public final static String MODULE_PROPERTIES = NbBundle.getMessage(IngestManager.class, public final static String MODULE_PROPERTIES = NbBundle.getMessage(IngestManager.class,
"IngestManager.moduleProperties.text"); "IngestManager.moduleProperties.text");
private volatile IngestUI ingestMessageBox; private volatile IngestUI ingestMessageBox;
// RJCTODO: Redo eventing for 3.1 // RJCTODO: Redo eventing for 3.1
@ -137,7 +137,7 @@ public class IngestManager {
this.ingestMessageBox = IngestMessageTopComponent.findInstance(); this.ingestMessageBox = IngestMessageTopComponent.findInstance();
} }
} }
synchronized private long getNextDataSourceTaskId() { synchronized private long getNextDataSourceTaskId() {
return ++this.nextDataSourceTaskId; return ++this.nextDataSourceTaskId;
} }
@ -145,7 +145,7 @@ public class IngestManager {
synchronized private long getNextThreadId() { synchronized private long getNextThreadId() {
return ++this.nextThreadId; return ++this.nextThreadId;
} }
/** /**
* Add property change listener to listen to ingest events as defined in * Add property change listener to listen to ingest events as defined in
* IngestModuleEvent. * IngestModuleEvent.
@ -166,8 +166,8 @@ public class IngestManager {
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "Ingest manager listener threw exception", e); logger.log(Level.SEVERE, "Ingest manager listener threw exception", e);
MessageNotifyUtil.Notify.show(NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr"), MessageNotifyUtil.Notify.show(NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr"),
NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr.errListenToUpdates.msg"), NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr.errListenToUpdates.msg"),
MessageNotifyUtil.MessageType.ERROR); MessageNotifyUtil.MessageType.ERROR);
} }
} }
@ -182,8 +182,8 @@ public class IngestManager {
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "Ingest manager listener threw exception", e); logger.log(Level.SEVERE, "Ingest manager listener threw exception", e);
MessageNotifyUtil.Notify.show(NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr"), MessageNotifyUtil.Notify.show(NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr"),
NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr.errListenToUpdates.msg"), NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr.errListenToUpdates.msg"),
MessageNotifyUtil.MessageType.ERROR); MessageNotifyUtil.MessageType.ERROR);
} }
} }
@ -199,8 +199,8 @@ public class IngestManager {
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "Ingest manager listener threw exception", e); logger.log(Level.SEVERE, "Ingest manager listener threw exception", e);
MessageNotifyUtil.Notify.show(NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr"), MessageNotifyUtil.Notify.show(NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr"),
NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr.errListenToUpdates.msg"), NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr.errListenToUpdates.msg"),
MessageNotifyUtil.MessageType.ERROR); MessageNotifyUtil.MessageType.ERROR);
} }
} }
@ -216,8 +216,8 @@ public class IngestManager {
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "Ingest manager listener threw exception", e); logger.log(Level.SEVERE, "Ingest manager listener threw exception", e);
MessageNotifyUtil.Notify.show(NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr"), MessageNotifyUtil.Notify.show(NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr"),
NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr.errListenToUpdates.msg"), NbBundle.getMessage(IngestManager.class, "IngestManager.moduleErr.errListenToUpdates.msg"),
MessageNotifyUtil.MessageType.ERROR); MessageNotifyUtil.MessageType.ERROR);
} }
} }
@ -273,7 +273,7 @@ public class IngestManager {
* @param pipelineContext ingest context used to ingest parent of the file * @param pipelineContext ingest context used to ingest parent of the file
* to be scheduled * to be scheduled
*/ */
void scheduleFileTask(long ingestJobId, AbstractFile file) { // RJCTODO: Consider renaming method void scheduleFile(long ingestJobId, AbstractFile file) {
IngestJob job = this.ingestJobs.get(ingestJobId); IngestJob job = this.ingestJobs.get(ingestJobId);
if (job == null) { if (job == null) {
// RJCTODO: Handle severe error // RJCTODO: Handle severe error
@ -317,7 +317,7 @@ public class IngestManager {
for (IngestJob job : ingestJobs.values()) { for (IngestJob job : ingestJobs.values()) {
job.releaseIngestPipelinesForThread(threadId); job.releaseIngestPipelinesForThread(threadId);
if (job.areIngestPipelinesShutDown()) { if (job.areIngestPipelinesShutDown()) {
ingestJobs.remove(job.getId()); ingestJobs.remove(job.getId());
} }
} }
} }
@ -351,7 +351,7 @@ public class IngestManager {
// Jettision the remaining tasks. This will dispose of any tasks that // Jettision the remaining tasks. This will dispose of any tasks that
// the scheduling worker queued up before it was cancelled. // the scheduling worker queued up before it was cancelled.
scheduler.getFileScheduler().empty(); scheduler.getFileScheduler().empty();
scheduler.getDataSourceScheduler().empty(); scheduler.getDataSourceScheduler().empty();
} }
/** /**
@ -431,7 +431,7 @@ public class IngestManager {
logger.log(Level.INFO, "Task scheduling thread cancelled"); logger.log(Level.INFO, "Task scheduling thread cancelled");
return null; return null;
} }
final String inputName = dataSource.getName(); final String inputName = dataSource.getName();
IngestJob ingestJob = new IngestJob(IngestManager.this.getNextDataSourceTaskId(), dataSource, moduleTemplates, processUnallocatedSpace); IngestJob ingestJob = new IngestJob(IngestManager.this.getNextDataSourceTaskId(), dataSource, moduleTemplates, processUnallocatedSpace);
@ -497,20 +497,19 @@ public class IngestManager {
@Override @Override
protected Void doInBackground() throws Exception { protected Void doInBackground() throws Exception {
logger.log(Level.INFO, String.format("Data source ingest thread {0} started", this.id)); logger.log(Level.INFO, "Data source ingest thread (id={0}) started", this.id);
// Set up a progress bar that can be used to cancel all of the // Set up a progress bar that can be used to cancel all of the
// ingest jobs currently being performed. // ingest jobs currently being performed.
final String displayName = NbBundle final String displayName = NbBundle.getMessage(this.getClass(), "IngestManager.DataSourceTaskWorker.displayName");
.getMessage(this.getClass(), "IngestManager.IngestAbstractFileProcessor.displayName");
progress = ProgressHandleFactory.createHandle(displayName, new Cancellable() { progress = ProgressHandleFactory.createHandle(displayName, new Cancellable() {
@Override @Override
public boolean cancel() { public boolean cancel() {
logger.log(Level.INFO, "Data source ingest thread {0} cancelled", DataSourceTaskWorker.this.id); logger.log(Level.INFO, "Data source ingest thread {0} cancelled", DataSourceTaskWorker.this.id);
if (progress != null) { if (progress != null) {
progress.setDisplayName(NbBundle.getMessage(this.getClass(), progress.setDisplayName(NbBundle.getMessage(this.getClass(),
"IngestManager.IngestAbstractFileProcessor.process.cancelling", "IngestManager.DataSourceTaskWorker.process.cancelling",
displayName)); displayName));
} }
IngestManager.getDefault().stopAll(); IngestManager.getDefault().stopAll();
return true; return true;
@ -522,7 +521,7 @@ public class IngestManager {
IngestScheduler.DataSourceScheduler scheduler = IngestScheduler.getInstance().getDataSourceScheduler(); IngestScheduler.DataSourceScheduler scheduler = IngestScheduler.getInstance().getDataSourceScheduler();
while (scheduler.hasNext()) { while (scheduler.hasNext()) {
if (isCancelled()) { if (isCancelled()) {
logger.log(Level.INFO, "Data source ingest thread {0} cancelled", this.id); logger.log(Level.INFO, "Data source ingest thread (id={0}) cancelled", this.id);
return null; return null;
} }
@ -531,7 +530,7 @@ public class IngestManager {
pipeline.process(this, this.progress); pipeline.process(this, this.progress);
} }
logger.log(Level.INFO, "Data source ingest thread {0} completed", this.id); logger.log(Level.INFO, "Data source ingest thread (id={0}) completed", this.id);
IngestManager.getDefault().reportThreadDone(this.id); IngestManager.getDefault().reportThreadDone(this.id);
return null; return null;
} }
@ -541,10 +540,10 @@ public class IngestManager {
try { try {
super.get(); super.get();
} catch (CancellationException | InterruptedException e) { } catch (CancellationException | InterruptedException e) {
logger.log(Level.INFO, "Data source ingest thread {0} cancelled", this.id); logger.log(Level.INFO, "Data source ingest thread (id={0}) cancelled", this.id);
IngestManager.getDefault().reportThreadDone(this.id); IngestManager.getDefault().reportThreadDone(this.id);
} catch (Exception ex) { } catch (Exception ex) {
String message = String.format("Data source ingest thread {0} experienced a fatal error", this.id); String message = String.format("Data source ingest thread (id=%d) experienced a fatal error", this.id);
logger.log(Level.SEVERE, message, ex); logger.log(Level.SEVERE, message, ex);
IngestManager.getDefault().reportThreadDone(this.id); IngestManager.getDefault().reportThreadDone(this.id);
} finally { } finally {
@ -568,7 +567,7 @@ public class IngestManager {
@Override @Override
protected Object doInBackground() throws Exception { protected Object doInBackground() throws Exception {
logger.log(Level.INFO, String.format("File ingest thread {0} started", this.id)); logger.log(Level.INFO, "File ingest thread (id={0}) started", this.id);
// Set up a progress bar that can be used to cancel all of the // Set up a progress bar that can be used to cancel all of the
// ingest jobs currently being performed. // ingest jobs currently being performed.
@ -577,11 +576,11 @@ public class IngestManager {
progress = ProgressHandleFactory.createHandle(displayName, new Cancellable() { progress = ProgressHandleFactory.createHandle(displayName, new Cancellable() {
@Override @Override
public boolean cancel() { public boolean cancel() {
logger.log(Level.INFO, "File ingest thread {0} cancelled", FileTaskWorker.this.id); logger.log(Level.INFO, "File ingest thread (id={0}) cancelled", FileTaskWorker.this.id);
if (progress != null) { if (progress != null) {
progress.setDisplayName( progress.setDisplayName(
NbBundle.getMessage(this.getClass(), "IngestManager.EnqueueWorker.process.cancelling", NbBundle.getMessage(this.getClass(), "IngestManager.FileTaskWorker.process.cancelling",
displayName)); displayName));
} }
IngestManager.getDefault().stopAll(); IngestManager.getDefault().stopAll();
return true; return true;
@ -597,7 +596,7 @@ public class IngestManager {
while (fileScheduler.hasNext()) { while (fileScheduler.hasNext()) {
if (isCancelled()) { if (isCancelled()) {
IngestManager.getDefault().reportThreadDone(this.id); IngestManager.getDefault().reportThreadDone(this.id);
logger.log(Level.INFO, "File ingest thread {0} cancelled", this.id); logger.log(Level.INFO, "File ingest thread (id={0}) cancelled", this.id);
return null; return null;
} }
@ -619,7 +618,7 @@ public class IngestManager {
} }
} }
logger.log(Level.INFO, "File ingest thread {0} completed", this.id); logger.log(Level.INFO, "File ingest thread (id={0}) completed", this.id);
IngestManager.getDefault().reportThreadDone(this.id); IngestManager.getDefault().reportThreadDone(this.id);
return null; return null;
} }
@ -630,7 +629,7 @@ public class IngestManager {
try { try {
super.get(); super.get();
} catch (CancellationException | InterruptedException e) { } catch (CancellationException | InterruptedException e) {
logger.log(Level.INFO, "File ingest thread {0} cancelled", this.id); logger.log(Level.INFO, "File ingest thread (id={0}) cancelled", this.id);
IngestManager.getDefault().reportThreadDone(this.id); IngestManager.getDefault().reportThreadDone(this.id);
} catch (Exception ex) { } catch (Exception ex) {
String message = String.format("File ingest thread {0} experienced a fatal error", this.id); String message = String.format("File ingest thread {0} experienced a fatal error", this.id);

View File

@ -23,13 +23,24 @@ package org.sleuthkit.autopsy.ingest;
*/ */
public interface IngestModule { public interface IngestModule {
public enum ResultCode { public enum ProcessResult {
OK, OK,
ERROR, ERROR
}; };
public class IngestModuleException extends Exception {
public IngestModuleException(String message) {
super(message);
}
}
// RJCTODO: Write header comment, make sure to mention "one module instance per thread" // RJCTODO: Write header comment, make sure to mention "one module instance per thread"
void startUp(IngestJobContext context) throws Exception; /**
* Invoked by the ingest frame
* @param context
* @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException
*/
void startUp(IngestJobContext context) throws IngestModuleException;
// RJCTODO: Write header comment, make sure to mention "one module instance per thread" // RJCTODO: Write header comment, make sure to mention "one module instance per thread"
void shutDown(boolean ingestJobWasCancelled); void shutDown(boolean ingestJobWasCancelled);

View File

@ -25,7 +25,7 @@ package org.sleuthkit.autopsy.ingest;
public abstract class IngestModuleAdapter implements IngestModule { public abstract class IngestModuleAdapter implements IngestModule {
@Override @Override
public void startUp(IngestJobContext context) throws Exception { public void startUp(IngestJobContext context) throws IngestModuleException {
} }
@Override @Override

View File

@ -152,7 +152,7 @@ public interface IngestModuleFactory {
* @param ingestOptions Per ingest job options to initialize the panel. * @param ingestOptions Per ingest job options to initialize the panel.
* @return A user interface panel. * @return A user interface panel.
*/ */
IngestModuleJobSettingsPanel getModuleSettingsPanel(IngestModuleSettings ingestOptions); IngestModuleSettingsPanel getModuleSettingsPanel(IngestModuleSettings ingestOptions);
/** /**
* Queries the factory to determine if it is capable of creating file ingest * Queries the factory to determine if it is capable of creating file ingest

View File

@ -54,7 +54,7 @@ public abstract class IngestModuleFactoryAdapter implements IngestModuleFactory
} }
@Override @Override
public IngestModuleJobSettingsPanel getModuleSettingsPanel(IngestModuleSettings ingestOptions) { public IngestModuleSettingsPanel getModuleSettingsPanel(IngestModuleSettings ingestOptions) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -19,16 +19,11 @@
package org.sleuthkit.autopsy.ingest; package org.sleuthkit.autopsy.ingest;
import javax.swing.JPanel; import javax.swing.JPanel;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
/** /**
* Base class for ingest module resources configuration panels. * Base class for ingest module resources configuration panels.
*/ */
public abstract class IngestModuleGlobalSetttingsPanel extends JPanel implements OptionsPanel { public abstract class IngestModuleGlobalSetttingsPanel extends JPanel {
@Override public abstract void saveSettings();
public abstract void load();
@Override
public abstract void store();
} }

View File

@ -21,14 +21,14 @@ package org.sleuthkit.autopsy.ingest;
import javax.swing.JPanel; import javax.swing.JPanel;
/** /**
* Abstract base class for ingest module per ingest job options panels. * Abstract base class for ingest module job settings panels.
*/ */
public abstract class IngestModuleJobSettingsPanel extends JPanel { public abstract class IngestModuleSettingsPanel extends JPanel {
/** /**
* Gets the ingest options for an ingest module. * Gets the ingest job settings for an ingest module.
* *
* @return The ingest options. * @return The ingest settings.
*/ */
public abstract IngestModuleSettings getIngestJobOptions(); public abstract IngestModuleSettings getSettings();
} }

View File

@ -134,7 +134,7 @@ public final class IngestServices {
*/ */
public void scheduleFile(long dataSourceTaskId, AbstractFile file) { public void scheduleFile(long dataSourceTaskId, AbstractFile file) {
logger.log(Level.INFO, "Scheduling file: {0}", file.getName()); logger.log(Level.INFO, "Scheduling file: {0}", file.getName());
manager.scheduleFileTask(dataSourceTaskId, file); manager.scheduleFile(dataSourceTaskId, file);
} }
/** /**

View File

@ -16,7 +16,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.sleuthkit.autopsy.exifparser; package org.sleuthkit.autopsy.exifparser;
import com.drew.imaging.ImageMetadataReader; import com.drew.imaging.ImageMetadataReader;
@ -56,33 +55,24 @@ import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
*/ */
public final class ExifParserFileIngestModule extends IngestModuleAdapter implements FileIngestModule { public final class ExifParserFileIngestModule extends IngestModuleAdapter implements FileIngestModule {
private IngestServices services;
private static final Logger logger = Logger.getLogger(ExifParserFileIngestModule.class.getName()); private static final Logger logger = Logger.getLogger(ExifParserFileIngestModule.class.getName());
private final IngestServices services = IngestServices.getDefault();
private int filesProcessed = 0; private int filesProcessed = 0;
private boolean filesToFire = false; private boolean filesToFire = false;
ExifParserFileIngestModule() { ExifParserFileIngestModule() {
} }
@Override
public void startUp(org.sleuthkit.autopsy.ingest.IngestJobContext context) throws Exception {
services = IngestServices.getDefault();
logger.log(Level.INFO, "init() {0}", this.toString());
filesProcessed = 0;
filesToFire = false;
}
@Override
public ResultCode process(AbstractFile content) {
@Override
public ProcessResult process(AbstractFile content) {
//skip unalloc //skip unalloc
if (content.getType().equals(TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) { if (content.getType().equals(TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) {
return ResultCode.OK; return ProcessResult.OK;
} }
// skip known // skip known
if (content.getKnown().equals(TskData.FileKnown.KNOWN)) { if (content.getKnown().equals(TskData.FileKnown.KNOWN)) {
return ResultCode.OK; return ProcessResult.OK;
} }
// update the tree every 1000 files if we have EXIF data that is not being being displayed // update the tree every 1000 files if we have EXIF data that is not being being displayed
@ -91,16 +81,16 @@ public final class ExifParserFileIngestModule extends IngestModuleAdapter implem
services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)); services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF));
filesToFire = false; filesToFire = false;
} }
//skip unsupported //skip unsupported
if (!parsableFormat(content)) { if (!parsableFormat(content)) {
return ResultCode.OK; return ProcessResult.OK;
} }
return processFile(content); return processFile(content);
} }
ResultCode processFile(AbstractFile f) { ProcessResult processFile(AbstractFile f) {
InputStream in = null; InputStream in = null;
BufferedInputStream bin = null; BufferedInputStream bin = null;
@ -130,7 +120,7 @@ public final class ExifParserFileIngestModule extends IngestModuleAdapter implem
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), latitude)); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), latitude));
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), longitude)); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), longitude));
} }
Rational altitude = gpsDir.getRational(GpsDirectory.TAG_GPS_ALTITUDE); Rational altitude = gpsDir.getRational(GpsDirectory.TAG_GPS_ALTITUDE);
if (altitude != null) { if (altitude != null) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), altitude.doubleValue())); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), altitude.doubleValue()));
@ -144,7 +134,7 @@ public final class ExifParserFileIngestModule extends IngestModuleAdapter implem
if (model != null && !model.isEmpty()) { if (model != null && !model.isEmpty()) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL.getTypeID(), ExifParserModuleFactory.getModuleName(), model)); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL.getTypeID(), ExifParserModuleFactory.getModuleName(), model));
} }
String make = devDir.getString(ExifIFD0Directory.TAG_MAKE); String make = devDir.getString(ExifIFD0Directory.TAG_MAKE);
if (make != null && !make.isEmpty()) { if (make != null && !make.isEmpty()) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE.getTypeID(), ExifParserModuleFactory.getModuleName(), make)); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE.getTypeID(), ExifParserModuleFactory.getModuleName(), make));
@ -157,22 +147,18 @@ public final class ExifParserFileIngestModule extends IngestModuleAdapter implem
bba.addAttributes(attributes); bba.addAttributes(attributes);
filesToFire = true; filesToFire = true;
} }
return ResultCode.OK; return ProcessResult.OK;
} } catch (TskCoreException ex) {
catch (TskCoreException ex) {
logger.log(Level.WARNING, "Failed to create blackboard artifact for exif metadata ({0}).", ex.getLocalizedMessage()); logger.log(Level.WARNING, "Failed to create blackboard artifact for exif metadata ({0}).", ex.getLocalizedMessage());
return ResultCode.ERROR; return ProcessResult.ERROR;
} } catch (ImageProcessingException ex) {
catch (ImageProcessingException ex) {
logger.log(Level.WARNING, "Failed to process the image file: {0}/{1}({2})", new Object[]{f.getParentPath(), f.getName(), ex.getLocalizedMessage()}); logger.log(Level.WARNING, "Failed to process the image file: {0}/{1}({2})", new Object[]{f.getParentPath(), f.getName(), ex.getLocalizedMessage()});
return ResultCode.ERROR; return ProcessResult.ERROR;
} } catch (IOException ex) {
catch (IOException ex) {
logger.log(Level.WARNING, "IOException when parsing image file: " + f.getParentPath() + "/" + f.getName(), ex); logger.log(Level.WARNING, "IOException when parsing image file: " + f.getParentPath() + "/" + f.getName(), ex);
return ResultCode.ERROR; return ProcessResult.ERROR;
} } finally {
finally {
try { try {
if (in != null) { if (in != null) {
in.close(); in.close();
@ -182,7 +168,7 @@ public final class ExifParserFileIngestModule extends IngestModuleAdapter implem
} }
} catch (IOException ex) { } catch (IOException ex) {
logger.log(Level.WARNING, "Failed to close InputStream.", ex); logger.log(Level.WARNING, "Failed to close InputStream.", ex);
return ResultCode.ERROR; return ProcessResult.ERROR;
} }
} }
} }
@ -201,7 +187,6 @@ public final class ExifParserFileIngestModule extends IngestModuleAdapter implem
@Override @Override
public void shutDown(boolean ingestJobCancelled) { public void shutDown(boolean ingestJobCancelled) {
logger.log(Level.INFO, "completed exif parsing {0}", this.toString());
if (filesToFire) { if (filesToFire) {
//send the final new data event //send the final new data event
services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)); services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF));

View File

@ -26,9 +26,9 @@ import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings; import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
/** /**
* An factory that creates file ingest modules that do hash database lookups. * An factory that creates file ingest modules that parse EXIF meta data
* associated with media files (e.g., JPEG format files).
*/ */
@ServiceProvider(service = IngestModuleFactory.class) @ServiceProvider(service = IngestModuleFactory.class)
public class ExifParserModuleFactory extends IngestModuleFactoryAdapter { public class ExifParserModuleFactory extends IngestModuleFactoryAdapter {
@ -39,7 +39,7 @@ public class ExifParserModuleFactory extends IngestModuleFactoryAdapter {
} }
static String getModuleName() { static String getModuleName() {
return NbBundle.getMessage(ExifParserFileIngestModule.class, // RJCTODO: Change bundles? return NbBundle.getMessage(ExifParserFileIngestModule.class,
"ExifParserFileIngestModule.moduleName.text"); "ExifParserFileIngestModule.moduleName.text");
} }

View File

@ -16,7 +16,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.sleuthkit.autopsy.fileextmismatch; package org.sleuthkit.autopsy.fileextmismatch;
import java.awt.Color; import java.awt.Color;
@ -34,11 +33,14 @@ import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.filetypeid.FileTypeIdIngestModule; import org.sleuthkit.autopsy.filetypeid.FileTypeIdIngestModule;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
/** /**
* Container panel for File Extension Mismatch Ingest Module advanced configuration options * Container panel for File Extension Mismatch Ingest Module advanced
* configuration options
*/ */
final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel { final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel implements OptionsPanel {
private static Logger logger = Logger.getLogger(FileExtMismatchConfigPanel.class.getName()); private static Logger logger = Logger.getLogger(FileExtMismatchConfigPanel.class.getName());
private HashMap<String, String[]> editableMap = new HashMap<>(); private HashMap<String, String[]> editableMap = new HashMap<>();
private ArrayList<String> mimeList = null; private ArrayList<String> mimeList = null;
@ -46,33 +48,32 @@ final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel
private MimeTableModel mimeTableModel; private MimeTableModel mimeTableModel;
private ExtTableModel extTableModel; private ExtTableModel extTableModel;
private final String EXT_HEADER_LABEL = NbBundle.getMessage(FileExtMismatchConfigPanel.class, private final String EXT_HEADER_LABEL = NbBundle.getMessage(FileExtMismatchConfigPanel.class,
"AddFileExtensionAction.extHeaderLbl.text"); "AddFileExtensionAction.extHeaderLbl.text");
private String selectedMime = ""; private String selectedMime = "";
private String selectedExt = ""; private String selectedExt = "";
ListSelectionModel lsm = null; ListSelectionModel lsm = null;
public FileExtMismatchConfigPanel() { public FileExtMismatchConfigPanel() {
mimeTableModel = new MimeTableModel(); mimeTableModel = new MimeTableModel();
extTableModel = new ExtTableModel(); extTableModel = new ExtTableModel();
initComponents(); initComponents();
customizeComponents(); customizeComponents();
} }
private void customizeComponents() { private void customizeComponents() {
setName(NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.name.text")); setName(NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.name.text"));
// Handle selections on the left table // Handle selections on the left table
lsm = mimeTable.getSelectionModel(); lsm = mimeTable.getSelectionModel();
lsm.addListSelectionListener(new ListSelectionListener() { lsm.addListSelectionListener(new ListSelectionListener() {
@Override @Override
public void valueChanged(ListSelectionEvent e) { public void valueChanged(ListSelectionEvent e) {
ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource(); ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource();
if (!listSelectionModel.isSelectionEmpty()) { if (!listSelectionModel.isSelectionEmpty()) {
int index = listSelectionModel.getMinSelectionIndex(); int index = listSelectionModel.getMinSelectionIndex();
listSelectionModel.setSelectionInterval(index, index); listSelectionModel.setSelectionInterval(index, index);
selectedMime = mimeList.get(index); selectedMime = mimeList.get(index);
String labelStr = EXT_HEADER_LABEL + selectedMime + ":"; String labelStr = EXT_HEADER_LABEL + selectedMime + ":";
if (labelStr.length() > 80) { if (labelStr.length() > 80) {
@ -80,7 +81,7 @@ final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel
} }
extHeaderLabel.setText(labelStr); extHeaderLabel.setText(labelStr);
updateExtList(); updateExtList();
extTableModel.resync(); extTableModel.resync();
//initButtons(); //initButtons();
} else { } else {
@ -88,32 +89,31 @@ final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel
currentExtensions = null; currentExtensions = null;
extTableModel.resync(); extTableModel.resync();
} }
clearErrLabels(); clearErrLabels();
} }
}); });
// Handle selections on the right table // Handle selections on the right table
ListSelectionModel extLsm = extTable.getSelectionModel(); ListSelectionModel extLsm = extTable.getSelectionModel();
extLsm.addListSelectionListener(new ListSelectionListener() { extLsm.addListSelectionListener(new ListSelectionListener() {
@Override @Override
public void valueChanged(ListSelectionEvent e) { public void valueChanged(ListSelectionEvent e) {
ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource(); ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource();
if (!listSelectionModel.isSelectionEmpty()) { if (!listSelectionModel.isSelectionEmpty()) {
int index = listSelectionModel.getMinSelectionIndex(); int index = listSelectionModel.getMinSelectionIndex();
listSelectionModel.setSelectionInterval(index, index); listSelectionModel.setSelectionInterval(index, index);
selectedExt = currentExtensions.get(index); selectedExt = currentExtensions.get(index);
} else { } else {
selectedExt = ""; selectedExt = "";
} }
extRemoveErrLabel.setText(" "); extRemoveErrLabel.setText(" ");
} }
}); });
} }
private void clearErrLabels() { private void clearErrLabels() {
@ -121,9 +121,9 @@ final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel
mimeRemoveErrLabel.setText(" "); mimeRemoveErrLabel.setText(" ");
extRemoveErrLabel.setText(" "); extRemoveErrLabel.setText(" ");
extErrorLabel.setText(" "); extErrorLabel.setText(" ");
saveMsgLabel.setText(" "); saveMsgLabel.setText(" ");
} }
/** /**
* This method is called from within the constructor to initialize the form. * 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 * WARNING: Do NOT modify this code. The content of this method is always
@ -348,41 +348,41 @@ final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel
private void addExtButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addExtButtonActionPerformed private void addExtButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addExtButtonActionPerformed
String newExt = userExtTextField.getText(); String newExt = userExtTextField.getText();
if (newExt.isEmpty()) { if (newExt.isEmpty()) {
extErrorLabel.setForeground(Color.red); extErrorLabel.setForeground(Color.red);
extErrorLabel.setText( extErrorLabel.setText(
NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addExtButton.errLabel.empty")); NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addExtButton.errLabel.empty"));
return; return;
} }
if (selectedMime.isEmpty()) { if (selectedMime.isEmpty()) {
extErrorLabel.setForeground(Color.red); extErrorLabel.setForeground(Color.red);
extErrorLabel.setText( extErrorLabel.setText(
NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addExtButton.errLabel.noMimeType")); NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addExtButton.errLabel.noMimeType"));
return; return;
} }
if (currentExtensions.contains(newExt)) { if (currentExtensions.contains(newExt)) {
extErrorLabel.setForeground(Color.red); extErrorLabel.setForeground(Color.red);
extErrorLabel.setText( extErrorLabel.setText(
NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addExtButton.errLabel.extExists")); NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addExtButton.errLabel.extExists"));
return; return;
} }
ArrayList<String> editedExtensions = new ArrayList<>(Arrays.asList(editableMap.get(selectedMime))); ArrayList<String> editedExtensions = new ArrayList<>(Arrays.asList(editableMap.get(selectedMime)));
editedExtensions.add(newExt); editedExtensions.add(newExt);
// Old array will be replaced by new array for this key // Old array will be replaced by new array for this key
editableMap.put(selectedMime, editedExtensions.toArray(new String[0])); editableMap.put(selectedMime, editedExtensions.toArray(new String[0]));
// Refresh table // Refresh table
updateExtList(); updateExtList();
extTableModel.resync(); extTableModel.resync();
// user feedback for successful add // user feedback for successful add
extErrorLabel.setForeground(Color.blue); extErrorLabel.setForeground(Color.blue);
extErrorLabel.setText( extErrorLabel.setText(
NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addExtButton.errLabel.extAdded", NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addExtButton.errLabel.extAdded",
newExt)); newExt));
extRemoveErrLabel.setText(" "); extRemoveErrLabel.setText(" ");
userExtTextField.setText(""); userExtTextField.setText("");
setIsModified(); setIsModified();
@ -399,26 +399,26 @@ final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel
mimeErrLabel.setText(NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addTypeButton.empty")); mimeErrLabel.setText(NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addTypeButton.empty"));
return; return;
} }
if (newMime.equals( "application/octet-stream")){ if (newMime.equals("application/octet-stream")) {
mimeErrLabel.setForeground(Color.red); mimeErrLabel.setForeground(Color.red);
mimeErrLabel.setText(NbBundle.getMessage(this.getClass(), mimeErrLabel.setText(NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.addTypeButton.mimeTypeNotSupported")); "FileExtMismatchConfigPanel.addTypeButton.mimeTypeNotSupported"));
return; return;
} }
if (mimeList.contains(newMime)) { if (mimeList.contains(newMime)) {
mimeErrLabel.setForeground(Color.red); mimeErrLabel.setForeground(Color.red);
mimeErrLabel.setText( mimeErrLabel.setText(
NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addTypeButton.mimeTypeExists")); NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addTypeButton.mimeTypeExists"));
return; return;
} }
if (!FileTypeIdIngestModule.isMimeTypeDetectable(newMime)) { if (!FileTypeIdIngestModule.isMimeTypeDetectable(newMime)) {
mimeErrLabel.setForeground(Color.red); mimeErrLabel.setForeground(Color.red);
mimeErrLabel.setText(NbBundle.getMessage(this.getClass(), mimeErrLabel.setText(NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.addTypeButton.mimeTypeNotDetectable")); "FileExtMismatchConfigPanel.addTypeButton.mimeTypeNotDetectable"));
return; return;
} }
editableMap.put(newMime, new String[0]); editableMap.put(newMime, new String[0]);
// Refresh table // Refresh table
@ -449,15 +449,15 @@ final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel
mimeRemoveErrLabel.setText( mimeRemoveErrLabel.setText(
NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.removeTypeButton.noneSelected")); NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.removeTypeButton.noneSelected"));
return; return;
} }
editableMap.remove(selectedMime); editableMap.remove(selectedMime);
String deadMime = selectedMime; String deadMime = selectedMime;
// Refresh table // Refresh table
updateMimeList(); updateMimeList();
mimeTableModel.resync(); mimeTableModel.resync();
// user feedback for successful add // user feedback for successful add
mimeRemoveErrLabel.setForeground(Color.blue); mimeRemoveErrLabel.setForeground(Color.blue);
mimeRemoveErrLabel.setText( mimeRemoveErrLabel.setText(
@ -471,26 +471,26 @@ final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel
extRemoveErrLabel.setText( extRemoveErrLabel.setText(
NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.removeExtButton.noneSelected")); NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.removeExtButton.noneSelected"));
return; return;
} }
if (selectedMime.isEmpty()) { if (selectedMime.isEmpty()) {
extErrorLabel.setForeground(Color.red); extErrorLabel.setForeground(Color.red);
extErrorLabel.setText(NbBundle.getMessage(this.getClass(), extErrorLabel.setText(NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.removeExtButton.noMimeTypeSelected")); "FileExtMismatchConfigPanel.removeExtButton.noMimeTypeSelected"));
return; return;
} }
ArrayList<String> editedExtensions = new ArrayList<>(Arrays.asList(editableMap.get(selectedMime))); ArrayList<String> editedExtensions = new ArrayList<>(Arrays.asList(editableMap.get(selectedMime)));
editedExtensions.remove(selectedExt); editedExtensions.remove(selectedExt);
String deadExt = selectedExt; String deadExt = selectedExt;
// Old array will be replaced by new array for this key // Old array will be replaced by new array for this key
editableMap.put(selectedMime, editedExtensions.toArray(new String[0])); editableMap.put(selectedMime, editedExtensions.toArray(new String[0]));
// Refresh tables // Refresh tables
updateExtList(); updateExtList();
extTableModel.resync(); extTableModel.resync();
// user feedback for successful add // user feedback for successful add
extRemoveErrLabel.setForeground(Color.blue); extRemoveErrLabel.setForeground(Color.blue);
extRemoveErrLabel.setText( extRemoveErrLabel.setText(
@ -504,7 +504,7 @@ final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel
Collections.sort(mimeList); Collections.sort(mimeList);
} }
} }
private void updateExtList() { private void updateExtList() {
String[] temp = editableMap.get(selectedMime); String[] temp = editableMap.get(selectedMime);
if (temp != null) { if (temp != null) {
@ -516,68 +516,72 @@ final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel
currentExtensions = null; currentExtensions = null;
} }
} }
@Override
public void saveSettings() {
if (FileExtMismatchXML.getDefault().save(editableMap)) {
mimeErrLabel.setText(" ");
mimeRemoveErrLabel.setText(" ");
extRemoveErrLabel.setText(" ");
extErrorLabel.setText(" ");
saveMsgLabel.setText(NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.store.msg"));
saveButton.setEnabled(false);
} else {
//error
JOptionPane.showMessageDialog(this,
NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.store.msgDlg.msg"),
NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.save.msgDlg.title"),
JOptionPane.ERROR_MESSAGE);
}
}
@Override @Override
public void load() { public void load() {
// Load the XML into a buffer that the user can modify. They can choose // Load the XML into a buffer that the user can modify. They can choose
// to save it back to the file after making changes. // to save it back to the file after making changes.
editableMap = FileExtMismatchXML.getDefault().load(); editableMap = FileExtMismatchXML.getDefault().load();
updateMimeList(); updateMimeList();
updateExtList(); updateExtList();
} }
@Override @Override
public void store() { public void store() {
if (FileExtMismatchXML.getDefault().save(editableMap)) { saveSettings();
mimeErrLabel.setText(" ");
mimeRemoveErrLabel.setText(" ");
extRemoveErrLabel.setText(" ");
extErrorLabel.setText(" ");
saveMsgLabel.setText(NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.store.msg"));
saveButton.setEnabled(false);
} else {
//error
JOptionPane.showMessageDialog(this,
NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.store.msgDlg.msg"),
NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.save.msgDlg.title"),
JOptionPane.ERROR_MESSAGE);
}
} }
private void setIsModified() { private void setIsModified() {
saveButton.setEnabled(true); saveButton.setEnabled(true);
saveMsgLabel.setText(" "); saveMsgLabel.setText(" ");
} }
public void cancel() { public void cancel() {
clearErrLabels(); clearErrLabels();
load(); // The next time this panel is opened, we want it to be fresh load(); // The next time this panel is opened, we want it to be fresh
} }
public void ok() { public void ok() {
// if data is unsaved // if data is unsaved
if (saveButton.isEnabled()) { if (saveButton.isEnabled()) {
int choice = JOptionPane.showConfirmDialog(this, int choice = JOptionPane.showConfirmDialog(this,
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.ok.confDlg.msg"), "FileExtMismatchConfigPanel.ok.confDlg.msg"),
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.confDlg.title"), "FileExtMismatchConfigPanel.confDlg.title"),
JOptionPane.YES_NO_OPTION); JOptionPane.YES_NO_OPTION);
if (choice == JOptionPane.YES_OPTION) { if (choice == JOptionPane.YES_OPTION) {
store(); store();
} }
} }
clearErrLabels(); clearErrLabels();
load(); // The next time this panel is opened, we want it to be fresh load(); // The next time this panel is opened, we want it to be fresh
} }
boolean valid() { boolean valid() {
return true; return true;
} }
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton addExtButton; private javax.swing.JButton addExtButton;
private javax.swing.JButton addTypeButton; private javax.swing.JButton addTypeButton;
@ -665,7 +669,7 @@ final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel
fireTableDataChanged(); fireTableDataChanged();
} }
} }
private class ExtTableModel extends AbstractTableModel { private class ExtTableModel extends AbstractTableModel {
@Override @Override
@ -696,7 +700,7 @@ final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel
@Override @Override
public Object getValueAt(int rowIndex, int columnIndex) { public Object getValueAt(int rowIndex, int columnIndex) {
Object ret = null; Object ret = null;
if ((currentExtensions == null) || (currentExtensions.size() == 0) || (rowIndex > currentExtensions.size())) { if ((currentExtensions == null) || (currentExtensions.size() == 0) || (rowIndex > currentExtensions.size())) {
return ""; return "";
} }
@ -729,6 +733,5 @@ final class FileExtMismatchConfigPanel extends IngestModuleGlobalSetttingsPanel
void resync() { void resync() {
fireTableDataChanged(); fireTableDataChanged();
} }
} }
} }

View File

@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory; import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings; import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleJobSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleSettingsPanel;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel;
/** /**
@ -35,15 +35,15 @@ import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel;
@ServiceProvider(service = IngestModuleFactory.class) @ServiceProvider(service = IngestModuleFactory.class)
public class FileExtMismatchDetectorModuleFactory extends IngestModuleFactoryAdapter { public class FileExtMismatchDetectorModuleFactory extends IngestModuleFactoryAdapter {
@Override
public String getModuleDisplayName() {
return getModuleName();
}
static String getModuleName() { static String getModuleName() {
return NbBundle.getMessage(FileExtMismatchIngestModule.class, return NbBundle.getMessage(FileExtMismatchIngestModule.class,
"FileExtMismatchIngestModule.moduleName"); "FileExtMismatchIngestModule.moduleName");
} }
@Override
public String getModuleDisplayName() {
return getModuleName();
}
@Override @Override
public String getModuleDescription() { public String getModuleDescription() {
@ -67,7 +67,7 @@ public class FileExtMismatchDetectorModuleFactory extends IngestModuleFactoryAda
} }
@Override @Override
public IngestModuleJobSettingsPanel getModuleSettingsPanel(IngestModuleSettings ingestOptions) { public IngestModuleSettingsPanel getModuleSettingsPanel(IngestModuleSettings ingestOptions) {
FileExtMismatchSimpleConfigPanel ingestOptionsPanel = new FileExtMismatchSimpleConfigPanel((FileExtMismatchDetectorOptions) ingestOptions); FileExtMismatchSimpleConfigPanel ingestOptionsPanel = new FileExtMismatchSimpleConfigPanel((FileExtMismatchDetectorOptions) ingestOptions);
return ingestOptionsPanel; return ingestOptionsPanel;
} }
@ -91,6 +91,6 @@ public class FileExtMismatchDetectorModuleFactory extends IngestModuleFactoryAda
@Override @Override
public FileIngestModule createFileIngestModule(IngestModuleSettings ingestOptions) { public FileIngestModule createFileIngestModule(IngestModuleSettings ingestOptions) {
return new FileExtMismatchIngestModule(); return new FileExtMismatchIngestModule(); // RJCTODO: Update to pass in options
} }
} }

View File

@ -47,42 +47,40 @@ import org.sleuthkit.datamodel.TskException;
*/ */
public class FileExtMismatchIngestModule extends IngestModuleAdapter implements FileIngestModule { public class FileExtMismatchIngestModule extends IngestModuleAdapter implements FileIngestModule {
private static final Logger logger = Logger.getLogger(FileExtMismatchIngestModule.class.getName()); private static final Logger logger = Logger.getLogger(FileExtMismatchIngestModule.class.getName());
private static long processTime = 0; private static long processTime = 0; // RJCTODO: This is not thread safe
private static int messageId = 0; private static int messageId = 0; // RJCTODO: This is not thread safe
private static long numFiles = 0; private static long numFiles = 0; // RJCTODO: This is not thread safe
private final IngestServices services = IngestServices.getDefault();
private boolean skipKnown = false; private boolean skipKnown = false;
private boolean skipNoExt = true; private boolean skipNoExt = true;
private boolean skipTextPlain = false; private boolean skipTextPlain = false;
private IngestServices services;
private HashMap<String, String[]> SigTypeToExtMap = new HashMap<>(); private HashMap<String, String[]> SigTypeToExtMap = new HashMap<>();
FileExtMismatchIngestModule() { FileExtMismatchIngestModule() {
} }
@Override @Override
public void startUp(IngestJobContext context) throws Exception { public void startUp(IngestJobContext context) throws IngestModuleException {
super.startUp(context);
services = IngestServices.getDefault();
FileExtMismatchXML xmlLoader = FileExtMismatchXML.getDefault(); FileExtMismatchXML xmlLoader = FileExtMismatchXML.getDefault();
SigTypeToExtMap = xmlLoader.load(); SigTypeToExtMap = xmlLoader.load();
} }
@Override @Override
public ResultCode process(AbstractFile abstractFile) { public ProcessResult process(AbstractFile abstractFile) {
// skip non-files // skip non-files
if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) || if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) ||
(abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) { (abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) {
return ResultCode.OK; return ProcessResult.OK;
} }
// deleted files often have content that was not theirs and therefor causes mismatch // deleted files often have content that was not theirs and therefor causes mismatch
if ((abstractFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)) || if ((abstractFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)) ||
(abstractFile.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC))) { (abstractFile.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC))) {
return ResultCode.OK; return ProcessResult.OK;
} }
if (skipKnown && (abstractFile.getKnown() == FileKnown.KNOWN)) { if (skipKnown && (abstractFile.getKnown() == FileKnown.KNOWN)) {
return ResultCode.OK; return ProcessResult.OK;
} }
try try
@ -100,10 +98,10 @@ public class FileExtMismatchIngestModule extends IngestModuleAdapter implements
services.fireModuleDataEvent(new ModuleDataEvent(FileExtMismatchDetectorModuleFactory.getModuleName(), ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED, Collections.singletonList(bart))); services.fireModuleDataEvent(new ModuleDataEvent(FileExtMismatchDetectorModuleFactory.getModuleName(), ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED, Collections.singletonList(bart)));
} }
return ResultCode.OK; return ProcessResult.OK;
} catch (TskException ex) { } catch (TskException ex) {
logger.log(Level.WARNING, "Error matching file signature", ex); logger.log(Level.WARNING, "Error matching file signature", ex);
return ResultCode.ERROR; return ProcessResult.ERROR;
} }
} }
@ -161,7 +159,7 @@ public class FileExtMismatchIngestModule extends IngestModuleAdapter implements
//details //details
detailsSb.append("<table border='0' cellpadding='4' width='280'>"); detailsSb.append("<table border='0' cellpadding='4' width='280'>");
detailsSb.append("<tr><td>" + FileExtMismatchDetectorModuleFactory.getModuleName() + "</td></tr>"); detailsSb.append("<tr><td>").append(FileExtMismatchDetectorModuleFactory.getModuleName()).append("</td></tr>");
detailsSb.append("<tr><td>").append( detailsSb.append("<tr><td>").append(
NbBundle.getMessage(this.getClass(), "FileExtMismatchIngestModule.complete.totalProcTime")) NbBundle.getMessage(this.getClass(), "FileExtMismatchIngestModule.complete.totalProcTime"))
@ -177,17 +175,17 @@ public class FileExtMismatchIngestModule extends IngestModuleAdapter implements
detailsSb.toString())); detailsSb.toString()));
} }
// RJCTODO: Ingest setting // RJCTODO: Ingest job setting
public void setSkipKnown(boolean flag) { public void setSkipKnown(boolean flag) {
skipKnown = flag; skipKnown = flag;
} }
// RJCTODO: Ingest setting // RJCTODO: Ingest job setting
public void setSkipNoExt(boolean flag) { public void setSkipNoExt(boolean flag) {
skipNoExt = flag; skipNoExt = flag;
} }
// RJCTODO: Ingest setting // RJCTODO: Ingest job setting
public void setSkipTextPlain(boolean flag) { public void setSkipTextPlain(boolean flag) {
skipTextPlain = flag; skipTextPlain = flag;
} }

View File

@ -19,13 +19,13 @@
package org.sleuthkit.autopsy.fileextmismatch; package org.sleuthkit.autopsy.fileextmismatch;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings; import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleJobSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleSettingsPanel;
/** /**
* UI component used to set ingest job options for file extension mismatch * UI component used to set ingest job options for file extension mismatch
* detector ingest modules. * detector ingest modules.
*/ */
class FileExtMismatchSimpleConfigPanel extends IngestModuleJobSettingsPanel { class FileExtMismatchSimpleConfigPanel extends IngestModuleSettingsPanel {
private FileExtMismatchDetectorOptions ingestJobOptions; private FileExtMismatchDetectorOptions ingestJobOptions;
@ -41,7 +41,7 @@ class FileExtMismatchSimpleConfigPanel extends IngestModuleJobSettingsPanel {
} }
@Override @Override
public IngestModuleSettings getIngestJobOptions() { public IngestModuleSettings getSettings() {
return ingestJobOptions; return ingestJobOptions;
} }

View File

@ -32,7 +32,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskData.FileKnown; import org.sleuthkit.datamodel.TskData.FileKnown;
import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.autopsy.ingest.IngestModule.ResultCode; import org.sleuthkit.autopsy.ingest.IngestModule.ProcessResult;
import org.sleuthkit.autopsy.ingest.IngestModuleAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleAdapter;
/** /**
@ -45,7 +45,7 @@ public class FileTypeIdIngestModule extends IngestModuleAdapter implements FileI
private static final long MIN_FILE_SIZE = 512; private static final long MIN_FILE_SIZE = 512;
private final FileTypeIdentifierIngestJobOptions ingestJobOptions; private final FileTypeIdentifierIngestJobOptions ingestJobOptions;
private long matchTime = 0; private long matchTime = 0;
private int messageId = 0; private int messageId = 0; // RJCTODO: If this is not made a thread safe static, duplicate message ids will be used
private long numFiles = 0; private long numFiles = 0;
// The detector. Swap out with a different implementation of FileTypeDetectionInterface as needed. // The detector. Swap out with a different implementation of FileTypeDetectionInterface as needed.
// If desired in the future to be more knowledgable about weird files or rare formats, we could // If desired in the future to be more knowledgable about weird files or rare formats, we could
@ -57,20 +57,20 @@ public class FileTypeIdIngestModule extends IngestModuleAdapter implements FileI
} }
@Override @Override
public ResultCode process(AbstractFile abstractFile) { public ProcessResult process(AbstractFile abstractFile) {
// skip non-files // skip non-files
if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
|| (abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) { || (abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) {
return ResultCode.OK; return ProcessResult.OK;
} }
if (ingestJobOptions.shouldSkipKnownFiles() && (abstractFile.getKnown() == FileKnown.KNOWN)) { if (ingestJobOptions.shouldSkipKnownFiles() && (abstractFile.getKnown() == FileKnown.KNOWN)) {
return ResultCode.OK; return ProcessResult.OK;
} }
if (abstractFile.getSize() < MIN_FILE_SIZE) { if (abstractFile.getSize() < MIN_FILE_SIZE) {
return ResultCode.OK; return ProcessResult.OK;
} }
try { try {
@ -87,13 +87,13 @@ public class FileTypeIdIngestModule extends IngestModuleAdapter implements FileI
// we don't fire the event because we just updated TSK_GEN_INFO, which isn't displayed in the tree and is vague. // we don't fire the event because we just updated TSK_GEN_INFO, which isn't displayed in the tree and is vague.
} }
return ResultCode.OK; return ProcessResult.OK;
} catch (TskException ex) { } catch (TskException ex) {
logger.log(Level.WARNING, "Error matching file signature", ex); logger.log(Level.WARNING, "Error matching file signature", ex);
return ResultCode.ERROR; return ProcessResult.ERROR;
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.WARNING, "Error matching file signature", e); logger.log(Level.WARNING, "Error matching file signature", e);
return ResultCode.ERROR; return ProcessResult.ERROR;
} }
} }
@ -105,26 +105,27 @@ public class FileTypeIdIngestModule extends IngestModuleAdapter implements FileI
detailsSb.append("<tr><td>").append(FileTypeIdentifierModuleFactory.getModuleName()).append("</td></tr>"); detailsSb.append("<tr><td>").append(FileTypeIdentifierModuleFactory.getModuleName()).append("</td></tr>");
detailsSb.append("<tr><td>") detailsSb.append("<tr><td>")
.append(NbBundle.getMessage(this.getClass(), "FileTypeIdIngestModule.complete.totalProcTime")) .append(NbBundle.getMessage(this.getClass(), "FileTypeIdIngestModule.complete.totalProcTime"))
.append("</td><td>").append(matchTime).append("</td></tr>\n"); .append("</td><td>").append(matchTime).append("</td></tr>\n");
detailsSb.append("<tr><td>") detailsSb.append("<tr><td>")
.append(NbBundle.getMessage(this.getClass(), "FileTypeIdIngestModule.complete.totalFiles")) .append(NbBundle.getMessage(this.getClass(), "FileTypeIdIngestModule.complete.totalFiles"))
.append("</td><td>").append(numFiles).append("</td></tr>\n"); .append("</td><td>").append(numFiles).append("</td></tr>\n");
detailsSb.append("</table>"); detailsSb.append("</table>");
IngestServices.getDefault().postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, FileTypeIdentifierModuleFactory.getModuleName(), IngestServices.getDefault().postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, FileTypeIdentifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"FileTypeIdIngestModule.complete.srvMsg.text"), "FileTypeIdIngestModule.complete.srvMsg.text"),
detailsSb.toString())); detailsSb.toString()));
} }
/** /**
* Validate if a given mime type is in the detector's registry. * Validate if a given mime type is in the detector's registry.
*
* @param mimeType Full string of mime type, e.g. "text/html" * @param mimeType Full string of mime type, e.g. "text/html"
* @return true if detectable * @return true if detectable
*/ */
public static boolean isMimeTypeDetectable(String mimeType) { public static boolean isMimeTypeDetectable(String mimeType) {
FileTypeDetectionInterface detector = new TikaFileTypeDetector(); FileTypeDetectionInterface detector = new TikaFileTypeDetector();
return detector.isMimeTypeDetectable(mimeType); return detector.isMimeTypeDetectable(mimeType);
} }
} }

View File

@ -19,13 +19,13 @@
package org.sleuthkit.autopsy.filetypeid; package org.sleuthkit.autopsy.filetypeid;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings; import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleJobSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleSettingsPanel;
/** /**
* UI component used to set ingest job options for file type identifier ingest * UI component used to set ingest job options for file type identifier ingest
* modules. * modules.
*/ */
class FileTypeIdSimpleConfigPanel extends IngestModuleJobSettingsPanel { class FileTypeIdSimpleConfigPanel extends IngestModuleSettingsPanel {
private final FileTypeIdentifierIngestJobOptions ingestJobOptions; private final FileTypeIdentifierIngestJobOptions ingestJobOptions;
@ -40,7 +40,7 @@ class FileTypeIdSimpleConfigPanel extends IngestModuleJobSettingsPanel {
} }
@Override @Override
public IngestModuleSettings getIngestJobOptions() { public IngestModuleSettings getSettings() {
return ingestJobOptions; return ingestJobOptions;
} }

View File

@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory; import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings; import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleJobSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleSettingsPanel;
/** /**
* An factory that creates file ingest modules that determine the types of * An factory that creates file ingest modules that determine the types of
@ -66,7 +66,7 @@ public class FileTypeIdentifierModuleFactory extends IngestModuleFactoryAdapter
} }
@Override @Override
public IngestModuleJobSettingsPanel getModuleSettingsPanel(IngestModuleSettings ingestJobOptions) { public IngestModuleSettingsPanel getModuleSettingsPanel(IngestModuleSettings ingestJobOptions) {
return new FileTypeIdSimpleConfigPanel((FileTypeIdentifierIngestJobOptions) ingestJobOptions); return new FileTypeIdSimpleConfigPanel((FileTypeIdentifierIngestJobOptions) ingestJobOptions);
} }

View File

@ -38,6 +38,7 @@ import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer; import javax.swing.table.TableCellRenderer;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -46,9 +47,11 @@ import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb.KnownFilesType;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel;
/** /**
* Instances of this class provide a comprehensive UI for managing the hash sets configuration. * Instances of this class provide a comprehensive UI for managing the hash sets
* configuration.
*/ */
public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel { public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel implements OptionsPanel {
private static final String NO_SELECTION_TEXT = NbBundle private static final String NO_SELECTION_TEXT = NbBundle
.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.noSelectionText"); .getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.noSelectionText");
private static final String ERROR_GETTING_PATH_TEXT = NbBundle private static final String ERROR_GETTING_PATH_TEXT = NbBundle
@ -56,13 +59,13 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
private static final String ERROR_GETTING_INDEX_STATUS_TEXT = NbBundle private static final String ERROR_GETTING_INDEX_STATUS_TEXT = NbBundle
.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.errorGettingIndexStatusText"); .getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.errorGettingIndexStatusText");
private HashDbManager hashSetManager = HashDbManager.getInstance(); private HashDbManager hashSetManager = HashDbManager.getInstance();
private HashSetTableModel hashSetTableModel = new HashSetTableModel(); private HashSetTableModel hashSetTableModel = new HashSetTableModel();
public HashDbConfigPanel() { public HashDbConfigPanel() {
initComponents(); initComponents();
customizeComponents(); customizeComponents();
updateComponentsForNoSelection(); updateComponentsForNoSelection();
// Listen to the ingest modules to refresh the enabled/disabled state of // Listen to the ingest modules to refresh the enabled/disabled state of
// the components in sync with file ingest. // the components in sync with file ingest.
IngestManager.addPropertyChangeListener(new PropertyChangeListener() { IngestManager.addPropertyChangeListener(new PropertyChangeListener() {
@ -72,9 +75,9 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
updateComponents(); updateComponents();
} }
} }
}); });
} }
private void customizeComponents() { private void customizeComponents() {
setName(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.setName.hashSetConfig")); setName(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.setName.hashSetConfig"));
this.ingestWarningLabel.setVisible(false); this.ingestWarningLabel.setVisible(false);
@ -89,21 +92,20 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
updateComponents(); updateComponents();
} }
} }
}); });
} }
private void updateComponents() { private void updateComponents() {
HashDb db = ((HashSetTable)hashSetTable).getSelection(); HashDb db = ((HashSetTable) hashSetTable).getSelection();
if (db != null) { if (db != null) {
updateComponentsForSelection(db); updateComponentsForSelection(db);
} } else {
else {
updateComponentsForNoSelection(); updateComponentsForNoSelection();
} }
} }
private void updateComponentsForNoSelection() { private void updateComponentsForNoSelection() {
boolean ingestIsRunning = IngestManager.getDefault().isIngestRunning(); boolean ingestIsRunning = IngestManager.getDefault().isIngestRunning();
// Update descriptive labels. // Update descriptive labels.
hashDbNameLabel.setText(NO_SELECTION_TEXT); hashDbNameLabel.setText(NO_SELECTION_TEXT);
@ -115,46 +117,44 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
hashDbIndexStatusLabel.setText(NO_SELECTION_TEXT); hashDbIndexStatusLabel.setText(NO_SELECTION_TEXT);
hashDbIndexStatusLabel.setForeground(Color.black); hashDbIndexStatusLabel.setForeground(Color.black);
indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index")); indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index"));
indexButton.setEnabled(false); indexButton.setEnabled(false);
// Update ingest options. // Update ingest options.
sendIngestMessagesCheckBox.setSelected(false); sendIngestMessagesCheckBox.setSelected(false);
sendIngestMessagesCheckBox.setEnabled(false); sendIngestMessagesCheckBox.setEnabled(false);
optionsLabel.setEnabled(false); optionsLabel.setEnabled(false);
optionsSeparator.setEnabled(false); optionsSeparator.setEnabled(false);
// Update database action buttons. // Update database action buttons.
createDatabaseButton.setEnabled(true); createDatabaseButton.setEnabled(true);
importDatabaseButton.setEnabled(true); importDatabaseButton.setEnabled(true);
deleteDatabaseButton.setEnabled(false); deleteDatabaseButton.setEnabled(false);
// Update ingest in progress warning label. // Update ingest in progress warning label.
ingestWarningLabel.setVisible(ingestIsRunning); ingestWarningLabel.setVisible(ingestIsRunning);
} }
private void updateComponentsForSelection(HashDb db) { private void updateComponentsForSelection(HashDb db) {
boolean ingestIsRunning = IngestManager.getDefault().isIngestRunning(); boolean ingestIsRunning = IngestManager.getDefault().isIngestRunning();
// Update descriptive labels. // Update descriptive labels.
hashDbNameLabel.setText(db.getHashSetName()); hashDbNameLabel.setText(db.getHashSetName());
hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName());
try { try {
hashDbLocationLabel.setText(shortenPath(db.getDatabasePath())); hashDbLocationLabel.setText(shortenPath(db.getDatabasePath()));
} } catch (TskCoreException ex) {
catch (TskCoreException ex) {
Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting database path of " + db.getHashSetName() + " hash database", ex); Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting database path of " + db.getHashSetName() + " hash database", ex);
hashDbLocationLabel.setText(ERROR_GETTING_PATH_TEXT); hashDbLocationLabel.setText(ERROR_GETTING_PATH_TEXT);
} }
try { try {
indexPathLabel.setText(shortenPath(db.getIndexPath())); indexPathLabel.setText(shortenPath(db.getIndexPath()));
} } catch (TskCoreException ex) {
catch (TskCoreException ex) {
Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index path of " + db.getHashSetName() + " hash database", ex); Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index path of " + db.getHashSetName() + " hash database", ex);
indexPathLabel.setText(ERROR_GETTING_PATH_TEXT); indexPathLabel.setText(ERROR_GETTING_PATH_TEXT);
} }
// Update indexing components. // Update indexing components.
try { try {
if (db.isIndexing()) { if (db.isIndexing()) {
@ -164,13 +164,11 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexGen")); NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexGen"));
hashDbIndexStatusLabel.setForeground(Color.black); hashDbIndexStatusLabel.setForeground(Color.black);
indexButton.setEnabled(false); indexButton.setEnabled(false);
} } else if (db.hasIndex()) {
else if (db.hasIndex()) {
if (db.hasIndexOnly()) { if (db.hasIndexOnly()) {
hashDbIndexStatusLabel.setText( hashDbIndexStatusLabel.setText(
NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexOnly")); NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexOnly"));
} } else {
else {
hashDbIndexStatusLabel.setText( hashDbIndexStatusLabel.setText(
NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexed")); NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexed"));
} }
@ -179,28 +177,25 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
indexButton.setText( indexButton.setText(
NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.reIndex")); NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.reIndex"));
indexButton.setEnabled(true); indexButton.setEnabled(true);
} } else {
else {
indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index")); indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index"));
indexButton.setEnabled(false); indexButton.setEnabled(false);
} }
} } else {
else {
hashDbIndexStatusLabel.setText( hashDbIndexStatusLabel.setText(
NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.noIndex")); NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.noIndex"));
hashDbIndexStatusLabel.setForeground(Color.red); hashDbIndexStatusLabel.setForeground(Color.red);
indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index")); indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index"));
indexButton.setEnabled(true); indexButton.setEnabled(true);
} }
} } catch (TskCoreException ex) {
catch (TskCoreException ex) { Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index state of hash database", ex);
Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index state of hash database", ex);
hashDbIndexStatusLabel.setText(ERROR_GETTING_INDEX_STATUS_TEXT); hashDbIndexStatusLabel.setText(ERROR_GETTING_INDEX_STATUS_TEXT);
hashDbIndexStatusLabel.setForeground(Color.red); hashDbIndexStatusLabel.setForeground(Color.red);
indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index")); indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index"));
indexButton.setEnabled(false); indexButton.setEnabled(false);
} }
// Disable the indexing button if ingest is in progress. // Disable the indexing button if ingest is in progress.
if (ingestIsRunning) { if (ingestIsRunning) {
indexButton.setEnabled(false); indexButton.setEnabled(false);
@ -211,36 +206,30 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
sendIngestMessagesCheckBox.setEnabled(!ingestIsRunning && db.getSearchDuringIngest() && db.getKnownFilesType().equals(KnownFilesType.KNOWN_BAD)); sendIngestMessagesCheckBox.setEnabled(!ingestIsRunning && db.getSearchDuringIngest() && db.getKnownFilesType().equals(KnownFilesType.KNOWN_BAD));
optionsLabel.setEnabled(!ingestIsRunning); optionsLabel.setEnabled(!ingestIsRunning);
optionsSeparator.setEnabled(!ingestIsRunning); optionsSeparator.setEnabled(!ingestIsRunning);
// Update database action buttons. // Update database action buttons.
createDatabaseButton.setEnabled(true); createDatabaseButton.setEnabled(true);
importDatabaseButton.setEnabled(true); importDatabaseButton.setEnabled(true);
deleteDatabaseButton.setEnabled(!ingestIsRunning); deleteDatabaseButton.setEnabled(!ingestIsRunning);
// Update ingest in progress warning label. // Update ingest in progress warning label.
ingestWarningLabel.setVisible(ingestIsRunning); ingestWarningLabel.setVisible(ingestIsRunning);
} }
private static String shortenPath(String path) { private static String shortenPath(String path) {
String shortenedPath = path; String shortenedPath = path;
if (shortenedPath.length() > 50){ if (shortenedPath.length() > 50) {
shortenedPath = shortenedPath.substring(0, 10 + shortenedPath.substring(10).indexOf(File.separator) + 1) + "..." + shortenedPath.substring((shortenedPath.length() - 20) + shortenedPath.substring(shortenedPath.length() - 20).indexOf(File.separator)); shortenedPath = shortenedPath.substring(0, 10 + shortenedPath.substring(10).indexOf(File.separator) + 1) + "..." + shortenedPath.substring((shortenedPath.length() - 20) + shortenedPath.substring(shortenedPath.length() - 20).indexOf(File.separator));
} }
return shortenedPath; return shortenedPath;
} }
private boolean isFileIngestStatusChangeEvent(PropertyChangeEvent evt) { private boolean isFileIngestStatusChangeEvent(PropertyChangeEvent evt) {
return evt.getPropertyName().equals(IngestManager.IngestModuleEvent.STARTED.toString()) || evt.getPropertyName().equals(IngestManager.IngestModuleEvent.COMPLETED.toString()) || evt.getPropertyName().equals(IngestManager.IngestModuleEvent.STOPPED.toString()); return evt.getPropertyName().equals(IngestManager.IngestModuleEvent.STARTED.toString()) || evt.getPropertyName().equals(IngestManager.IngestModuleEvent.COMPLETED.toString()) || evt.getPropertyName().equals(IngestManager.IngestModuleEvent.STOPPED.toString());
}
@Override
public void load() {
hashSetTable.clearSelection();
hashSetTableModel.refreshModel();
} }
@Override @Override
public void store() { public void saveSettings() {
//Checking for for any unindexed databases //Checking for for any unindexed databases
List<HashDb> unindexed = new ArrayList<>(); List<HashDb> unindexed = new ArrayList<>();
for (HashDb hashSet : hashSetManager.getAllHashSets()) { for (HashDb hashSet : hashSetManager.getAllHashSets()) {
@ -248,66 +237,76 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
if (!hashSet.hasIndex()) { if (!hashSet.hasIndex()) {
unindexed.add(hashSet); unindexed.add(hashSet);
} }
} } catch (TskCoreException ex) {
catch (TskCoreException ex) { Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex);
Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex);
} }
} }
//If unindexed ones are found, show a popup box that will either index them, or remove them. //If unindexed ones are found, show a popup box that will either index them, or remove them.
if (unindexed.size() == 1){ if (unindexed.size() == 1) {
showInvalidIndex(false, unindexed); showInvalidIndex(false, unindexed);
} } else if (unindexed.size() > 1) {
else if (unindexed.size() > 1){
showInvalidIndex(true, unindexed); showInvalidIndex(true, unindexed);
} }
hashSetManager.save(); hashSetManager.save();
} }
@Override
public void load() {
hashSetTable.clearSelection();
hashSetTableModel.refreshModel();
}
@Override
public void store() {
saveSettings();
}
public void cancel() { public void cancel() {
HashDbManager.getInstance().loadLastSavedConfiguration(); HashDbManager.getInstance().loadLastSavedConfiguration();
} }
void removeThese(List<HashDb> toRemove) { void removeThese(List<HashDb> toRemove) {
for (HashDb hashDb : toRemove) { for (HashDb hashDb : toRemove) {
hashSetManager.removeHashDatabaseInternal(hashDb); hashSetManager.removeHashDatabaseInternal(hashDb);
} }
hashSetTableModel.refreshModel(); hashSetTableModel.refreshModel();
} }
/** /**
* Displays the popup box that tells user that some of his databases are unindexed, along with solutions. * Displays the popup box that tells user that some of his databases are
* This method is related to ModalNoButtons, to be removed at a later date. * unindexed, along with solutions. This method is related to
* ModalNoButtons, to be removed at a later date.
*
* @param plural Whether or not there are multiple unindexed databases * @param plural Whether or not there are multiple unindexed databases
* @param unindexed The list of unindexed databases. Can be of size 1. * @param unindexed The list of unindexed databases. Can be of size 1.
*/ */
private void showInvalidIndex(boolean plural, List<HashDb> unindexed){ private void showInvalidIndex(boolean plural, List<HashDb> unindexed) {
String total = ""; String total = "";
String message; String message;
for(HashDb hdb : unindexed){ for (HashDb hdb : unindexed) {
total+= "\n" + hdb.getHashSetName(); total += "\n" + hdb.getHashSetName();
} }
if(plural){ if (plural) {
message = NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.dbsNotIndexedMsg", total); message = NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.dbsNotIndexedMsg", total);
} } else {
else{
message = NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.dbNotIndexedMsg", total); message = NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.dbNotIndexedMsg", total);
} }
int res = JOptionPane.showConfirmDialog(this, message, int res = JOptionPane.showConfirmDialog(this, message,
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"HashDbConfigPanel.unindexedDbsMsg"), "HashDbConfigPanel.unindexedDbsMsg"),
JOptionPane.YES_NO_OPTION); JOptionPane.YES_NO_OPTION);
if(res == JOptionPane.YES_OPTION){ if (res == JOptionPane.YES_OPTION) {
ModalNoButtons indexingDialog = new ModalNoButtons(this, new Frame(),unindexed); ModalNoButtons indexingDialog = new ModalNoButtons(this, new Frame(), unindexed);
indexingDialog.setLocationRelativeTo(null); indexingDialog.setLocationRelativeTo(null);
indexingDialog.setVisible(true); indexingDialog.setVisible(true);
indexingDialog.setModal(true); indexingDialog.setModal(true);
hashSetTableModel.refreshModel(); hashSetTableModel.refreshModel();
} }
if(res == JOptionPane.NO_OPTION){ if (res == JOptionPane.NO_OPTION) {
JOptionPane.showMessageDialog(this, NbBundle.getMessage(this.getClass(), JOptionPane.showMessageDialog(this, NbBundle.getMessage(this.getClass(),
"HashDbConfigPanel.allUnindexedDbsRmFromListMsg")); "HashDbConfigPanel.allUnindexedDbsRmFromListMsg"));
removeThese(unindexed); removeThese(unindexed);
} }
} }
@ -315,30 +314,30 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
boolean valid() { boolean valid() {
return true; return true;
} }
/** /**
* This class implements a table for displaying configured hash sets. * This class implements a table for displaying configured hash sets.
*/ */
private class HashSetTable extends JTable { private class HashSetTable extends JTable {
@Override @Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
// Use the hash set name as the cell text. // Use the hash set name as the cell text.
JComponent cellRenderer = (JComponent)super.prepareRenderer(renderer, row, column); JComponent cellRenderer = (JComponent) super.prepareRenderer(renderer, row, column);
cellRenderer.setToolTipText((String)getValueAt(row, column)); cellRenderer.setToolTipText((String) getValueAt(row, column));
// Give the user a visual indication of any hash sets with a hash // Give the user a visual indication of any hash sets with a hash
// database that needs to be indexed by displaying the hash set name // database that needs to be indexed by displaying the hash set name
// in red. // in red.
if (hashSetTableModel.indexExists(row)){ if (hashSetTableModel.indexExists(row)) {
cellRenderer.setForeground(Color.black); cellRenderer.setForeground(Color.black);
} } else {
else{
cellRenderer.setForeground(Color.red); cellRenderer.setForeground(Color.red);
} }
return cellRenderer; return cellRenderer;
} }
public HashDb getSelection() { public HashDb getSelection() {
return hashSetTableModel.getHashSetAt(getSelectionModel().getMinSelectionIndex()); return hashSetTableModel.getHashSetAt(getSelectionModel().getMinSelectionIndex());
} }
@ -348,19 +347,20 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
getSelectionModel().setSelectionInterval(index, index); getSelectionModel().setSelectionInterval(index, index);
} }
} }
public void selectRowByName(String name) { public void selectRowByName(String name) {
setSelection(hashSetTableModel.getIndexByName(name)); setSelection(hashSetTableModel.getIndexByName(name));
} }
} }
/** /**
* This class implements the table model for the table used to display * This class implements the table model for the table used to display
* configured hash sets. * configured hash sets.
*/ */
private class HashSetTableModel extends AbstractTableModel { private class HashSetTableModel extends AbstractTableModel {
List<HashDb> hashSets = HashDbManager.getInstance().getAllHashSets(); List<HashDb> hashSets = HashDbManager.getInstance().getAllHashSets();
@Override @Override
public int getColumnCount() { public int getColumnCount() {
return 1; return 1;
@ -380,17 +380,16 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
public Object getValueAt(int rowIndex, int columnIndex) { public Object getValueAt(int rowIndex, int columnIndex) {
return hashSets.get(rowIndex).getHashSetName(); return hashSets.get(rowIndex).getHashSetName();
} }
private boolean indexExists(int rowIndex){ private boolean indexExists(int rowIndex) {
try { try {
return hashSets.get(rowIndex).hasIndex(); return hashSets.get(rowIndex).hasIndex();
} } catch (TskCoreException ex) {
catch (TskCoreException ex) { Logger.getLogger(HashSetTableModel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex);
Logger.getLogger(HashSetTableModel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex);
return false; return false;
} }
} }
@Override @Override
public boolean isCellEditable(int rowIndex, int columnIndex) { public boolean isCellEditable(int rowIndex, int columnIndex) {
return false; return false;
@ -409,32 +408,31 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
HashDb getHashSetAt(int index) { HashDb getHashSetAt(int index) {
if (!hashSets.isEmpty() && index >= 0 && index < hashSets.size()) { if (!hashSets.isEmpty() && index >= 0 && index < hashSets.size()) {
return hashSets.get(index); return hashSets.get(index);
} } else {
else {
return null; return null;
} }
} }
int getIndexByName(String name) { int getIndexByName(String name) {
for (int i = 0; i < hashSets.size(); ++i) { for (int i = 0; i < hashSets.size(); ++i) {
if (hashSets.get(i).getHashSetName().equals(name)) { if (hashSets.get(i).getHashSetName().equals(name)) {
return i; return i;
} }
} }
return -1; return -1;
} }
void refreshModel() { void refreshModel() {
hashSets = HashDbManager.getInstance().getAllHashSets(); hashSets = HashDbManager.getInstance().getAllHashSets();
refreshDisplay(); refreshDisplay();
} }
void refreshDisplay() { void refreshDisplay() {
fireTableDataChanged(); fireTableDataChanged();
} }
} }
/** /**
* This method is called from within the constructor to initialize the form. * 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 * WARNING: Do NOT modify this code. The content of this method is always
@ -692,22 +690,22 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void indexButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexButtonActionPerformed private void indexButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexButtonActionPerformed
final HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); final HashDb hashDb = ((HashSetTable) hashSetTable).getSelection();
assert hashDb != null; assert hashDb != null;
// Add a listener for the INDEXING_DONE event. This listener will update // Add a listener for the INDEXING_DONE event. This listener will update
// the UI. // the UI.
hashDb.addPropertyChangeListener(new PropertyChangeListener() { hashDb.addPropertyChangeListener(new PropertyChangeListener() {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) { if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) {
HashDb selectedHashDb = ((HashSetTable)hashSetTable).getSelection(); HashDb selectedHashDb = ((HashSetTable) hashSetTable).getSelection();
if (selectedHashDb != null && hashDb != null && hashDb.equals(selectedHashDb)) { if (selectedHashDb != null && hashDb != null && hashDb.equals(selectedHashDb)) {
updateComponents(); updateComponents();
} }
hashSetTableModel.refreshDisplay(); hashSetTableModel.refreshDisplay();
} }
} }
}); });
// Display a modal dialog box to kick off the indexing on a worker thread // Display a modal dialog box to kick off the indexing on a worker thread
@ -718,17 +716,17 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
ModalNoButtons indexDialog = new ModalNoButtons(this, new Frame(), hashDb); ModalNoButtons indexDialog = new ModalNoButtons(this, new Frame(), hashDb);
indexDialog.setLocationRelativeTo(null); indexDialog.setLocationRelativeTo(null);
indexDialog.setVisible(true); indexDialog.setVisible(true);
indexDialog.setModal(true); indexDialog.setModal(true);
}//GEN-LAST:event_indexButtonActionPerformed }//GEN-LAST:event_indexButtonActionPerformed
private void deleteDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteDatabaseButtonActionPerformed private void deleteDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteDatabaseButtonActionPerformed
if (JOptionPane.showConfirmDialog(null, if (JOptionPane.showConfirmDialog(null,
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"HashDbConfigPanel.deleteDbActionConfirmMsg"), "HashDbConfigPanel.deleteDbActionConfirmMsg"),
NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.deleteDbActionMsg"), NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.deleteDbActionMsg"),
JOptionPane.YES_NO_OPTION, JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) { JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) {
HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); HashDb hashDb = ((HashSetTable) hashSetTable).getSelection();
if (hashDb != null) { if (hashDb != null) {
hashSetManager.removeHashDatabaseInternal(hashDb); hashSetManager.removeHashDatabaseInternal(hashDb);
hashSetTableModel.refreshModel(); hashSetTableModel.refreshModel();
@ -738,16 +736,16 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
private void hashSetTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_hashSetTableKeyPressed private void hashSetTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_hashSetTableKeyPressed
if (evt.getKeyCode() == KeyEvent.VK_DELETE) { if (evt.getKeyCode() == KeyEvent.VK_DELETE) {
HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); HashDb hashDb = ((HashSetTable) hashSetTable).getSelection();
if (hashDb != null) { if (hashDb != null) {
hashSetManager.removeHashDatabaseInternal(hashDb); hashSetManager.removeHashDatabaseInternal(hashDb);
hashSetTableModel.refreshModel(); hashSetTableModel.refreshModel();
} }
} }
}//GEN-LAST:event_hashSetTableKeyPressed }//GEN-LAST:event_hashSetTableKeyPressed
private void sendIngestMessagesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sendIngestMessagesCheckBoxActionPerformed private void sendIngestMessagesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sendIngestMessagesCheckBoxActionPerformed
HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); HashDb hashDb = ((HashSetTable) hashSetTable).getSelection();
if (hashDb != null) { if (hashDb != null) {
hashDb.setSendIngestMessages(sendIngestMessagesCheckBox.isSelected()); hashDb.setSendIngestMessages(sendIngestMessagesCheckBox.isSelected());
} }
@ -757,18 +755,17 @@ public final class HashDbConfigPanel extends IngestModuleGlobalSetttingsPanel {
HashDb hashDb = new HashDbImportDatabaseDialog().getHashDatabase(); HashDb hashDb = new HashDbImportDatabaseDialog().getHashDatabase();
if (null != hashDb) { if (null != hashDb) {
hashSetTableModel.refreshModel(); hashSetTableModel.refreshModel();
((HashSetTable)hashSetTable).selectRowByName(hashDb.getHashSetName()); ((HashSetTable) hashSetTable).selectRowByName(hashDb.getHashSetName());
} }
}//GEN-LAST:event_importDatabaseButtonActionPerformed }//GEN-LAST:event_importDatabaseButtonActionPerformed
private void createDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createDatabaseButtonActionPerformed private void createDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createDatabaseButtonActionPerformed
HashDb hashDb = new HashDbCreateDatabaseDialog().getHashDatabase(); HashDb hashDb = new HashDbCreateDatabaseDialog().getHashDatabase();
if (null != hashDb) { if (null != hashDb) {
hashSetTableModel.refreshModel(); hashSetTableModel.refreshModel();
((HashSetTable)hashSetTable).selectRowByName(hashDb.getHashSetName()); ((HashSetTable) hashSetTable).selectRowByName(hashDb.getHashSetName());
} }
}//GEN-LAST:event_createDatabaseButtonActionPerformed }//GEN-LAST:event_createDatabaseButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton createDatabaseButton; private javax.swing.JButton createDatabaseButton;
private javax.swing.JButton deleteDatabaseButton; private javax.swing.JButton deleteDatabaseButton;

View File

@ -63,7 +63,7 @@ public class HashDbIngestModule extends IngestModuleAdapter implements FileInges
} }
@Override @Override
public void startUp(org.sleuthkit.autopsy.ingest.IngestJobContext context) throws Exception { public void startUp(org.sleuthkit.autopsy.ingest.IngestJobContext context) throws IngestModuleException {
super.startUp(context); super.startUp(context);
services = IngestServices.getDefault(); services = IngestServices.getDefault();
skCase = Case.getCurrentCase().getSleuthkitCase(); skCase = Case.getCurrentCase().getSleuthkitCase();
@ -110,15 +110,15 @@ public class HashDbIngestModule extends IngestModuleAdapter implements FileInges
} }
@Override @Override
public ResultCode process(AbstractFile file) { public ProcessResult process(AbstractFile file) {
// Skip unallocated space files. // Skip unallocated space files.
if (file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) { if (file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) {
return ResultCode.OK; return ProcessResult.OK;
} }
// bail out if we have no hashes set // bail out if we have no hashes set
if ((knownHashSets.isEmpty()) && (knownBadHashSets.isEmpty()) && (calcHashesIsSet == false)) { if ((knownHashSets.isEmpty()) && (knownBadHashSets.isEmpty()) && (calcHashesIsSet == false)) {
return ResultCode.OK; return ProcessResult.OK;
} }
// calc hash value // calc hash value
@ -139,13 +139,13 @@ public class HashDbIngestModule extends IngestModuleAdapter implements FileInges
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.calcHashValueErr", "HashDbIngestModule.calcHashValueErr",
name))); name)));
return ResultCode.ERROR; return ProcessResult.ERROR;
} }
} }
// look up in known bad first // look up in known bad first
boolean foundBad = false; boolean foundBad = false;
ResultCode ret = ResultCode.OK; ProcessResult ret = ProcessResult.OK;
for (HashDb db : knownBadHashSets) { for (HashDb db : knownBadHashSets) {
try { try {
long lookupstart = System.currentTimeMillis(); long lookupstart = System.currentTimeMillis();
@ -165,7 +165,7 @@ public class HashDbIngestModule extends IngestModuleAdapter implements FileInges
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.settingKnownBadStateErr", "HashDbIngestModule.settingKnownBadStateErr",
name))); name)));
ret = ResultCode.ERROR; ret = ProcessResult.ERROR;
} }
String hashSetName = db.getHashSetName(); String hashSetName = db.getHashSetName();
@ -196,7 +196,7 @@ public class HashDbIngestModule extends IngestModuleAdapter implements FileInges
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.lookingUpKnownBadHashValueErr", "HashDbIngestModule.lookingUpKnownBadHashValueErr",
name))); name)));
ret = ResultCode.ERROR; ret = ProcessResult.ERROR;
} }
} }
@ -213,7 +213,7 @@ public class HashDbIngestModule extends IngestModuleAdapter implements FileInges
break; break;
} catch (TskException ex) { } catch (TskException ex) {
logger.log(Level.WARNING, "Couldn't set known state for file " + name + " - see sleuthkit log for details", ex); logger.log(Level.WARNING, "Couldn't set known state for file " + name + " - see sleuthkit log for details", ex);
ret = ResultCode.ERROR; ret = ProcessResult.ERROR;
} }
} }
lookuptime += (System.currentTimeMillis() - lookupstart); lookuptime += (System.currentTimeMillis() - lookupstart);
@ -227,7 +227,7 @@ public class HashDbIngestModule extends IngestModuleAdapter implements FileInges
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.lookingUpKnownHashValueErr", "HashDbIngestModule.lookingUpKnownHashValueErr",
name))); name)));
ret = ResultCode.ERROR; ret = ProcessResult.ERROR;
} }
} }
} }

View File

@ -33,12 +33,12 @@ import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings; import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleJobSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleSettingsPanel;
/** /**
* Instances of this class provide a simplified UI for managing the hash sets configuration. * Instances of this class provide a simplified UI for managing the hash sets configuration.
*/ */
public class HashDbSimpleConfigPanel extends IngestModuleJobSettingsPanel { public class HashDbSimpleConfigPanel extends IngestModuleSettingsPanel {
private HashDatabasesTableModel knownTableModel; private HashDatabasesTableModel knownTableModel;
private HashDatabasesTableModel knownBadTableModel; private HashDatabasesTableModel knownBadTableModel;
@ -76,7 +76,7 @@ public class HashDbSimpleConfigPanel extends IngestModuleJobSettingsPanel {
} }
@Override @Override
public IngestModuleSettings getIngestJobOptions() { public IngestModuleSettings getSettings() {
HashDbManager hashDbManager = HashDbManager.getInstance(); HashDbManager hashDbManager = HashDbManager.getInstance();
List<HashDbManager.HashDb> knownFileHashSets = hashDbManager.getKnownFileHashSets(); List<HashDbManager.HashDb> knownFileHashSets = hashDbManager.getKnownFileHashSets();
List<HashDbManager.HashDb> knownBadFileHashSets = hashDbManager.getKnownBadFileHashSets(); List<HashDbManager.HashDb> knownBadFileHashSets = hashDbManager.getKnownBadFileHashSets();

View File

@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory; import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings; import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleJobSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleSettingsPanel;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel;
/** /**
@ -64,7 +64,7 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter {
} }
@Override @Override
public IngestModuleJobSettingsPanel getModuleSettingsPanel(IngestModuleSettings ingestOptions) { public IngestModuleSettingsPanel getModuleSettingsPanel(IngestModuleSettings ingestOptions) {
HashDbSimpleConfigPanel ingestOptionsPanel = new HashDbSimpleConfigPanel(); HashDbSimpleConfigPanel ingestOptionsPanel = new HashDbSimpleConfigPanel();
ingestOptionsPanel.load(); ingestOptionsPanel.load();
return ingestOptionsPanel; return ingestOptionsPanel;

View File

@ -29,6 +29,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
// Note: This is a first step towards a keyword lists manager; it consists of // Note: This is a first step towards a keyword lists manager; it consists of
// the portion of the keyword list management code that resided in the keyword // the portion of the keyword list management code that resided in the keyword
// search file ingest module. // search file ingest module.
// RJCTODO: How to keyword lists get initialized
final class KeywordListsManager { final class KeywordListsManager {
private static KeywordListsManager instance = null; private static KeywordListsManager instance = null;
@ -47,6 +48,7 @@ final class KeywordListsManager {
} }
private KeywordListsManager() { private KeywordListsManager() {
addKeywordListsForFileIngest(null);
} }
/** /**
@ -56,7 +58,7 @@ final class KeywordListsManager {
* *
* @param listNames The names of disabled lists to temporarily enable * @param listNames The names of disabled lists to temporarily enable
*/ */
void addKeywordListsForFileIngest(List<String> listNames) { synchronized void addKeywordListsForFileIngest(List<String> listNames) {
keywords.clear(); keywords.clear();
keywordListNames.clear(); keywordListNames.clear();
@ -64,7 +66,7 @@ final class KeywordListsManager {
KeywordSearchListsXML globalKeywordSearchOptions = KeywordSearchListsXML.getCurrent(); KeywordSearchListsXML globalKeywordSearchOptions = KeywordSearchListsXML.getCurrent();
for (KeywordList list : globalKeywordSearchOptions.getListsL()) { for (KeywordList list : globalKeywordSearchOptions.getListsL()) {
String listName = list.getName(); String listName = list.getName();
if ((list.getUseForIngest() == true) || (null != listNames && listNames.contains(listName))) { if ((list.getUseForIngest() == true) || (listNames != null && listNames.contains(listName))) {
keywordListNames.add(listName); keywordListNames.add(listName);
logMessage.append(listName).append(" "); logMessage.append(listName).append(" ");
} }
@ -84,7 +86,7 @@ final class KeywordListsManager {
* *
* @return The names of the enabled keyword lists * @return The names of the enabled keyword lists
*/ */
List<String> getNamesOfKeywordListsForFileIngest() { synchronized List<String> getNamesOfKeywordListsForFileIngest() {
return new ArrayList<>(keywordListNames); return new ArrayList<>(keywordListNames);
} }
@ -94,7 +96,7 @@ final class KeywordListsManager {
* *
* @return True if there are no keywords specified, false otherwise * @return True if there are no keywords specified, false otherwise
*/ */
boolean hasNoKeywordsForSearch() { synchronized boolean hasNoKeywordsForSearch() {
return (keywords.isEmpty()); return (keywords.isEmpty());
} }
} }

View File

@ -19,13 +19,14 @@
package org.sleuthkit.autopsy.keywordsearch; package org.sleuthkit.autopsy.keywordsearch;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel;
/** /**
* Global options panel for keyword searching. * Global options panel for keyword searching.
*/ */
// RJCTODO: Why is this a public class? // RJCTODO: Why is this a public class?
public final class KeywordSearchConfigurationPanel extends IngestModuleGlobalSetttingsPanel { public final class KeywordSearchConfigurationPanel extends IngestModuleGlobalSetttingsPanel implements OptionsPanel {
private KeywordSearchConfigurationPanel1 listsPanel; private KeywordSearchConfigurationPanel1 listsPanel;
private KeywordSearchConfigurationPanel3 languagesPanel; private KeywordSearchConfigurationPanel3 languagesPanel;
@ -84,10 +85,15 @@ public final class KeywordSearchConfigurationPanel extends IngestModuleGlobalSet
} }
@Override @Override
public void store() { public void saveSettings() {
listsPanel.store(); listsPanel.store();
languagesPanel.store(); languagesPanel.store();
generalPanel.store(); generalPanel.store();
}
@Override
public void store() {
saveSettings();
} }
public void cancel() { public void cancel() {

View File

@ -16,7 +16,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.sleuthkit.autopsy.keywordsearch; package org.sleuthkit.autopsy.keywordsearch;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
@ -76,11 +75,13 @@ import org.sleuthkit.datamodel.TskData.FileKnown;
* on currently configured lists for ingest and writes results to blackboard * on currently configured lists for ingest and writes results to blackboard
* Reports interesting events to Inbox and to viewers * Reports interesting events to Inbox and to viewers
* *
* Registered as a module in layer.xml RJCTODO: Track this down, does not seem to be true * Registered as a module in layer.xml RJCTODO: Track this down, does not seem
* to be true
*/ */
public final class KeywordSearchIngestModule extends IngestModuleAdapter implements FileIngestModule { public final class KeywordSearchIngestModule extends IngestModuleAdapter implements FileIngestModule {
enum UpdateFrequency { enum UpdateFrequency {
FAST(20), FAST(20),
AVG(10), AVG(10),
SLOW(5), SLOW(5),
@ -96,9 +97,8 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
return time; return time;
} }
}; };
private static final Logger logger = Logger.getLogger(KeywordSearchIngestModule.class.getName()); private static final Logger logger = Logger.getLogger(KeywordSearchIngestModule.class.getName());
private IngestServices services; private IngestServices services = IngestServices.getDefault();
private Ingester ingester = null; private Ingester ingester = null;
private volatile boolean commitIndex = false; //whether to commit index next time private volatile boolean commitIndex = false; //whether to commit index next time
private volatile boolean runSearcher = false; //whether to run searcher next time private volatile boolean runSearcher = false; //whether to run searcher next time
@ -114,7 +114,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
private Set<Long> curDataSourceIds; private Set<Long> curDataSourceIds;
private static final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true); //use fairness policy private static final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true); //use fairness policy
private static final Lock searcherLock = rwLock.writeLock(); private static final Lock searcherLock = rwLock.writeLock();
private volatile int messageID = 0; private volatile int messageID = 0; // RJCTODO: Despite volatile, this is not thread safe, uses increment (not atomic)
private boolean processedFiles; private boolean processedFiles;
private volatile boolean finalSearcherDone = true; //mark as done, until it's inited private volatile boolean finalSearcherDone = true; //mark as done, until it's inited
private SleuthkitCase caseHandle = null; private SleuthkitCase caseHandle = null;
@ -122,11 +122,12 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
private static AbstractFileStringExtract stringExtractor; private static AbstractFileStringExtract stringExtractor;
private boolean initialized = false; private boolean initialized = false;
private Tika tikaFormatDetector; private Tika tikaFormatDetector;
private enum IngestStatus { private enum IngestStatus {
TEXT_INGESTED, /// Text was extracted by knowing file type and text_ingested
TEXT_INGESTED, /// Text was extracted by knowing file type and text_ingested
STRINGS_INGESTED, ///< Strings were extracted from file STRINGS_INGESTED, ///< Strings were extracted from file
METADATA_INGESTED, ///< No content, so we just text_ingested metadata METADATA_INGESTED, ///< No content, so we just text_ingested metadata
SKIPPED_ERROR_INDEXING, ///< File was skipped because index engine had problems SKIPPED_ERROR_INDEXING, ///< File was skipped because index engine had problems
SKIPPED_ERROR_TEXTEXTRACT, ///< File was skipped because of text extraction issues SKIPPED_ERROR_TEXTEXTRACT, ///< File was skipped because of text extraction issues
SKIPPED_ERROR_IO ///< File was skipped because of IO issues reading it SKIPPED_ERROR_IO ///< File was skipped because of IO issues reading it
@ -135,15 +136,106 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
KeywordSearchIngestModule() { KeywordSearchIngestModule() {
} }
/**
* Initializes the module for new ingest run Sets up threads, timers,
* retrieves settings, keyword lists to run on
*
*/
@Override @Override
public ResultCode process(AbstractFile abstractFile) { public void startUp(IngestJobContext context) throws IngestModuleException {
logger.log(Level.INFO, "init()");
initialized = false;
caseHandle = Case.getCurrentCase().getSleuthkitCase();
tikaFormatDetector = new Tika();
ingester = Server.getIngester();
final Server server = KeywordSearch.getServer();
try {
if (!server.isRunning()) {
String msg = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.badInitMsg");
logger.log(Level.SEVERE, msg);
String details = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.tryStopSolrMsg", msg);
services.postMessage(IngestMessage.createErrorMessage(++messageID, KeywordSearchModuleFactory.getModuleName(), msg, details));
throw new IngestModuleException(msg);
}
} catch (KeywordSearchModuleException ex) {
logger.log(Level.WARNING, "Error checking if Solr server is running while initializing ingest", ex);
//this means Solr is not properly initialized
String msg = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.badInitMsg");
String details = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.tryStopSolrMsg", msg);
services.postMessage(IngestMessage.createErrorMessage(++messageID, KeywordSearchModuleFactory.getModuleName(), msg, details));
throw new IngestModuleException(msg);
}
try {
// make an actual query to verify that server is responding
// we had cases where getStatus was OK, but the connection resulted in a 404
server.queryNumIndexedDocuments();
} catch (KeywordSearchModuleException | NoOpenCoreException ex) {
throw new IngestModuleException(
NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.exception.errConnToSolr.msg",
ex.getMessage()));
}
//initialize extractors
stringExtractor = new AbstractFileStringExtract(this);
stringExtractor.setScripts(KeywordSearchSettings.getStringExtractScripts());
stringExtractor.setOptions(KeywordSearchSettings.getStringExtractOptions());
//log the scripts used for debugging
final StringBuilder sbScripts = new StringBuilder();
for (SCRIPT s : KeywordSearchSettings.getStringExtractScripts()) {
sbScripts.append(s.name()).append(" ");
}
logger.log(Level.INFO, "Using string extract scripts: {0}", sbScripts.toString());
textExtractors = new ArrayList<>();
//order matters, more specific extractors first
textExtractors.add(new AbstractFileHtmlExtract(this));
textExtractors.add(new AbstractFileTikaTextExtract(this));
ingestStatus = new HashMap<>();
if (KeywordListsManager.getInstance().hasNoKeywordsForSearch()) {
services.postMessage(IngestMessage.createWarningMessage(++messageID, KeywordSearchModuleFactory.getModuleName(), NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.noKwInLstMsg"),
NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.onlyIdxKwSkipMsg")));
}
processedFiles = false;
finalSearcherDone = false;
searcherDone = true; //make sure to start the initial currentSearcher
//keeps track of all results per run not to repeat reporting the same hits
currentResults = new HashMap<>();
curDataSourceIds = new HashSet<>();
indexer = new Indexer();
final int updateIntervalMs = KeywordSearchSettings.getUpdateFrequency().getTime() * 60 * 1000;
logger.log(Level.INFO, "Using commit interval (ms): {0}", updateIntervalMs);
logger.log(Level.INFO, "Using searcher interval (ms): {0}", updateIntervalMs);
commitTimer = new Timer(updateIntervalMs, new CommitTimerAction());
searchTimer = new Timer(updateIntervalMs, new SearchTimerAction());
initialized = true;
commitTimer.start();
searchTimer.start();
}
@Override
public ProcessResult process(AbstractFile abstractFile) {
if (initialized == false) //error initializing indexing/Solr if (initialized == false) //error initializing indexing/Solr
{ {
logger.log(Level.WARNING, "Skipping processing, module not initialized, file: {0}", abstractFile.getName()); logger.log(Level.WARNING, "Skipping processing, module not initialized, file: {0}", abstractFile.getName());
ingestStatus.put(abstractFile.getId(), IngestStatus.SKIPPED_ERROR_INDEXING); ingestStatus.put(abstractFile.getId(), IngestStatus.SKIPPED_ERROR_INDEXING);
return ResultCode.OK; return ProcessResult.OK;
} }
try { try {
//add data source id of the file to the set, keeping track of images being ingested //add data source id of the file to the set, keeping track of images being ingested
@ -153,19 +245,19 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting image id of file processed by keyword search: " + abstractFile.getName(), ex); logger.log(Level.SEVERE, "Error getting image id of file processed by keyword search: " + abstractFile.getName(), ex);
} }
if (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR)) { if (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR)) {
//skip indexing of virtual dirs (no content, no real name) - will index children files //skip indexing of virtual dirs (no content, no real name) - will index children files
return ResultCode.OK; return ProcessResult.OK;
} }
if (KeywordSearchSettings.getSkipKnown() && abstractFile.getKnown().equals(FileKnown.KNOWN)) { if (KeywordSearchSettings.getSkipKnown() && abstractFile.getKnown().equals(FileKnown.KNOWN)) {
//index meta-data only //index meta-data only
indexer.indexFile(abstractFile, false); indexer.indexFile(abstractFile, false);
return ResultCode.OK; return ProcessResult.OK;
} }
processedFiles = true; processedFiles = true;
//check if it's time to commit after previous processing //check if it's time to commit after previous processing
checkRunCommitSearch(); checkRunCommitSearch();
@ -173,7 +265,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
//index the file and content (if the content is supported) //index the file and content (if the content is supported)
indexer.indexFile(abstractFile, true); indexer.indexFile(abstractFile, true);
return ResultCode.OK; return ProcessResult.OK;
} }
/** /**
@ -190,7 +282,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
stop(); stop();
return; return;
} }
commitTimer.stop(); commitTimer.stop();
//NOTE, we let the 1 before last searcher complete fully, and enqueue the last one //NOTE, we let the 1 before last searcher complete fully, and enqueue the last one
@ -209,7 +301,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
postIndexSummary(); postIndexSummary();
//run one last search as there are probably some new files committed //run one last search as there are probably some new files committed
List<String> keywordLists = KeywordListsManager.getInstance().getNamesOfKeywordListsForFileIngest(); List<String> keywordLists = KeywordListsManager.getInstance().getNamesOfKeywordListsForFileIngest();
if (!keywordLists.isEmpty() && processedFiles == true) { if (!keywordLists.isEmpty() && processedFiles == true) {
finalSearcher = new Searcher(keywordLists, true); //final searcher run finalSearcher = new Searcher(keywordLists, true); //final searcher run
finalSearcher.execute(); finalSearcher.execute();
@ -281,98 +373,6 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
initialized = false; initialized = false;
} }
/**
* Initializes the module for new ingest run Sets up threads, timers,
* retrieves settings, keyword lists to run on
*
*/
@Override
public void startUp(IngestJobContext context) throws Exception {
logger.log(Level.INFO, "init()");
services = IngestServices.getDefault();
initialized = false;
caseHandle = Case.getCurrentCase().getSleuthkitCase();
tikaFormatDetector = new Tika();
ingester = Server.getIngester();
final Server server = KeywordSearch.getServer();
try {
if (!server.isRunning()) {
String msg = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.badInitMsg");
logger.log(Level.SEVERE, msg);
String details = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.tryStopSolrMsg", msg);
services.postMessage(IngestMessage.createErrorMessage(++messageID, KeywordSearchModuleFactory.getModuleName(), msg, details));
throw new Exception(msg);
}
} catch (KeywordSearchModuleException ex) {
logger.log(Level.WARNING, "Error checking if Solr server is running while initializing ingest", ex);
//this means Solr is not properly initialized
String msg = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.badInitMsg");
String details = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.tryStopSolrMsg", msg);
services.postMessage(IngestMessage.createErrorMessage(++messageID, KeywordSearchModuleFactory.getModuleName(), msg, details));
throw new Exception(msg);
}
try {
// make an actual query to verify that server is responding
// we had cases where getStatus was OK, but the connection resulted in a 404
server.queryNumIndexedDocuments();
} catch (KeywordSearchModuleException | NoOpenCoreException ex) {
throw new Exception(
NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.exception.errConnToSolr.msg",
ex.getMessage()));
}
//initialize extractors
stringExtractor = new AbstractFileStringExtract(this);
stringExtractor.setScripts(KeywordSearchSettings.getStringExtractScripts());
stringExtractor.setOptions(KeywordSearchSettings.getStringExtractOptions());
//log the scripts used for debugging
final StringBuilder sbScripts = new StringBuilder();
for (SCRIPT s : KeywordSearchSettings.getStringExtractScripts()) {
sbScripts.append(s.name()).append(" ");
}
logger.log(Level.INFO, "Using string extract scripts: {0}", sbScripts.toString());
textExtractors = new ArrayList<>();
//order matters, more specific extractors first
textExtractors.add(new AbstractFileHtmlExtract(this));
textExtractors.add(new AbstractFileTikaTextExtract(this));
ingestStatus = new HashMap<>();
// RJCTODO: Fetch lists for job and check?
// if (keywords.isEmpty() || keywordLists.isEmpty()) {
// services.postMessage(IngestMessage.createWarningMessage(++messageID, this, NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.noKwInLstMsg"),
// NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.init.onlyIdxKwSkipMsg")));
// }
processedFiles = false;
finalSearcherDone = false;
searcherDone = true; //make sure to start the initial currentSearcher
//keeps track of all results per run not to repeat reporting the same hits
currentResults = new HashMap<>();
curDataSourceIds = new HashSet<>();
indexer = new Indexer();
final int updateIntervalMs = KeywordSearchSettings.getUpdateFrequency().getTime() * 60 * 1000;
logger.log(Level.INFO, "Using commit interval (ms): {0}", updateIntervalMs);
logger.log(Level.INFO, "Using searcher interval (ms): {0}", updateIntervalMs);
commitTimer = new Timer(updateIntervalMs, new CommitTimerAction());
searchTimer = new Timer(updateIntervalMs, new SearchTimerAction());
initialized = true;
commitTimer.start();
searchTimer.start();
}
/** /**
* Commits index and notifies listeners of index update * Commits index and notifies listeners of index update
*/ */
@ -435,8 +435,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
if (error_index > 0) { if (error_index > 0) {
MessageNotifyUtil.Notify.error(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.postIndexSummary.kwIdxErrsTitle"), MessageNotifyUtil.Notify.error(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.postIndexSummary.kwIdxErrsTitle"),
NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.postIndexSummary.kwIdxErrMsgFiles", error_index)); NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.postIndexSummary.kwIdxErrMsgFiles", error_index));
} } else if (error_io + error_text > 0) {
else if (error_io + error_text > 0) {
MessageNotifyUtil.Notify.warn(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.postIndexSummary.kwIdxWarnMsgTitle"), MessageNotifyUtil.Notify.warn(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.postIndexSummary.kwIdxWarnMsgTitle"),
NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.postIndexSummary.idxErrReadFilesMsg")); NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.postIndexSummary.idxErrReadFilesMsg"));
} }
@ -597,14 +596,14 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
* Adds the file to the index. Detects file type, calls extractors, etc. * Adds the file to the index. Detects file type, calls extractors, etc.
* *
* @param aFile File to analyze * @param aFile File to analyze
* @param indexContent False if only metadata should be text_ingested. True if * @param indexContent False if only metadata should be text_ingested.
* content and metadata should be index. * True if content and metadata should be index.
*/ */
private void indexFile(AbstractFile aFile, boolean indexContent) { private void indexFile(AbstractFile aFile, boolean indexContent) {
//logger.log(Level.INFO, "Processing AbstractFile: " + abstractFile.getName()); //logger.log(Level.INFO, "Processing AbstractFile: " + abstractFile.getName());
TskData.TSK_DB_FILES_TYPE_ENUM aType = aFile.getType(); TskData.TSK_DB_FILES_TYPE_ENUM aType = aFile.getType();
// unallocated and unused blocks can only have strings extracted from them. // unallocated and unused blocks can only have strings extracted from them.
if ((aType.equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) || aType.equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS))) { if ((aType.equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) || aType.equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS))) {
extractStringsAndIndex(aFile); extractStringsAndIndex(aFile);
@ -616,8 +615,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
try { try {
ingester.ingest(aFile, false); //meta-data only ingester.ingest(aFile, false); //meta-data only
ingestStatus.put(aFile.getId(), IngestStatus.METADATA_INGESTED); ingestStatus.put(aFile.getId(), IngestStatus.METADATA_INGESTED);
} } catch (IngesterException ex) {
catch (IngesterException ex) {
ingestStatus.put(aFile.getId(), IngestStatus.SKIPPED_ERROR_INDEXING); ingestStatus.put(aFile.getId(), IngestStatus.SKIPPED_ERROR_INDEXING);
logger.log(Level.WARNING, "Unable to index meta-data for file: " + aFile.getId(), ex); logger.log(Level.WARNING, "Unable to index meta-data for file: " + aFile.getId(), ex);
} }
@ -630,11 +628,9 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
try { try {
is = new ReadContentInputStream(aFile); is = new ReadContentInputStream(aFile);
detectedFormat = tikaFormatDetector.detect(is, aFile.getName()); detectedFormat = tikaFormatDetector.detect(is, aFile.getName());
} } catch (Exception e) {
catch (Exception e) {
logger.log(Level.WARNING, "Could not detect format using tika for file: " + aFile, e); logger.log(Level.WARNING, "Could not detect format using tika for file: " + aFile, e);
} } finally {
finally {
if (is != null) { if (is != null) {
try { try {
is.close(); is.close();
@ -644,9 +640,9 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
} }
} }
} }
// @@@ Add file type signature to blackboard here // @@@ Add file type signature to blackboard here
//logger.log(Level.INFO, "Detected format: " + aFile.getName() + " " + detectedFormat); //logger.log(Level.INFO, "Detected format: " + aFile.getName() + " " + detectedFormat);
// we skip archive formats that are opened by the archive module. // we skip archive formats that are opened by the archive module.
@ -655,8 +651,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
try { try {
ingester.ingest(aFile, false); //meta-data only ingester.ingest(aFile, false); //meta-data only
ingestStatus.put(aFile.getId(), IngestStatus.METADATA_INGESTED); ingestStatus.put(aFile.getId(), IngestStatus.METADATA_INGESTED);
} } catch (IngesterException ex) {
catch (IngesterException ex) {
ingestStatus.put(aFile.getId(), IngestStatus.SKIPPED_ERROR_INDEXING); ingestStatus.put(aFile.getId(), IngestStatus.SKIPPED_ERROR_INDEXING);
logger.log(Level.WARNING, "Unable to index meta-data for file: " + aFile.getId(), ex); logger.log(Level.WARNING, "Unable to index meta-data for file: " + aFile.getId(), ex);
} }
@ -732,15 +727,15 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
logger.log(Level.INFO, "Pending start of new searcher"); logger.log(Level.INFO, "Pending start of new searcher");
} }
final String displayName = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.doInBackGround.displayName") + final String displayName = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.doInBackGround.displayName")
(finalRun ? (" - "+ NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.doInBackGround.finalizeMsg")) : ""); + (finalRun ? (" - " + NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.doInBackGround.finalizeMsg")) : "");
progressGroup = AggregateProgressFactory.createSystemHandle(displayName + (" ("+ progressGroup = AggregateProgressFactory.createSystemHandle(displayName + (" ("
NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.doInBackGround.pendingMsg") +")"), null, new Cancellable() { + NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.doInBackGround.pendingMsg") + ")"), null, new Cancellable() {
@Override @Override
public boolean cancel() { public boolean cancel() {
logger.log(Level.INFO, "Cancelling the searcher by user."); logger.log(Level.INFO, "Cancelling the searcher by user.");
if (progressGroup != null) { if (progressGroup != null) {
progressGroup.setDisplayName(displayName + " ("+ NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.doInBackGround.cancelMsg") +"...)"); progressGroup.setDisplayName(displayName + " (" + NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.doInBackGround.cancelMsg") + "...)");
} }
return Searcher.this.cancel(true); return Searcher.this.cancel(true);
} }
@ -800,10 +795,9 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
boolean isRegex = !keywordQuery.isLiteral(); boolean isRegex = !keywordQuery.isLiteral();
if (isRegex) { if (isRegex) {
del = new TermComponentQuery(keywordQuery); del = new TermComponentQuery(keywordQuery);
} } else {
else {
del = new LuceneQuery(keywordQuery); del = new LuceneQuery(keywordQuery);
del.escape(); del.escape();
} }
//limit search to currently ingested data sources //limit search to currently ingested data sources
@ -858,7 +852,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
logger.log(Level.INFO, "Cancel detected, bailing before new hit processed for query: {0}", keywordQuery.getQuery()); logger.log(Level.INFO, "Cancel detected, bailing before new hit processed for query: {0}", keywordQuery.getQuery());
return null; return null;
} }
// update progress display // update progress display
String hitDisplayStr = hitTerm.getQuery(); String hitDisplayStr = hitTerm.getQuery();
if (hitDisplayStr.length() > 50) { if (hitDisplayStr.length() > 50) {
@ -870,7 +864,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
// this returns the unique files in the set with the first chunk that has a hit // this returns the unique files in the set with the first chunk that has a hit
Map<AbstractFile, Integer> contentHitsFlattened = ContentHit.flattenResults(newResults.get(hitTerm)); Map<AbstractFile, Integer> contentHitsFlattened = ContentHit.flattenResults(newResults.get(hitTerm));
for (final AbstractFile hitFile : contentHitsFlattened.keySet()) { for (final AbstractFile hitFile : contentHitsFlattened.keySet()) {
// get the snippet for the first hit in the file // get the snippet for the first hit in the file
String snippet; String snippet;
final String snippetQuery = KeywordSearchUtil.escapeLuceneQuery(hitTerm.getQuery()); final String snippetQuery = KeywordSearchUtil.escapeLuceneQuery(hitTerm.getQuery());
@ -963,7 +957,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
} }
} }
detailsSb.append("</table>"); detailsSb.append("</table>");
services.postMessage(IngestMessage.createDataMessage(++messageID, KeywordSearchModuleFactory.getModuleName(), subjectSb.toString(), detailsSb.toString(), uniqueKey, written.getArtifact())); services.postMessage(IngestMessage.createDataMessage(++messageID, KeywordSearchModuleFactory.getModuleName(), subjectSb.toString(), detailsSb.toString(), uniqueKey, written.getArtifact()));
} }
} //for each file hit } //for each file hit
@ -1000,14 +994,13 @@ public final class KeywordSearchIngestModule extends IngestModuleAdapter impleme
return null; return null;
} }
@Override @Override
protected void done() { protected void done() {
// call get to see if there were any errors // call get to see if there were any errors
try { try {
get(); get();
} } catch (InterruptedException | ExecutionException e) {
catch (InterruptedException | ExecutionException e) {
logger.log(Level.SEVERE, "Error performing keyword search: " + e.getMessage()); logger.log(Level.SEVERE, "Error performing keyword search: " + e.getMessage());
services.postMessage(IngestMessage.createErrorMessage(++messageID, KeywordSearchModuleFactory.getModuleName(), "Error performing keyword search", e.getMessage())); services.postMessage(IngestMessage.createErrorMessage(++messageID, KeywordSearchModuleFactory.getModuleName(), "Error performing keyword search", e.getMessage()));
} }

View File

@ -28,13 +28,13 @@ import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn; import javax.swing.table.TableColumn;
import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT; import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings; import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleJobSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleSettingsPanel;
import org.sleuthkit.autopsy.ingest.NoIngestModuleSettings; import org.sleuthkit.autopsy.ingest.NoIngestModuleSettings;
/** /**
* Ingest job options panel for the keyword search file ingest module. * Ingest job options panel for the keyword search file ingest module.
*/ */
public class KeywordSearchIngestSimplePanel extends IngestModuleJobSettingsPanel { public class KeywordSearchIngestSimplePanel extends IngestModuleSettingsPanel {
private final static Logger logger = Logger.getLogger(KeywordSearchIngestSimplePanel.class.getName()); private final static Logger logger = Logger.getLogger(KeywordSearchIngestSimplePanel.class.getName());
public static final String PROP_OPTIONS = "Keyword Search_Options"; public static final String PROP_OPTIONS = "Keyword Search_Options";
@ -72,7 +72,7 @@ public class KeywordSearchIngestSimplePanel extends IngestModuleJobSettingsPanel
} }
@Override @Override
public IngestModuleSettings getIngestJobOptions() { public IngestModuleSettings getSettings() {
return new NoIngestModuleSettings(); return new NoIngestModuleSettings();
} }

View File

@ -26,7 +26,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory; import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings; import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleJobSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleSettingsPanel;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel;
/** /**
@ -60,7 +60,7 @@ public class KeywordSearchModuleFactory extends IngestModuleFactoryAdapter {
} }
@Override @Override
public IngestModuleJobSettingsPanel getModuleSettingsPanel(IngestModuleSettings ingestJobOptions) { public IngestModuleSettingsPanel getModuleSettingsPanel(IngestModuleSettings ingestJobOptions) {
KeywordSearchIngestSimplePanel ingestOptionsPanel = new KeywordSearchIngestSimplePanel(); KeywordSearchIngestSimplePanel ingestOptionsPanel = new KeywordSearchIngestSimplePanel();
ingestOptionsPanel.load(); ingestOptionsPanel.load();
return ingestOptionsPanel; return ingestOptionsPanel;

View File

@ -33,6 +33,7 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleStatusHelper; import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleStatusHelper;
import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException;
import org.sleuthkit.datamodel.*; import org.sleuthkit.datamodel.*;
abstract class Extract { abstract class Extract {
@ -47,7 +48,7 @@ abstract class Extract {
Extract() { Extract() {
} }
void init() throws Exception { void init() throws IngestModuleException {
} }
abstract void process(Content dataSource, DataSourceIngestModuleStatusHelper controller); abstract void process(Content dataSource, DataSourceIngestModuleStatusHelper controller);

View File

@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestMessage; import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType; import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.autopsy.ingest.IngestModule.ResultCode; import org.sleuthkit.autopsy.ingest.IngestModule.ProcessResult;
import org.sleuthkit.autopsy.ingest.IngestModuleAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleAdapter;
import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestJobContext;
@ -48,7 +48,7 @@ public final class RAImageIngestModule extends IngestModuleAdapter implements Da
private static int messageId = 0; private static int messageId = 0;
private final List<Extract> extracters = new ArrayList<>(); private final List<Extract> extracters = new ArrayList<>();
private final List<Extract> browserExtracters = new ArrayList<>(); private final List<Extract> browserExtracters = new ArrayList<>();
private IngestServices services; private IngestServices services = IngestServices.getDefault();
private StringBuilder subCompleted = new StringBuilder(); private StringBuilder subCompleted = new StringBuilder();
RAImageIngestModule() { RAImageIngestModule() {
@ -57,9 +57,34 @@ public final class RAImageIngestModule extends IngestModuleAdapter implements Da
synchronized int getNextMessageId() { synchronized int getNextMessageId() {
return ++messageId; return ++messageId;
} }
@Override
public void startUp(IngestJobContext context) throws IngestModuleException {
Extract registry = new ExtractRegistry();
Extract iexplore = new ExtractIE();
Extract recentDocuments = new RecentDocumentsByLnk();
Extract chrome = new Chrome();
Extract firefox = new Firefox();
Extract SEUQA = new SearchEngineURLQueryAnalyzer();
extracters.add(chrome);
extracters.add(firefox);
extracters.add(iexplore);
extracters.add(recentDocuments);
extracters.add(SEUQA); // this needs to run after the web browser modules
extracters.add(registry); // this runs last because it is slowest
browserExtracters.add(chrome);
browserExtracters.add(firefox);
browserExtracters.add(iexplore);
for (Extract extracter : extracters) {
extracter.init();
}
}
@Override @Override
public ResultCode process(Content dataSource, DataSourceIngestModuleStatusHelper controller) { public ProcessResult process(Content dataSource, DataSourceIngestModuleStatusHelper controller) {
services.postMessage(IngestMessage.createMessage(getNextMessageId(), MessageType.INFO, RecentActivityExtracterModuleFactory.getModuleName(), "Started " + dataSource.getName())); services.postMessage(IngestMessage.createMessage(getNextMessageId(), MessageType.INFO, RecentActivityExtracterModuleFactory.getModuleName(), "Started " + dataSource.getName()));
controller.switchToDeterminate(extracters.size()); controller.switchToDeterminate(extracters.size());
@ -134,7 +159,7 @@ public final class RAImageIngestModule extends IngestModuleAdapter implements Da
historyMsg.toString()); historyMsg.toString());
services.postMessage(inboxMsg); services.postMessage(inboxMsg);
return ResultCode.OK; return ProcessResult.OK;
} }
@Override @Override
@ -156,33 +181,6 @@ public final class RAImageIngestModule extends IngestModuleAdapter implements Da
} }
} }
@Override
public void startUp(IngestJobContext context) throws Exception {
services = IngestServices.getDefault();
Extract registry = new ExtractRegistry();
Extract iexplore = new ExtractIE();
Extract recentDocuments = new RecentDocumentsByLnk();
Extract chrome = new Chrome();
Extract firefox = new Firefox();
Extract SEUQA = new SearchEngineURLQueryAnalyzer();
extracters.add(chrome);
extracters.add(firefox);
extracters.add(iexplore);
extracters.add(recentDocuments);
extracters.add(SEUQA); // this needs to run after the web browser modules
extracters.add(registry); // this runs last because it is slowest
browserExtracters.add(chrome);
browserExtracters.add(firefox);
browserExtracters.add(iexplore);
for (Extract extracter : extracters) {
extracter.init();
}
}
private void stop() { private void stop() {
for (Extract extracter : extracters) { for (Extract extracter : extracters) {
try { try {

View File

@ -18,6 +18,7 @@
*/ */
package org.sleuthkit.autopsy.recentactivity; package org.sleuthkit.autopsy.recentactivity;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule; import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
@ -26,25 +27,24 @@ import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings; import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
/** /**
* A factory that creates data source ingest modules that extract recent activity artifacts. * A factory that creates data source ingest modules that extract recent
* activity artifacts from data sources.
*/ */
@ServiceProvider(service = IngestModuleFactory.class) @ServiceProvider(service = IngestModuleFactory.class)
public class RecentActivityExtracterModuleFactory extends IngestModuleFactoryAdapter { public class RecentActivityExtracterModuleFactory extends IngestModuleFactoryAdapter {
public final static String MODULE_NAME = "Recent Activity";
public final static String MODULE_DESCRIPTION = "Extracts recent user activity, such as Web browsing, recently used documents and installed programs."; static String getModuleName() {
return NbBundle.getMessage(RAImageIngestModule.class, "RAImageIngestModule.getName");
}
@Override @Override
public String getModuleDisplayName() { public String getModuleDisplayName() {
return getModuleName(); return getModuleName();
} }
static String getModuleName() {
return MODULE_NAME;
}
@Override @Override
public String getModuleDescription() { public String getModuleDescription() {
return MODULE_DESCRIPTION; return NbBundle.getMessage(RAImageIngestModule.class, "RAImageIngestModule.getDesc");
} }
@Override @Override
@ -62,4 +62,3 @@ public class RecentActivityExtracterModuleFactory extends IngestModuleFactoryAda
return new RAImageIngestModule(); return new RAImageIngestModule();
} }
} }

View File

@ -36,6 +36,7 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.XMLUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleStatusHelper; import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleStatusHelper;
import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException;
import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
@ -315,16 +316,18 @@ class SearchEngineURLQueryAnalyzer extends Extract {
@Override @Override
public void process(Content dataSource, DataSourceIngestModuleStatusHelper controller) { public void process(Content dataSource, DataSourceIngestModuleStatusHelper controller) {
this.getURLs(dataSource, controller); this.getURLs(dataSource, controller);
logger.info("Search Engine stats: \n" + getTotals()); logger.log(Level.INFO, "Search Engine stats: \n{0}", getTotals());
} }
@Override @Override
void init() throws Exception { void init() throws IngestModuleException {
try { try {
PlatformUtil.extractResourceToUserConfigDir(SearchEngineURLQueryAnalyzer.class, XMLFILE); PlatformUtil.extractResourceToUserConfigDir(SearchEngineURLQueryAnalyzer.class, XMLFILE);
init2(); init2();
} catch (IOException e) { } catch (IOException e) {
logger.log(Level.SEVERE, "Unable to find " + XMLFILE, e); String message = "Unable to find " + XMLFILE;
logger.log(Level.SEVERE, message, e);
throw new IngestModuleException(message);
} }
} }

View File

@ -23,7 +23,6 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil;
@ -50,7 +49,7 @@ import org.sleuthkit.datamodel.Volume;
* Scalpel carving ingest module * Scalpel carving ingest module
*/ */
class ScalpelCarverIngestModule extends IngestModuleAdapter implements FileIngestModule { class ScalpelCarverIngestModule extends IngestModuleAdapter implements FileIngestModule {
private static final Logger logger = Logger.getLogger(ScalpelCarverIngestModule.class.getName()); private static final Logger logger = Logger.getLogger(ScalpelCarverIngestModule.class.getName());
private final String MODULE_OUTPUT_DIR_NAME = "ScalpelCarver"; private final String MODULE_OUTPUT_DIR_NAME = "ScalpelCarver";
private String moduleOutputDirPath; private String moduleOutputDirPath;
@ -58,35 +57,83 @@ class ScalpelCarverIngestModule extends IngestModuleAdapter implements FileInges
private String configFilePath; private String configFilePath;
private boolean initialized = false; private boolean initialized = false;
private ScalpelCarver carver; private ScalpelCarver carver;
private IngestJobContext context; private IngestJobContext context;
ScalpelCarverIngestModule() { ScalpelCarverIngestModule() {
} }
@Override @Override
public ResultCode process(AbstractFile abstractFile) { public void startUp(IngestJobContext context) throws IngestModuleException {
ScalpelCarver.init(); this.context = context;
// make sure this is Windows
String os = System.getProperty("os.name");
if (!os.startsWith("Windows")) {
String message = "Scalpel carving module is not compatible with non-Windows OS's at this time.";
logger.log(Level.SEVERE, message);
throw new IngestModuleException(message);
}
carver = new ScalpelCarver();
if (!carver.isInitialized()) {
String message = "Error initializing scalpel carver.";
logger.log(Level.SEVERE, message);
throw new IngestModuleException(message); // RJCTODO: Needs additional internationalization
}
// make sure module output directory exists; create it if it doesn't
moduleOutputDirPath = Case.getCurrentCase().getModulesOutputDirAbsPath()
+ File.separator + MODULE_OUTPUT_DIR_NAME;
File moduleOutputDir = new File(moduleOutputDirPath);
if (!moduleOutputDir.exists()) {
if (!moduleOutputDir.mkdir()) {
String message = "Could not create the output directory for the Scalpel module.";
logger.log(Level.SEVERE, message);
throw new IngestModuleException(message);
}
}
// create path to scalpel config file in user's home directory
configFilePath = PlatformUtil.getUserConfigDirectory()
+ File.separator + configFileName;
// copy the default config file to the user's home directory if one
// is not already there
try {
PlatformUtil.extractResourceToUserConfigDir(this.getClass(), configFileName);
} catch (IOException ex) {
String message = "Could not obtain the path to the Scalpel configuration file.";
logger.log(Level.SEVERE, message, ex);
throw new IngestModuleException(message);
}
initialized = true;
}
@Override
public ProcessResult process(AbstractFile abstractFile) {
ScalpelCarver.init(); // RJCTODO: Is this SclapelCarver class thread-safe?
if (!initialized) { if (!initialized) {
return ResultCode.OK; return ProcessResult.OK;
} }
// only process files whose type is TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS // only process files whose type is TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS
TSK_DB_FILES_TYPE_ENUM type = abstractFile.getType(); TSK_DB_FILES_TYPE_ENUM type = abstractFile.getType();
if (type != TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) { if (type != TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
return ResultCode.OK; return ProcessResult.OK;
} }
// create the output directory for this run // create the output directory for this run
String scalpelOutputDirPath = moduleOutputDirPath + File.separator + abstractFile.getId(); String scalpelOutputDirPath = moduleOutputDirPath + File.separator + abstractFile.getId();
File scalpelOutputDir = new File(scalpelOutputDirPath); File scalpelOutputDir = new File(scalpelOutputDirPath);
if (!scalpelOutputDir.exists()) { if (!scalpelOutputDir.exists()) {
if (!scalpelOutputDir.mkdir()) { if (!scalpelOutputDir.mkdir()) {
logger.log(Level.SEVERE, "Could not create Scalpel output directory: " + scalpelOutputDirPath); logger.log(Level.SEVERE, "Could not create Scalpel output directory: {0}", scalpelOutputDirPath);
return ResultCode.OK; return ProcessResult.OK;
} }
} }
// find the ID of the parent FileSystem, Volume or Image // find the ID of the parent FileSystem, Volume or Image
long id = -1; long id = -1;
Content parent = null; Content parent = null;
@ -96,9 +143,9 @@ class ScalpelCarverIngestModule extends IngestModuleAdapter implements FileInges
logger.log(Level.SEVERE, "Exception while trying to get parent of AbstractFile.", ex); logger.log(Level.SEVERE, "Exception while trying to get parent of AbstractFile.", ex);
} }
while (parent != null) { while (parent != null) {
if (parent instanceof FileSystem || if (parent instanceof FileSystem
parent instanceof Volume || || parent instanceof Volume
parent instanceof Image) { || parent instanceof Image) {
id = parent.getId(); id = parent.getId();
break; break;
} }
@ -108,53 +155,43 @@ class ScalpelCarverIngestModule extends IngestModuleAdapter implements FileInges
logger.log(Level.SEVERE, "Exception while trying to get parent of Content object.", ex); logger.log(Level.SEVERE, "Exception while trying to get parent of Content object.", ex);
} }
} }
// make sure we have a valid systemID // make sure we have a valid systemID
if (id == -1) { if (id == -1) {
logger.log(Level.SEVERE, "Could not get an ID for a FileSystem, Volume or Image for the given AbstractFile."); logger.log(Level.SEVERE, "Could not get an ID for a FileSystem, Volume or Image for the given AbstractFile.");
return ResultCode.OK; return ProcessResult.OK;
} }
// carve the AbstractFile // carve the AbstractFile
List<CarvedFileMeta> output = null; List<CarvedFileMeta> output = null;
try { try {
output = carver.carve(abstractFile, configFilePath, scalpelOutputDirPath); output = carver.carve(abstractFile, configFilePath, scalpelOutputDirPath);
} catch (ScalpelException ex) { } catch (ScalpelException ex) {
logger.log(Level.SEVERE, "Error when attempting to carved data from AbstractFile with ID " + abstractFile.getId()); logger.log(Level.SEVERE, "Error when attempting to carved data from AbstractFile with ID {0}", abstractFile.getId());
return ResultCode.OK; return ProcessResult.OK;
} }
// get the image's size
long imageSize = Long.MAX_VALUE;
try {
imageSize = abstractFile.getImage().getSize();
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Could not obtain the image's size.");
}
// add a carved file to the DB for each file that scalpel carved // add a carved file to the DB for each file that scalpel carved
SleuthkitCase db = Case.getCurrentCase().getSleuthkitCase(); SleuthkitCase db = Case.getCurrentCase().getSleuthkitCase();
List<LayoutFile> carvedFiles = new ArrayList<LayoutFile>(output.size()); List<LayoutFile> carvedFiles = new ArrayList<LayoutFile>(output.size());
for (CarvedFileMeta carvedFileMeta : output) { for (CarvedFileMeta carvedFileMeta : output) {
// calculate the byte offset of this carved file // calculate the byte offset of this carved file
long byteOffset; long byteOffset;
try { try {
byteOffset = abstractFile.convertToImgOffset(carvedFileMeta.getByteStart()); byteOffset = abstractFile.convertToImgOffset(carvedFileMeta.getByteStart());
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Could not calculate the image byte offset of AbstractFile (" + abstractFile.getName() + ")"); logger.log(Level.SEVERE, "Could not calculate the image byte offset of AbstractFile ({0})", abstractFile.getName());
break; break;
} }
// get the size of the carved file // get the size of the carved file
long size = carvedFileMeta.getByteLength(); long size = carvedFileMeta.getByteLength();
// create the list of TskFileRange objects // create the list of TskFileRange objects
List<TskFileRange> data = new ArrayList<TskFileRange>(); List<TskFileRange> data = new ArrayList<TskFileRange>();
data.add(new TskFileRange(byteOffset, size, 0)); data.add(new TskFileRange(byteOffset, size, 0));
// add the carved file // add the carved file
try { try {
carvedFiles.add(db.addCarvedFile(carvedFileMeta.getFileName(), size, id, data)); carvedFiles.add(db.addCarvedFile(carvedFileMeta.getFileName(), size, id, data));
@ -162,7 +199,7 @@ class ScalpelCarverIngestModule extends IngestModuleAdapter implements FileInges
logger.log(Level.SEVERE, "There was a problem while trying to add a carved file to the database.", ex); logger.log(Level.SEVERE, "There was a problem while trying to add a carved file to the database.", ex);
} }
} }
// get the IngestServices object // get the IngestServices object
IngestServices is = IngestServices.getDefault(); IngestServices is = IngestServices.getDefault();
@ -182,55 +219,10 @@ class ScalpelCarverIngestModule extends IngestModuleAdapter implements FileInges
} else { } else {
logger.log(Level.SEVERE, "Could not obtain the carved files directory."); logger.log(Level.SEVERE, "Could not obtain the carved files directory.");
} }
// reschedule carved files
context.submitFilesForIngest(new ArrayList<AbstractFile>(carvedFiles));
return ResultCode.OK;
}
@Override
public void startUp(IngestJobContext context) throws Exception {
this.context = context;
// make sure this is Windows
String os = System.getProperty("os.name");
if (!os.startsWith("Windows")) {
logger.log(Level.WARNING, "Scalpel carving module is not compatible with non-Windows OS's at this time.");
return;
}
carver = new ScalpelCarver(); // reschedule carved files
if (! carver.isInitialized()) { context.addFilesToPipeline(new ArrayList<AbstractFile>(carvedFiles));
logger.log(Level.SEVERE, "Error initializing scalpel carver. ");
return; return ProcessResult.OK;
}
// make sure module output directory exists; create it if it doesn't
moduleOutputDirPath = Case.getCurrentCase().getModulesOutputDirAbsPath() +
File.separator + MODULE_OUTPUT_DIR_NAME;
File moduleOutputDir = new File(moduleOutputDirPath);
if (!moduleOutputDir.exists()) {
if (!moduleOutputDir.mkdir()) {
logger.log(Level.SEVERE, "Could not create the output directory for the Scalpel module.");
return;
}
}
// create path to scalpel config file in user's home directory
configFilePath = PlatformUtil.getUserConfigDirectory()
+ File.separator + configFileName;
// copy the default config file to the user's home directory if one
// is not already there
try {
PlatformUtil.extractResourceToUserConfigDir(this.getClass(), configFileName);
} catch (IOException ex) {
logger.log(Level.SEVERE, "Could not obtain the path to the Scalpel configuration file.", ex);
return;
}
initialized = true;
} }
} }

View File

@ -18,7 +18,8 @@
*/ */
package org.sleuthkit.autopsy.scalpel; package org.sleuthkit.autopsy.scalpel;
// TODO: Uncomment the following line to allow the ingest framework to use this module // TODO: Uncomment the following line to allow the ingest framework to use this
// module. The dependency has already been added to the project.
//import org.openide.util.lookup.ServiceProvider; //import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;

View File

@ -56,27 +56,29 @@ import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.autopsy.ingest.IngestModule.ResultCode; import org.sleuthkit.autopsy.ingest.IngestModule.ProcessResult;
import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
/** /**
* 7Zip ingest module Extracts supported archives, adds extracted DerivedFiles, * 7Zip ingest module extracts supported archives, adds extracted DerivedFiles,
* reschedules extracted DerivedFiles for ingest. * reschedules extracted DerivedFiles for ingest.
*/ */
public final class SevenZipIngestModule extends IngestModuleAdapter implements FileIngestModule { public final class SevenZipIngestModule extends IngestModuleAdapter implements FileIngestModule {
private static final Logger logger = Logger.getLogger(SevenZipIngestModule.class.getName()); private static final Logger logger = Logger.getLogger(SevenZipIngestModule.class.getName());
private IngestServices services; private IngestServices services = IngestServices.getDefault();
private volatile int messageID = 0; private volatile int messageID = 0; // RJCTODO: This is not actually thread safe
static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // "iso"}; static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // "iso"};
private String unpackDir; //relative to the case, to store in db private String unpackDir; //relative to the case, to store in db
private String unpackDirPath; //absolute, to extract to private String unpackDirPath; //absolute, to extract to
private FileManager fileManager; private FileManager fileManager;
//encryption type strings //encryption type strings
private static final String ENCRYPTION_FILE_LEVEL = NbBundle.getMessage(SevenZipIngestModule.class, private static final String ENCRYPTION_FILE_LEVEL = NbBundle.getMessage(SevenZipIngestModule.class,
"SevenZipIngestModule.encryptionFileLevel"); "SevenZipIngestModule.encryptionFileLevel");
private static final String ENCRYPTION_FULL = NbBundle.getMessage(SevenZipIngestModule.class, private static final String ENCRYPTION_FULL = NbBundle.getMessage(SevenZipIngestModule.class,
"SevenZipIngestModule.encryptionFull"); "SevenZipIngestModule.encryptionFull");
//zip bomb detection //zip bomb detection
private static final int MAX_DEPTH = 4; private static final int MAX_DEPTH = 4;
private static final int MAX_COMPRESSION_RATIO = 600; private static final int MAX_COMPRESSION_RATIO = 600;
@ -94,11 +96,15 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
} }
@Override @Override
public void startUp(IngestJobContext context) throws Exception{ public void startUp(IngestJobContext context) throws IngestModuleException {
this.context = context; this.context = context;
unpackDir = context.getOutputDirectoryRelativePath();
unpackDirPath = context.getOutputDirectoryAbsolutePath(); final Case currentCase = Case.getCurrentCase();
fileManager = context.getCase().getServices().getFileManager();
unpackDir = Case.getModulesOutputDirRelPath() + File.separator + ArchiveFileExtractorModuleFactory.getModuleName();
unpackDirPath = currentCase.getModulesOutputDirAbsPath() + File.separator + ArchiveFileExtractorModuleFactory.getModuleName();
fileManager = currentCase.getServices().getFileManager();
File unpackDirPathFile = new File(unpackDirPath); File unpackDirPathFile = new File(unpackDirPath);
if (!unpackDirPathFile.exists()) { if (!unpackDirPathFile.exists()) {
@ -107,10 +113,10 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
} catch (SecurityException e) { } catch (SecurityException e) {
logger.log(Level.SEVERE, "Error initializing output dir: " + unpackDirPath, e); logger.log(Level.SEVERE, "Error initializing output dir: " + unpackDirPath, e);
String msg = NbBundle.getMessage(this.getClass(), String msg = NbBundle.getMessage(this.getClass(),
"SevenZipIngestModule.init.errInitModule.msg", ArchiveFileExtractorModuleFactory.getModuleName()); "SevenZipIngestModule.init.errInitModule.msg", ArchiveFileExtractorModuleFactory.getModuleName());
String details = NbBundle.getMessage(this.getClass(), String details = NbBundle.getMessage(this.getClass(),
"SevenZipIngestModule.init.errInitModule.details", "SevenZipIngestModule.init.errInitModule.details",
unpackDirPath, e.getMessage()); unpackDirPath, e.getMessage());
services.postMessage(IngestMessage.createErrorMessage(++messageID, ArchiveFileExtractorModuleFactory.getModuleName(), msg, details)); services.postMessage(IngestMessage.createErrorMessage(++messageID, ArchiveFileExtractorModuleFactory.getModuleName(), msg, details));
throw e; throw e;
} }
@ -123,10 +129,9 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
} catch (SevenZipNativeInitializationException e) { } catch (SevenZipNativeInitializationException e) {
logger.log(Level.SEVERE, "Error initializing 7-Zip-JBinding library", e); logger.log(Level.SEVERE, "Error initializing 7-Zip-JBinding library", e);
String msg = NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.init.errInitModule.msg", String msg = NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.init.errInitModule.msg",
ArchiveFileExtractorModuleFactory.getModuleName()); ArchiveFileExtractorModuleFactory.getModuleName());
String details = NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.init.errCantInitLib", String details = NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.init.errCantInitLib",
e.getMessage()); e.getMessage());
//MessageNotifyUtil.Notify.error(msg, details);
services.postMessage(IngestMessage.createErrorMessage(++messageID, ArchiveFileExtractorModuleFactory.getModuleName(), msg, details)); services.postMessage(IngestMessage.createErrorMessage(++messageID, ArchiveFileExtractorModuleFactory.getModuleName(), msg, details));
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -135,17 +140,17 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
} }
@Override @Override
public ResultCode process(AbstractFile abstractFile) { public ProcessResult process(AbstractFile abstractFile) {
if (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) { if (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) {
return ResultCode.OK; return ProcessResult.OK;
} }
if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) { if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) {
return ResultCode.OK; return ProcessResult.OK;
} }
if (abstractFile.isFile() == false || !isSupported(abstractFile)) { if (abstractFile.isFile() == false || !isSupported(abstractFile)) {
return ResultCode.OK; return ProcessResult.OK;
} }
//check if already has derived files, skip //check if already has derived files, skip
@ -156,12 +161,12 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
final String localRootAbsPath = getLocalRootAbsPath(uniqueFileName); final String localRootAbsPath = getLocalRootAbsPath(uniqueFileName);
if (new File(localRootAbsPath).exists()) { if (new File(localRootAbsPath).exists()) {
logger.log(Level.INFO, "File already has been processed as it has children and local unpacked file, skipping: {0}", abstractFile.getName()); logger.log(Level.INFO, "File already has been processed as it has children and local unpacked file, skipping: {0}", abstractFile.getName());
return ResultCode.OK; return ProcessResult.OK;
} }
} }
} catch (TskCoreException e) { } catch (TskCoreException e) {
logger.log(Level.INFO, "Error checking if file already has been processed, skipping: {0}", abstractFile.getName()); logger.log(Level.INFO, "Error checking if file already has been processed, skipping: {0}", abstractFile.getName());
return ResultCode.OK; return ProcessResult.OK;
} }
logger.log(Level.INFO, "Processing with archive extractor: {0}", abstractFile.getName()); logger.log(Level.INFO, "Processing with archive extractor: {0}", abstractFile.getName());
@ -169,10 +174,10 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
List<AbstractFile> unpackedFiles = unpack(abstractFile); List<AbstractFile> unpackedFiles = unpack(abstractFile);
if (!unpackedFiles.isEmpty()) { if (!unpackedFiles.isEmpty()) {
sendNewFilesEvent(abstractFile, unpackedFiles); sendNewFilesEvent(abstractFile, unpackedFiles);
context.submitFilesForIngest(unpackedFiles); context.addFilesToPipeline(unpackedFiles);
} }
return ResultCode.OK; return ProcessResult.OK;
} }
private void sendNewFilesEvent(AbstractFile archive, List<AbstractFile> unpackedFiles) { private void sendNewFilesEvent(AbstractFile archive, List<AbstractFile> unpackedFiles) {
@ -231,12 +236,11 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
if (cRatio >= MAX_COMPRESSION_RATIO) { if (cRatio >= MAX_COMPRESSION_RATIO) {
String itemName = archiveFileItem.getPath(); String itemName = archiveFileItem.getPath();
logger.log(Level.INFO, "Possible zip bomb detected, compression ration: " + cRatio logger.log(Level.INFO, "Possible zip bomb detected, compression ration: {0} for in archive item: {1}", new Object[]{cRatio, itemName});
+ " for in archive item: " + itemName);
String msg = NbBundle.getMessage(this.getClass(), String msg = NbBundle.getMessage(this.getClass(),
"SevenZipIngestModule.isZipBombCheck.warnMsg", archiveName, itemName); "SevenZipIngestModule.isZipBombCheck.warnMsg", archiveName, itemName);
String details = NbBundle.getMessage(this.getClass(), String details = NbBundle.getMessage(this.getClass(),
"SevenZipIngestModule.isZipBombCheck.warnDetails", cRatio); "SevenZipIngestModule.isZipBombCheck.warnDetails", cRatio);
//MessageNotifyUtil.Notify.error(msg, details); //MessageNotifyUtil.Notify.error(msg, details);
services.postMessage(IngestMessage.createWarningMessage(++messageID, ArchiveFileExtractorModuleFactory.getModuleName(), msg, details)); services.postMessage(IngestMessage.createWarningMessage(++messageID, ArchiveFileExtractorModuleFactory.getModuleName(), msg, details));
return true; return true;
@ -267,10 +271,10 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
parentAr = archiveDepthCountTree.addArchive(null, archiveId); parentAr = archiveDepthCountTree.addArchive(null, archiveId);
} else if (parentAr.getDepth() == MAX_DEPTH) { } else if (parentAr.getDepth() == MAX_DEPTH) {
String msg = NbBundle.getMessage(this.getClass(), String msg = NbBundle.getMessage(this.getClass(),
"SevenZipIngestModule.unpack.warnMsg.zipBomb", archiveFile.getName()); "SevenZipIngestModule.unpack.warnMsg.zipBomb", archiveFile.getName());
String details = NbBundle.getMessage(this.getClass(), String details = NbBundle.getMessage(this.getClass(),
"SevenZipIngestModule.unpack.warnDetails.zipBomb", "SevenZipIngestModule.unpack.warnDetails.zipBomb",
parentAr.getDepth()); parentAr.getDepth());
//MessageNotifyUtil.Notify.error(msg, details); //MessageNotifyUtil.Notify.error(msg, details);
services.postMessage(IngestMessage.createWarningMessage(++messageID, ArchiveFileExtractorModuleFactory.getModuleName(), msg, details)); services.postMessage(IngestMessage.createWarningMessage(++messageID, ArchiveFileExtractorModuleFactory.getModuleName(), msg, details));
return unpackedFiles; return unpackedFiles;
@ -349,9 +353,9 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
} else { } else {
extractedPath = "/" + useName; extractedPath = "/" + useName;
} }
String msg = NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.unpack.unknownPath.msg", String msg = NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.unpack.unknownPath.msg",
archiveFile.getName(), extractedPath); archiveFile.getName(), extractedPath);
logger.log(Level.WARNING, msg); logger.log(Level.WARNING, msg);
} }
@ -394,13 +398,13 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
long newDiskSpace = freeDiskSpace - size; long newDiskSpace = freeDiskSpace - size;
if (newDiskSpace < MIN_FREE_DISK_SPACE) { if (newDiskSpace < MIN_FREE_DISK_SPACE) {
String msg = NbBundle.getMessage(this.getClass(), String msg = NbBundle.getMessage(this.getClass(),
"SevenZipIngestModule.unpack.notEnoughDiskSpace.msg", "SevenZipIngestModule.unpack.notEnoughDiskSpace.msg",
archiveFile.getName(), fileName); archiveFile.getName(), fileName);
String details = NbBundle.getMessage(this.getClass(), String details = NbBundle.getMessage(this.getClass(),
"SevenZipIngestModule.unpack.notEnoughDiskSpace.details"); "SevenZipIngestModule.unpack.notEnoughDiskSpace.details");
//MessageNotifyUtil.Notify.error(msg, details); //MessageNotifyUtil.Notify.error(msg, details);
services.postMessage(IngestMessage.createErrorMessage(++messageID, ArchiveFileExtractorModuleFactory.getModuleName(), msg, details)); services.postMessage(IngestMessage.createErrorMessage(++messageID, ArchiveFileExtractorModuleFactory.getModuleName(), msg, details));
logger.log(Level.INFO, "Skipping archive item due not sufficient disk space for this item: " + archiveFile.getName() + ", " + fileName); logger.log(Level.INFO, "Skipping archive item due not sufficient disk space for this item: {0}, {1}", new Object[]{archiveFile.getName(), fileName});
continue; //skip this file continue; //skip this file
} else { } else {
//update est. disk space during this archive, so we don't need to poll for every file extracted //update est. disk space during this archive, so we don't need to poll for every file extracted
@ -493,10 +497,10 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
// print a message if the file is allocated // print a message if the file is allocated
if (archiveFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) { if (archiveFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
String msg = NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.unpack.errUnpacking.msg", String msg = NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.unpack.errUnpacking.msg",
archiveFile.getName()); archiveFile.getName());
String details = NbBundle.getMessage(this.getClass(), String details = NbBundle.getMessage(this.getClass(),
"SevenZipIngestModule.unpack.errUnpacking.details", "SevenZipIngestModule.unpack.errUnpacking.details",
fullName, ex.getMessage()); fullName, ex.getMessage());
services.postMessage(IngestMessage.createErrorMessage(++messageID, ArchiveFileExtractorModuleFactory.getModuleName(), msg, details)); services.postMessage(IngestMessage.createErrorMessage(++messageID, ArchiveFileExtractorModuleFactory.getModuleName(), msg, details));
} }
} finally { } finally {
@ -517,8 +521,9 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
} }
//close progress bar //close progress bar
if (progressStarted) if (progressStarted) {
progress.finish(); progress.finish();
}
} }
//create artifact and send user message //create artifact and send user message
@ -527,17 +532,15 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
try { try {
BlackboardArtifact artifact = archiveFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED); BlackboardArtifact artifact = archiveFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
artifact.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), ArchiveFileExtractorModuleFactory.getModuleName(), encryptionType)); artifact.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), ArchiveFileExtractorModuleFactory.getModuleName(), encryptionType));
context.fireDataEvent(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED); services.fireModuleDataEvent(new ModuleDataEvent(ArchiveFileExtractorModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED));
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error creating blackboard artifact for encryption detected for file: " + archiveFile, ex); logger.log(Level.SEVERE, "Error creating blackboard artifact for encryption detected for file: " + archiveFile, ex);
} }
String msg = NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.unpack.encrFileDetected.msg"); String msg = NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.unpack.encrFileDetected.msg");
String details = NbBundle.getMessage(this.getClass(), String details = NbBundle.getMessage(this.getClass(),
"SevenZipIngestModule.unpack.encrFileDetected.details", "SevenZipIngestModule.unpack.encrFileDetected.details",
archiveFile.getName(), ArchiveFileExtractorModuleFactory.getModuleName()); archiveFile.getName(), ArchiveFileExtractorModuleFactory.getModuleName());
// MessageNotifyUtil.Notify.info(msg, details);
services.postMessage(IngestMessage.createWarningMessage(++messageID, ArchiveFileExtractorModuleFactory.getModuleName(), msg, details)); services.postMessage(IngestMessage.createWarningMessage(++messageID, ArchiveFileExtractorModuleFactory.getModuleName(), msg, details));
} }
@ -552,7 +555,7 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
return true; return true;
} }
} }
// if no extension match, check the blackboard for the file type // if no extension match, check the blackboard for the file type
boolean attributeFound = false; boolean attributeFound = false;
try { try {
@ -565,14 +568,12 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
} }
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
}
}
// if no blackboard entry for file type, do it manually for ZIP files: // if no blackboard entry for file type, do it manually for ZIP files:
if (attributeFound) { if (attributeFound) {
return false; return false;
} } else {
else {
return isZipFileHeader(file); return isZipFileHeader(file);
} }
} }
@ -628,7 +629,7 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
} catch (IOException ex) { } catch (IOException ex) {
throw new SevenZipException( throw new SevenZipException(
NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.UnpackStream.write.exception.msg", NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.UnpackStream.write.exception.msg",
localAbsPath), ex); localAbsPath), ex);
} }
return bytes.length; return bytes.length;
} }
@ -770,7 +771,7 @@ public final class SevenZipIngestModule extends IngestModuleAdapter implements F
logger.log(Level.SEVERE, "Error adding a derived file to db:" + fileName, ex); logger.log(Level.SEVERE, "Error adding a derived file to db:" + fileName, ex);
throw new TskCoreException( throw new TskCoreException(
NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.UnpackedTree.exception.msg", NbBundle.getMessage(this.getClass(), "SevenZipIngestModule.UnpackedTree.exception.msg",
fileName), ex); fileName), ex);
} }
//recurse //recurse

View File

@ -1,5 +1,5 @@
OpenIDE-Module-Name=ewfVerify OpenIDE-Module-Name=ewfVerify
EwfVerifyIngestModule.moduleName.text=EWF Verify EwfVerifyIngestModule.moduleName.text=EWF Verifier
EwfVerifyIngestModule.moduleDesc.text=Validates the integrity of E01 files. EwfVerifyIngestModule.moduleDesc.text=Validates the integrity of E01 files.
EwfVerifyIngestModule.process.errProcImg=Error processing {0} EwfVerifyIngestModule.process.errProcImg=Error processing {0}
EwfVerifyIngestModule.process.skipNonEwf=Skipping non-ewf image {0} EwfVerifyIngestModule.process.skipNonEwf=Skipping non-ewf image {0}

View File

@ -27,7 +27,8 @@ import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings; import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
/** /**
* An factory that creates file ingest modules that do hash database lookups. * An factory that creates data source ingest modules that verify the integrity
* of Expert Witness Format (EWF) files (.e01).
*/ */
@ServiceProvider(service = IngestModuleFactory.class) @ServiceProvider(service = IngestModuleFactory.class)
public class EwfVerifierModuleFactory extends IngestModuleFactoryAdapter { public class EwfVerifierModuleFactory extends IngestModuleFactoryAdapter {
@ -36,7 +37,7 @@ public class EwfVerifierModuleFactory extends IngestModuleFactoryAdapter {
return NbBundle.getMessage(EwfVerifyIngestModule.class, return NbBundle.getMessage(EwfVerifyIngestModule.class,
"EwfVerifyIngestModule.moduleName.text"); "EwfVerifyIngestModule.moduleName.text");
} }
@Override @Override
public String getModuleDisplayName() { public String getModuleDisplayName() {
return getModuleName(); return getModuleName();

View File

@ -16,7 +16,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.sleuthkit.autopsy.ewfverify; package org.sleuthkit.autopsy.ewfverify;
import java.security.MessageDigest; import java.security.MessageDigest;
@ -38,8 +37,8 @@ import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
/** /**
* Data source ingest module that verifies the integrity of an Expert Witness * Data source ingest module that verifies the integrity of an Expert Witness
* Format (EWF) E01 image file by generating a hash of the file and comparing it * Format (EWF) E01 image file by generating a hash of the file and comparing it
* to the value stored in the image. * to the value stored in the image.
*/ */
public class EwfVerifyIngestModule extends IngestModuleAdapter implements DataSourceIngestModule { public class EwfVerifyIngestModule extends IngestModuleAdapter implements DataSourceIngestModule {
@ -47,7 +46,6 @@ public class EwfVerifyIngestModule extends IngestModuleAdapter implements DataSo
private static final Logger logger = Logger.getLogger(EwfVerifyIngestModule.class.getName()); private static final Logger logger = Logger.getLogger(EwfVerifyIngestModule.class.getName());
private static final long DEFAULT_CHUNK_SIZE = 32 * 1024; private static final long DEFAULT_CHUNK_SIZE = 32 * 1024;
private static final IngestServices services = IngestServices.getDefault(); private static final IngestServices services = IngestServices.getDefault();
private IngestJobContext context;
private Image img; private Image img;
private String imgName; private String imgName;
private MessageDigest messageDigest; private MessageDigest messageDigest;
@ -59,17 +57,16 @@ public class EwfVerifyIngestModule extends IngestModuleAdapter implements DataSo
EwfVerifyIngestModule() { EwfVerifyIngestModule() {
} }
@Override @Override
public void startUp(IngestJobContext context) throws Exception { public void startUp(IngestJobContext context) throws IngestModuleException {
this.context = context;
verified = false; verified = false;
skipped = false; skipped = false;
img = null; img = null;
imgName = ""; imgName = "";
storedHash = ""; storedHash = "";
calculatedHash = ""; calculatedHash = "";
if (messageDigest == null) { if (messageDigest == null) {
try { try {
messageDigest = MessageDigest.getInstance("MD5"); messageDigest = MessageDigest.getInstance("MD5");
@ -81,9 +78,9 @@ public class EwfVerifyIngestModule extends IngestModuleAdapter implements DataSo
messageDigest.reset(); messageDigest.reset();
} }
} }
@Override @Override
public ResultCode process(Content dataSource, DataSourceIngestModuleStatusHelper statusHelper) { public ProcessResult process(Content dataSource, DataSourceIngestModuleStatusHelper statusHelper) {
imgName = dataSource.getName(); imgName = dataSource.getName();
try { try {
img = dataSource.getImage(); img = dataSource.getImage();
@ -91,88 +88,86 @@ public class EwfVerifyIngestModule extends IngestModuleAdapter implements DataSo
img = null; img = null;
logger.log(Level.SEVERE, "Failed to get image from Content.", ex); logger.log(Level.SEVERE, "Failed to get image from Content.", ex);
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.ERROR, EwfVerifierModuleFactory.getModuleName(), services.postMessage(IngestMessage.createMessage(++messageId, MessageType.ERROR, EwfVerifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.errProcImg", "EwfVerifyIngestModule.process.errProcImg",
imgName))); imgName)));
return ResultCode.ERROR; return ProcessResult.ERROR;
} }
// Skip images that are not E01 // Skip images that are not E01
if (img.getType() != TskData.TSK_IMG_TYPE_ENUM.TSK_IMG_TYPE_EWF_EWF) { if (img.getType() != TskData.TSK_IMG_TYPE_ENUM.TSK_IMG_TYPE_EWF_EWF) {
img = null; img = null;
logger.log(Level.INFO, "Skipping non-ewf image " + imgName); logger.log(Level.INFO, "Skipping non-ewf image {0}", imgName);
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, EwfVerifierModuleFactory.getModuleName(), services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, EwfVerifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.skipNonEwf", "EwfVerifyIngestModule.process.skipNonEwf",
imgName))); imgName)));
skipped = true; skipped = true;
return ResultCode.OK; return ProcessResult.OK;
}
if ((img.getMd5()!= null) && !img.getMd5().isEmpty())
{
storedHash = img.getMd5().toLowerCase();
logger.log(Level.INFO, "Hash value stored in {0}: {1}", new Object[]{imgName, storedHash});
}
else {
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.ERROR, EwfVerifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.noStoredHash",
imgName)));
return ResultCode.ERROR;
} }
logger.log(Level.INFO, "Starting ewf verification of " + img.getName()); if ((img.getMd5() != null) && !img.getMd5().isEmpty()) {
storedHash = img.getMd5().toLowerCase();
logger.log(Level.INFO, "Hash value stored in {0}: {1}", new Object[]{imgName, storedHash});
} else {
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.ERROR, EwfVerifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.noStoredHash",
imgName)));
return ProcessResult.ERROR;
}
logger.log(Level.INFO, "Starting ewf verification of {0}", img.getName());
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, EwfVerifierModuleFactory.getModuleName(), services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, EwfVerifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.startingImg", "EwfVerifyIngestModule.process.startingImg",
imgName))); imgName)));
long size = img.getSize(); long size = img.getSize();
if (size == 0) { if (size == 0) {
logger.log(Level.WARNING, "Size of image " + imgName + " was 0 when queried."); logger.log(Level.WARNING, "Size of image {0} was 0 when queried.", imgName);
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.ERROR, EwfVerifierModuleFactory.getModuleName(), services.postMessage(IngestMessage.createMessage(++messageId, MessageType.ERROR, EwfVerifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.errGetSizeOfImg", "EwfVerifyIngestModule.process.errGetSizeOfImg",
imgName))); imgName)));
} }
// Libewf uses a sector size of 64 times the sector size, which is the // Libewf uses a sector size of 64 times the sector size, which is the
// motivation for using it here. // motivation for using it here.
long chunkSize = 64 * img.getSsize(); long chunkSize = 64 * img.getSsize();
chunkSize = (chunkSize == 0) ? DEFAULT_CHUNK_SIZE : chunkSize; chunkSize = (chunkSize == 0) ? DEFAULT_CHUNK_SIZE : chunkSize;
int totalChunks = (int) Math.ceil(size / chunkSize); int totalChunks = (int) Math.ceil(size / chunkSize);
logger.log(Level.INFO, "Total chunks = {0}", totalChunks); logger.log(Level.INFO, "Total chunks = {0}", totalChunks);
int read; int read;
byte[] data; byte[] data;
statusHelper.switchToDeterminate(totalChunks); statusHelper.switchToDeterminate(totalChunks);
// Read in byte size chunks and update the hash value with the data. // Read in byte size chunks and update the hash value with the data.
for (int i = 0; i < totalChunks; i++) { for (int i = 0; i < totalChunks; i++) {
if (statusHelper.isCancelled()) { if (statusHelper.isCancelled()) {
return ResultCode.OK; return ProcessResult.OK;
} }
data = new byte[ (int) chunkSize ]; data = new byte[(int) chunkSize];
try { try {
read = img.read(data, i * chunkSize, chunkSize); read = img.read(data, i * chunkSize, chunkSize);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
String msg = NbBundle.getMessage(this.getClass(), String msg = NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.errReadImgAtChunk", imgName, i); "EwfVerifyIngestModule.process.errReadImgAtChunk", imgName, i);
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.ERROR, EwfVerifierModuleFactory.getModuleName(), msg)); services.postMessage(IngestMessage.createMessage(++messageId, MessageType.ERROR, EwfVerifierModuleFactory.getModuleName(), msg));
logger.log(Level.SEVERE, msg, ex); logger.log(Level.SEVERE, msg, ex);
return ResultCode.ERROR; return ProcessResult.ERROR;
} }
messageDigest.update(data); messageDigest.update(data);
statusHelper.progress(i); statusHelper.progress(i);
} }
// Finish generating the hash and get it as a string value // Finish generating the hash and get it as a string value
calculatedHash = DatatypeConverter.printHexBinary(messageDigest.digest()).toLowerCase(); calculatedHash = DatatypeConverter.printHexBinary(messageDigest.digest()).toLowerCase();
verified = calculatedHash.equals(storedHash); verified = calculatedHash.equals(storedHash);
logger.log(Level.INFO, "Hash calculated from {0}: {1}", new Object[]{imgName, calculatedHash}); logger.log(Level.INFO, "Hash calculated from {0}: {1}", new Object[]{imgName, calculatedHash});
return ResultCode.OK; return ProcessResult.OK;
} }
@Override @Override
@ -184,7 +179,7 @@ public class EwfVerifyIngestModule extends IngestModuleAdapter implements DataSo
extra += "<li>Result:" + msg + "</li>"; extra += "<li>Result:" + msg + "</li>";
extra += "<li>Calculated hash: " + calculatedHash + "</li>"; extra += "<li>Calculated hash: " + calculatedHash + "</li>";
extra += "<li>Stored hash: " + storedHash + "</li>"; extra += "<li>Stored hash: " + storedHash + "</li>";
services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, EwfVerifierModuleFactory.getModuleName(), imgName + msg, extra)); services.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, EwfVerifierModuleFactory.getModuleName(), imgName + msg, extra));
logger.log(Level.INFO, "{0}{1}", new Object[]{imgName, msg}); logger.log(Level.INFO, "{0}{1}", new Object[]{imgName, msg});
} }
} }

View File

@ -49,7 +49,7 @@ public class EmailParserModuleFactory extends IngestModuleFactoryAdapter {
@Override @Override
public String getModuleDescription() { public String getModuleDescription() {
return "This module detects and parses mbox and pst/ost files and populates email artifacts in the blackboard."; return NbBundle.getMessage(ThunderbirdMboxFileIngestModule.class, "ThunderbirdMboxFileIngestModule.getDesc.text");
} }
@Override @Override

View File

@ -30,7 +30,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestMessage; import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestModule.ResultCode; import org.sleuthkit.autopsy.ingest.IngestModule.ProcessResult;
import org.sleuthkit.autopsy.ingest.IngestModuleAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleAdapter;
import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.IngestServices;
@ -46,37 +46,44 @@ import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.TskException;
/** /**
* File-level ingest module that detects MBOX files based on signature. * File-level ingest module that detects MBOX files based on signature.
* Understands Thunderbird folder layout to provide additional structure and metadata. * Understands Thunderbird folder layout to provide additional structure and
* metadata.
*/ */
public final class ThunderbirdMboxFileIngestModule extends IngestModuleAdapter implements FileIngestModule { public final class ThunderbirdMboxFileIngestModule extends IngestModuleAdapter implements FileIngestModule {
private static final Logger logger = Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName()); private static final Logger logger = Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName());
private IngestServices services; private IngestServices services = IngestServices.getDefault();
private int messageId = 0; // RJCTODO: Not thread safe private int messageId = 0; // RJCTODO: Not thread safe
private FileManager fileManager; private FileManager fileManager;
private IngestJobContext context; private IngestJobContext context;
ThunderbirdMboxFileIngestModule() { ThunderbirdMboxFileIngestModule() {
} }
@Override @Override
public ResultCode process(AbstractFile abstractFile) { public void startUp(IngestJobContext context) throws IngestModuleException {
this.context = context;
fileManager = Case.getCurrentCase().getServices().getFileManager();
}
@Override
public ProcessResult process(AbstractFile abstractFile) {
// skip known // skip known
if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) { if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) {
return ResultCode.OK; return ProcessResult.OK;
} }
//skip unalloc //skip unalloc
if(abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) { if (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) {
return ResultCode.OK; return ProcessResult.OK;
} }
if (abstractFile.isVirtual()) { if (abstractFile.isVirtual()) {
return ResultCode.OK; return ProcessResult.OK;
} }
// check its signature // check its signature
boolean isMbox = false; boolean isMbox = false;
try { try {
@ -90,49 +97,49 @@ public final class ThunderbirdMboxFileIngestModule extends IngestModuleAdapter i
} catch (TskException ex) { } catch (TskException ex) {
logger.log(Level.WARNING, null, ex); logger.log(Level.WARNING, null, ex);
} }
if (isMbox) { if (isMbox) {
return processMBox(abstractFile); return processMBox(abstractFile);
} }
if (PstParser.isPstFile(abstractFile)) { if (PstParser.isPstFile(abstractFile)) {
return processPst(abstractFile); return processPst(abstractFile);
} }
return ResultCode.OK; return ProcessResult.OK;
} }
/** /**
* Processes a pst/ost data file and extracts and adds email artifacts. * Processes a pst/ost data file and extracts and adds email artifacts.
* *
* @param abstractFile The pst/ost data file to process. * @param abstractFile The pst/ost data file to process.
* @return * @return
*/ */
private ResultCode processPst(AbstractFile abstractFile) { private ProcessResult processPst(AbstractFile abstractFile) {
String fileName = getTempPath() + File.separator + abstractFile.getName() String fileName = getTempPath() + File.separator + abstractFile.getName()
+ "-" + String.valueOf(abstractFile.getId()); + "-" + String.valueOf(abstractFile.getId());
File file = new File(fileName); File file = new File(fileName);
if (abstractFile.getSize() >= services.getFreeDiskSpace()) { if (abstractFile.getSize() >= services.getFreeDiskSpace()) {
logger.log(Level.WARNING, "Not enough disk space to write file to disk."); logger.log(Level.WARNING, "Not enough disk space to write file to disk.");
IngestMessage msg = IngestMessage.createErrorMessage(messageId++, EmailParserModuleFactory.getModuleName(), EmailParserModuleFactory.getModuleName(), IngestMessage msg = IngestMessage.createErrorMessage(messageId++, EmailParserModuleFactory.getModuleName(), EmailParserModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"ThunderbirdMboxFileIngestModule.processPst.errMsg.outOfDiskSpace", "ThunderbirdMboxFileIngestModule.processPst.errMsg.outOfDiskSpace",
abstractFile.getName())); abstractFile.getName()));
services.postMessage(msg); services.postMessage(msg);
return ResultCode.OK; return ProcessResult.OK;
} }
try { try {
ContentUtils.writeToFile(abstractFile, file); ContentUtils.writeToFile(abstractFile, file);
} catch (IOException ex) { } catch (IOException ex) {
logger.log(Level.WARNING, "Failed writing pst file to disk.", ex); logger.log(Level.WARNING, "Failed writing pst file to disk.", ex);
return ResultCode.OK; return ProcessResult.OK;
} }
PstParser parser = new PstParser(services); PstParser parser = new PstParser(services);
PstParser.ParseResult result = parser.parse(file); PstParser.ParseResult result = parser.parse(file);
if (result == PstParser.ParseResult.OK) { if (result == PstParser.ParseResult.OK) {
// parse success: Process email and add artifacts // parse success: Process email and add artifacts
processEmails(parser.getResults(), abstractFile); processEmails(parser.getResults(), abstractFile);
@ -150,34 +157,35 @@ public final class ThunderbirdMboxFileIngestModule extends IngestModuleAdapter i
// parsing error: log message // parsing error: log message
postErrorMessage( postErrorMessage(
NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg", NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg",
abstractFile.getName()), abstractFile.getName()),
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"ThunderbirdMboxFileIngestModule.processPst.errProcFile.details")); "ThunderbirdMboxFileIngestModule.processPst.errProcFile.details"));
logger.log(Level.INFO, "PSTParser failed to parse {0}", abstractFile.getName()); logger.log(Level.INFO, "PSTParser failed to parse {0}", abstractFile.getName());
return ResultCode.ERROR; return ProcessResult.ERROR;
} }
if (file.delete() == false) { if (file.delete() == false) {
logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName());
} }
String errors = parser.getErrors(); String errors = parser.getErrors();
if (errors.isEmpty() == false) { if (errors.isEmpty() == false) {
postErrorMessage( postErrorMessage(
NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg2", NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg2",
abstractFile.getName()), errors); abstractFile.getName()), errors);
} }
return ResultCode.OK; return ProcessResult.OK;
} }
/** /**
* Parse and extract email messages and attachments from an MBox file. * Parse and extract email messages and attachments from an MBox file.
*
* @param abstractFile * @param abstractFile
* @param ingestContext * @param ingestContext
* @return * @return
*/ */
private ResultCode processMBox(AbstractFile abstractFile) { private ProcessResult processMBox(AbstractFile abstractFile) {
String mboxFileName = abstractFile.getName(); String mboxFileName = abstractFile.getName();
String mboxParentDir = abstractFile.getParentPath(); String mboxParentDir = abstractFile.getParentPath();
// use the local path to determine the e-mail folder structure // use the local path to determine the e-mail folder structure
@ -185,56 +193,56 @@ public final class ThunderbirdMboxFileIngestModule extends IngestModuleAdapter i
// email folder is everything after "Mail" or ImapMail // email folder is everything after "Mail" or ImapMail
if (mboxParentDir.contains("/Mail/")) { if (mboxParentDir.contains("/Mail/")) {
emailFolder = mboxParentDir.substring(mboxParentDir.indexOf("/Mail/") + 5); emailFolder = mboxParentDir.substring(mboxParentDir.indexOf("/Mail/") + 5);
} } else if (mboxParentDir.contains("/ImapMail/")) {
else if (mboxParentDir.contains("/ImapMail/")) { emailFolder = mboxParentDir.substring(mboxParentDir.indexOf("/ImapMail/") + 9);
emailFolder = mboxParentDir.substring(mboxParentDir.indexOf("/ImapMail/") + 9); }
}
emailFolder = emailFolder + mboxFileName; emailFolder = emailFolder + mboxFileName;
emailFolder = emailFolder.replaceAll(".sbd", ""); emailFolder = emailFolder.replaceAll(".sbd", "");
String fileName = getTempPath() + File.separator + abstractFile.getName() String fileName = getTempPath() + File.separator + abstractFile.getName()
+ "-" + String.valueOf(abstractFile.getId()); + "-" + String.valueOf(abstractFile.getId());
File file = new File(fileName); File file = new File(fileName);
if (abstractFile.getSize() >= services.getFreeDiskSpace()) { if (abstractFile.getSize() >= services.getFreeDiskSpace()) {
logger.log(Level.WARNING, "Not enough disk space to write file to disk."); logger.log(Level.WARNING, "Not enough disk space to write file to disk.");
postErrorMessage( postErrorMessage(
NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg", NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg",
abstractFile.getName()), abstractFile.getName()),
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"ThunderbirdMboxFileIngestModule.processMBox.errProfFile.details")); "ThunderbirdMboxFileIngestModule.processMBox.errProfFile.details"));
return ResultCode.OK; return ProcessResult.OK;
} }
try { try {
ContentUtils.writeToFile(abstractFile, file); ContentUtils.writeToFile(abstractFile, file);
} catch (IOException ex) { } catch (IOException ex) {
logger.log(Level.WARNING, "Failed writing mbox file to disk.", ex); logger.log(Level.WARNING, "Failed writing mbox file to disk.", ex);
return ResultCode.OK; return ProcessResult.OK;
} }
MboxParser parser = new MboxParser(services, emailFolder); MboxParser parser = new MboxParser(services, emailFolder);
List<EmailMessage> emails = parser.parse(file); List<EmailMessage> emails = parser.parse(file);
processEmails(emails, abstractFile); processEmails(emails, abstractFile);
if (file.delete() == false) { if (file.delete() == false) {
logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName());
} }
String errors = parser.getErrors(); String errors = parser.getErrors();
if (errors.isEmpty() == false) { if (errors.isEmpty() == false) {
postErrorMessage( postErrorMessage(
NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg2", NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg2",
abstractFile.getName()), errors); abstractFile.getName()), errors);
} }
return ResultCode.OK; return ProcessResult.OK;
} }
/** /**
* Get a path to a temporary folder. * Get a path to a temporary folder.
* @return *
* @return
*/ */
public static String getTempPath() { public static String getTempPath() {
String tmpDir = Case.getCurrentCase().getTempDirectory() + File.separator String tmpDir = Case.getCurrentCase().getTempDirectory() + File.separator
@ -245,35 +253,29 @@ public final class ThunderbirdMboxFileIngestModule extends IngestModuleAdapter i
} }
return tmpDir; return tmpDir;
} }
public static String getModuleOutputPath() { public static String getModuleOutputPath() {
String outDir = Case.getCurrentCase().getModulesOutputDirAbsPath() + File.separator + String outDir = Case.getCurrentCase().getModulesOutputDirAbsPath() + File.separator
EmailParserModuleFactory.getModuleName(); + EmailParserModuleFactory.getModuleName();
File dir = new File(outDir); File dir = new File(outDir);
if (dir.exists() == false) { if (dir.exists() == false) {
dir.mkdirs(); dir.mkdirs();
} }
return outDir; return outDir;
} }
public static String getRelModuleOutputPath() { public static String getRelModuleOutputPath() {
return Case.getModulesOutputDirRelPath() + File.separator + return Case.getModulesOutputDirRelPath() + File.separator
EmailParserModuleFactory.getModuleName(); + EmailParserModuleFactory.getModuleName();
} }
@Override
public void startUp(IngestJobContext context) throws Exception {
this.context = context;
services = IngestServices.getDefault();
fileManager = Case.getCurrentCase().getServices().getFileManager();
}
/** /**
* Take the extracted information in the email messages and add the * Take the extracted information in the email messages and add the
* appropriate artifacts and derived files. * appropriate artifacts and derived files.
*
* @param emails * @param emails
* @param abstractFile * @param abstractFile
* @param ingestContext * @param ingestContext
*/ */
private void processEmails(List<EmailMessage> emails, AbstractFile abstractFile) { private void processEmails(List<EmailMessage> emails, AbstractFile abstractFile) {
List<AbstractFile> derivedFiles = new ArrayList<>(); List<AbstractFile> derivedFiles = new ArrayList<>();
@ -283,21 +285,23 @@ public final class ThunderbirdMboxFileIngestModule extends IngestModuleAdapter i
} }
addArtifact(email, abstractFile); addArtifact(email, abstractFile);
} }
if (derivedFiles.isEmpty() == false) { if (derivedFiles.isEmpty() == false) {
for (AbstractFile derived : derivedFiles) { // RJCTODO: May want to add bulk method for (AbstractFile derived : derivedFiles) { // RJCTODO: May want to add bulk method
services.fireModuleContentEvent(new ModuleContentEvent(derived)); services.fireModuleContentEvent(new ModuleContentEvent(derived));
} }
} }
context.submitFilesForIngest(derivedFiles); context.addFilesToPipeline(derivedFiles);
services.fireModuleDataEvent(new ModuleDataEvent(EmailParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG)); services.fireModuleDataEvent(new ModuleDataEvent(EmailParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG));
} }
/** /**
* Add the given attachments as derived files and reschedule them for ingest. * Add the given attachments as derived files and reschedule them for
* ingest.
*
* @param attachments * @param attachments
* @param abstractFile * @param abstractFile
* @return * @return
*/ */
private List<AbstractFile> handleAttachments(List<Attachment> attachments, AbstractFile abstractFile) { private List<AbstractFile> handleAttachments(List<Attachment> attachments, AbstractFile abstractFile) {
List<AbstractFile> files = new ArrayList<>(); List<AbstractFile> files = new ArrayList<>();
@ -311,26 +315,27 @@ public final class ThunderbirdMboxFileIngestModule extends IngestModuleAdapter i
long size = attach.getSize(); long size = attach.getSize();
try { try {
DerivedFile df = fileManager.addDerivedFile(filename, relPath, DerivedFile df = fileManager.addDerivedFile(filename, relPath,
size, cTime, crTime, aTime, mTime, true, abstractFile, "", size, cTime, crTime, aTime, mTime, true, abstractFile, "",
EmailParserModuleFactory.getModuleName(), EmailParserModuleFactory.getVersion(), ""); EmailParserModuleFactory.getModuleName(), EmailParserModuleFactory.getVersion(), "");
files.add(df); files.add(df);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
postErrorMessage( postErrorMessage(
NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.handleAttch.errMsg", NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.handleAttch.errMsg",
abstractFile.getName()), abstractFile.getName()),
NbBundle.getMessage(this.getClass(), NbBundle.getMessage(this.getClass(),
"ThunderbirdMboxFileIngestModule.handleAttch.errMsg.details", filename)); "ThunderbirdMboxFileIngestModule.handleAttch.errMsg.details", filename));
logger.log(Level.INFO, "", ex); logger.log(Level.INFO, "", ex);
} }
} }
return files; return files;
} }
/** /**
* Add a blackboard artifact for the given email message. * Add a blackboard artifact for the given email message.
*
* @param email * @param email
* @param abstractFile * @param abstractFile
*/ */
private void addArtifact(EmailMessage email, AbstractFile abstractFile) { private void addArtifact(EmailMessage email, AbstractFile abstractFile) {
List<BlackboardAttribute> bbattributes = new ArrayList<>(); List<BlackboardAttribute> bbattributes = new ArrayList<>();
@ -345,7 +350,7 @@ public final class ThunderbirdMboxFileIngestModule extends IngestModuleAdapter i
String subject = email.getSubject(); String subject = email.getSubject();
long id = email.getId(); long id = email.getId();
String localPath = email.getLocalPath(); String localPath = email.getLocalPath();
if (to.isEmpty() == false) { if (to.isEmpty() == false) {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_TO.getTypeID(), EmailParserModuleFactory.getModuleName(), to)); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_TO.getTypeID(), EmailParserModuleFactory.getModuleName(), to));
} }
@ -381,7 +386,7 @@ public final class ThunderbirdMboxFileIngestModule extends IngestModuleAdapter i
} else { } else {
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH.getTypeID(), EmailParserModuleFactory.getModuleName(), "/foo/bar")); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH.getTypeID(), EmailParserModuleFactory.getModuleName(), "/foo/bar"));
} }
try { try {
BlackboardArtifact bbart; BlackboardArtifact bbart;
bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG); bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
@ -390,12 +395,12 @@ public final class ThunderbirdMboxFileIngestModule extends IngestModuleAdapter i
logger.log(Level.WARNING, null, ex); logger.log(Level.WARNING, null, ex);
} }
} }
void postErrorMessage(String subj, String details) { void postErrorMessage(String subj, String details) {
IngestMessage ingestMessage = IngestMessage.createErrorMessage(messageId++, EmailParserModuleFactory.getVersion(), subj, details); IngestMessage ingestMessage = IngestMessage.createErrorMessage(messageId++, EmailParserModuleFactory.getVersion(), subj, details);
services.postMessage(ingestMessage); services.postMessage(ingestMessage);
} }
IngestServices getServices() { IngestServices getServices() {
return services; return services;
} }