Merge pull request #556 from rcordovano/new_ingest_framework

New ingest framework
This commit is contained in:
Richard Cordovano 2014-03-24 21:58:49 -04:00
commit 51cca21f3f
133 changed files with 5959 additions and 7419 deletions

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -19,7 +19,6 @@
package org.sleuthkit.autopsy.casemodule;
import org.sleuthkit.autopsy.ingest.IngestConfigurator;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.event.ActionEvent;
@ -36,12 +35,12 @@ import org.openide.DialogDisplayer;
import org.openide.WizardDescriptor;
import org.openide.util.ChangeSupport;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction;
import org.openide.util.actions.Presenter;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.Image;
/**
@ -109,8 +108,7 @@ public final class AddImageAction extends CallableSystemAction implements Presen
public void actionPerformed(ActionEvent e) {
Logger.noteAction(AddImageAction.class);
final IngestConfigurator ingestConfig = Lookup.getDefault().lookup(IngestConfigurator.class);
if (null != ingestConfig && ingestConfig.isIngestRunning()) {
if (IngestManager.getDefault().isIngestRunning()) {
final String msg = NbBundle.getMessage(this.getClass(), "AddImageAction.ingestConfig.ongoingIngest.msg");
if (JOptionPane.showConfirmDialog(null, msg,
NbBundle.getMessage(this.getClass(),

View File

@ -19,8 +19,8 @@
package org.sleuthkit.autopsy.casemodule;
import org.sleuthkit.autopsy.ingest.IngestJobLauncher;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.ingest.IngestConfigurator;
import java.awt.Color;
import java.awt.Component;
import java.awt.Window;
@ -33,7 +33,6 @@ import javax.swing.SwingUtilities;
import javax.swing.event.ChangeListener;
import org.openide.WizardDescriptor;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
@ -47,7 +46,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDescriptor> {
private static final Logger logger = Logger.getLogger(AddImageWizardIngestConfigPanel.class.getName());
private IngestConfigurator ingestConfig;
private IngestJobLauncher ingestConfig;
/**
* The visual component that displays this panel. If you need to access the
* component from this class, just use getComponent().
@ -74,8 +73,8 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
this.progressPanel = proPanel;
this.dataSourcePanel = dsPanel;
ingestConfig = Lookup.getDefault().lookup(IngestConfigurator.class);
List<String> messages = ingestConfig.setContext(AddImageWizardIngestConfigPanel.class.getCanonicalName());
ingestConfig = new IngestJobLauncher(AddImageWizardIngestConfigPanel.class.getCanonicalName());
List<String> messages = ingestConfig.getIngestJobConfigWarnings();
if (messages.isEmpty() == false) {
StringBuilder warning = new StringBuilder();
for (String message : messages) {
@ -96,7 +95,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
@Override
public Component getComponent() {
if (component == null) {
component = new AddImageWizardIngestConfigVisual(ingestConfig.getIngestConfigPanel());
component = new AddImageWizardIngestConfigVisual(ingestConfig.getIngestJobConfigPanel());
}
return component;
}
@ -188,8 +187,8 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
*/
@Override
public void storeSettings(WizardDescriptor settings) {
//save previously selected config
ingestConfig.save();
ingestConfig.saveIngestJobConfig();
// Start ingest if it hasn't already been started
readyToIngest = true;
startIngest();
@ -202,8 +201,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
private void startIngest() {
if (!newContents.isEmpty() && readyToIngest && !ingested) {
ingested = true;
ingestConfig.setContent(newContents);
ingestConfig.start();
ingestConfig.startIngestJobs(newContents);
progressPanel.setStateFinished();
}

View File

@ -114,13 +114,13 @@ class DirectoryTreeFilterNode extends FilterNode {
//ingest action
actions.add(new AbstractAction(
NbBundle.getMessage(this.getClass(), "DirectoryTreeFilterNode.action.runIngestMods.text")) {
@Override
public void actionPerformed(ActionEvent e) {
final IngestDialog ingestDialog = new IngestDialog();
ingestDialog.setContent(Collections.<Content>singletonList(content));
ingestDialog.display();
}
});
@Override
public void actionPerformed(ActionEvent e) {
final IngestDialog ingestDialog = new IngestDialog();
ingestDialog.setDataSources(Collections.<Content>singletonList(content));
ingestDialog.display();
}
});
}
//check if delete actions should be added
@ -141,7 +141,7 @@ class DirectoryTreeFilterNode extends FilterNode {
}
private static List<Action> getDetailActions(Content c) {
List<Action> actions = new ArrayList<Action>();
List<Action> actions = new ArrayList<>();
actions.addAll(ExplorerNodeActionVisitor.getActions(c));

View File

@ -64,7 +64,7 @@ import org.sleuthkit.autopsy.datamodel.RootContentChildren;
import org.sleuthkit.autopsy.datamodel.Views;
import org.sleuthkit.autopsy.datamodel.ViewsNode;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent;
import org.sleuthkit.autopsy.ingest.IngestManager.IngestEvent;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -587,7 +587,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
// change in node selection
else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
respondSelection((Node[]) oldValue, (Node[]) newValue);
} else if (changed.equals(IngestModuleEvent.DATA.toString())) {
} else if (changed.equals(IngestEvent.DATA.toString())) {
final ModuleDataEvent event = (ModuleDataEvent) oldValue;
if (event.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO) {
return;
@ -598,7 +598,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
refreshTree(event.getArtifactType());
}
});
} else if (changed.equals(IngestModuleEvent.COMPLETED.toString())) {
} else if (changed.equals(IngestEvent.COMPLETED.toString())) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
@ -606,7 +606,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
refreshTree();
}
});
} else if (changed.equals(IngestModuleEvent.CONTENT_CHANGED.toString())) {
} else if (changed.equals(IngestEvent.CONTENT_CHANGED.toString())) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {

View File

@ -1,33 +1,32 @@
/*
* Sample module in the public domain. Feel free to use this as a template
* for your modules.
*
* Contact: Brian Carrier [carrier <at> sleuthkit [dot] org]
*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
* Sample module in the public domain. Feel free to use this as a template
* for your modules.
*
* Contact: Brian Carrier [carrier <at> sleuthkit [dot] org]
*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.sleuthkit.autopsy.examples;
import java.util.List;
@ -35,10 +34,10 @@ import org.apache.log4j.Logger;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.casemodule.services.Services;
import org.sleuthkit.autopsy.ingest.IngestDataSourceWorkerController;
import org.sleuthkit.autopsy.ingest.IngestModuleDataSource;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.PipelineContext;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleStatusHelper;
import org.sleuthkit.autopsy.ingest.IngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleAdapter;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.FsContent;
@ -46,74 +45,40 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Sample DataSource-level ingest module that doesn't do much at all.
* Just exists to show basic idea of these modules
* Sample data source ingest module that doesn't do much. Note that the
* IngestModuleAdapter abstract class could have been used as a base class to
* obtain default implementations of many of the DataSourceIngestModule methods.
*/
public class SampleDataSourceIngestModule extends org.sleuthkit.autopsy.ingest.IngestModuleDataSource {
/* Data Source modules operate on a disk or set of logical files. They
* are passed in teh data source refernce and query it for things they want.
*/
// RJCTODO: Remove inheritance from IngestModuleAdapter to show full implementation of interface
// provide better documentation, and provide more extensive demonstration of how to
// use various ingest services.
class SampleDataSourceIngestModule extends IngestModuleAdapter implements DataSourceIngestModule {
private static final Logger logger = Logger.getLogger(SampleDataSourceIngestModule.class);
@Override
public void process(PipelineContext<IngestModuleDataSource> pipelineContext, Content dataSource, IngestDataSourceWorkerController controller) {
public ProcessResult process(Content dataSource, DataSourceIngestModuleStatusHelper statusHelper) {
Case case1 = Case.getCurrentCase();
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
Services services = new Services(sleuthkitCase);
FileManager fm = services.getFileManager();
FileManager fileManager = services.getFileManager();
try {
/* you can use the findFiles method in FileManager (or similar ones in
* SleuthkitCase to find files based only on their name. This
* one finds files that have a .doc extension. */
List<AbstractFile> docFiles = fm.findFiles(dataSource, "%.doc");
List<AbstractFile> docFiles = fileManager.findFiles(dataSource, "%.doc");
for (AbstractFile file : docFiles) {
// do something with each doc file
}
/* We can also do more general queries with findFilesWhere, which
* allows us to make our own WHERE clause in the database.
*/
long currentTime = System.currentTimeMillis()/1000;
// go back 2 weeks
long minTime = currentTime - (14 * 24 * 60 * 60);
long currentTime = System.currentTimeMillis() / 1000;
long minTime = currentTime - (14 * 24 * 60 * 60); // Go back two weeks.
List<FsContent> otherFiles = sleuthkitCase.findFilesWhere("crtime > " + minTime);
// do something with these files...
} catch (TskCoreException ex) {
Logger log = Logger.getLogger(SampleDataSourceIngestModule.class);
log.fatal("Error retrieving files from database: " + ex.getLocalizedMessage());
}
}
@Override
public void init(IngestModuleInit initContext) throws IngestModuleException {
}
@Override
public void complete() {
}
@Override
public void stop() {
}
@Override
public String getName() {
return "SampleDataSourceIngestModule";
}
@Override
public String getVersion() {
return "1.0";
}
@Override
public String getDescription() {
return "Doesn't do much";
}
@Override
public boolean hasBackgroundJobsRunning() {
return false;
logger.fatal("Error retrieving files from database: " + ex.getLocalizedMessage());
return IngestModule.ProcessResult.OK;
}
return IngestModule.ProcessResult.OK;
}
}

View File

@ -32,9 +32,10 @@ package org.sleuthkit.autopsy.examples;
import org.apache.log4j.Logger;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.PipelineContext;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleAdapter;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -53,26 +54,15 @@ import org.sleuthkit.datamodel.TskData;
* org.sleuthkit.autopsy.examples package. Either change the package or the
* loading code to make this module actually run.
*/
public class SampleFileIngestModule extends org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile {
// RJCTODO: Remove inheritance from IngestModuleAdapter to show full implementation of interface
// provide better documentation, and provide more extensive demonstration of how to
// use various ingest services.
class SampleFileIngestModule extends IngestModuleAdapter implements FileIngestModule {
private int attrId = -1;
private static SampleFileIngestModule defaultInstance = null;
// Private to ensure Singleton status
private SampleFileIngestModule() {
}
// File-level ingest modules are currently singleton -- this is required
public static synchronized SampleFileIngestModule getDefault() {
//defaultInstance is a private static class variable
if (defaultInstance == null) {
defaultInstance = new SampleFileIngestModule();
}
return defaultInstance;
}
@Override
public void init(IngestModuleInit initContext) throws IngestModuleException {
public void startUp(IngestJobContext initContext) {
/* For this demo, we are going to make a private attribute to post our
* results to the blackbaord with. There are many standard blackboard artifact
* and attribute types and you should first consider using one of those before
@ -99,19 +89,18 @@ public class SampleFileIngestModule extends org.sleuthkit.autopsy.ingest.IngestM
}
@Override
public ProcessResult process(PipelineContext<IngestModuleAbstractFile> pipelineContext, AbstractFile abstractFile) {
public IngestModule.ProcessResult process(AbstractFile abstractFile) {
// skip non-files
if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
|| (abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) {
return ProcessResult.OK;
return IngestModule.ProcessResult.OK;
}
// skip NSRL / known files
if (abstractFile.getKnown() == TskData.FileKnown.KNOWN) {
return ProcessResult.OK;
return IngestModule.ProcessResult.OK;
}
/* Do a non-sensical calculation of the number of 0x00 bytes
* in the first 1024-bytes of the file. This is for demo
* purposes only.
@ -128,7 +117,7 @@ public class SampleFileIngestModule extends org.sleuthkit.autopsy.ingest.IngestM
if (attrId != -1) {
// Make an attribute using the ID for the private type that we previously created.
BlackboardAttribute attr = new BlackboardAttribute(attrId, getName(), count);
BlackboardAttribute attr = new BlackboardAttribute(attrId, "SampleFileIngestModule", count); // RJCTODO: Set up factory with static module name function as example
/* add it to the general info artifact. In real modules, you would likely have
* more complex data types and be making more specific artifacts.
@ -137,38 +126,12 @@ public class SampleFileIngestModule extends org.sleuthkit.autopsy.ingest.IngestM
art.addAttribute(attr);
}
return ProcessResult.OK;
return IngestModule.ProcessResult.OK;
} catch (TskCoreException ex) {
Exceptions.printStackTrace(ex);
return ProcessResult.ERROR;
return IngestModule.ProcessResult.ERROR;
}
}
@Override
public void complete() {
}
@Override
public void stop() {
}
@Override
public String getVersion() {
return "1.0";
}
@Override
public String getName() {
return "SampleFileIngestModule";
}
@Override
public String getDescription() {
return "Doesn't do much";
}
@Override
public boolean hasBackgroundJobsRunning() {
return false;
}
// RJCTODO: Add a module factory with service provider annotation (commented out)
}

View File

@ -6,7 +6,6 @@ IngestMessageDetailsPanel.viewArtifactButton.text=Go to Result
IngestMessageDetailsPanel.viewContentButton.text=Go to Directory
IngestMessagePanel.sortByLabel.text=Sort by:
IngestMessagePanel.sortByComboBox.toolTipText=Sort messages by time (chronological order) or message priority
IngestDialogPanel.advancedButton.text=Advanced
IngestMessageDetailsPanel.messageDetailsPane.contentType=text/html
IngestMessageDetailsPanel.messageDetailsPane.toolTipText=
IngestMessagesToolbar.toolTipText=
@ -17,16 +16,14 @@ IngestMessagePanel.totalMessagesNameLabel.text=Total:
IngestMessagePanel.totalMessagesNameVal.text=-
IngestMessagePanel.totalUniqueMessagesNameLabel.text=Unique:
IngestMessagePanel.totalUniqueMessagesNameVal.text=-
IngestDialogPanel.processUnallocCheckbox.text=Process Unallocated Space
IngestDialogPanel.processUnallocCheckbox.toolTipText=Processes unallocated space, such as deleted files. Produces more complete results, but it may take longer to process on large images.
DataSourceTask.toString.text=ScheduledTask'{'input\={0}, modules\={1}'}'
GeneralIngestConfigurator.modName.tbirdParser.text=Thunderbird Parser
GeneralIngestConfigurator.modName.mboxParser.text=MBox Parser
GeneralIngestConfigurator.modName.emailParser.text=Email Parser
GeneralIngestConfigurator.enabledMods.notFound.msg={0} was previously enabled, but could not be found
IngestDataSourceThread.displayName.text={0} dataSource id\:{1}
IngestDataSourceThread.progress.pending={0} (Pending...)
IngestDataSourceThread.progress.cancelling={0} (Cancelling...)
IngestJobConfigurationPanel.processUnallocCheckbox.toolTipText=Processes unallocated space, such as deleted files. Produces more complete results, but it may take longer to process on large images.
IngestJobConfigurationPanel.processUnallocCheckbox.text=Process Unallocated Space
IngestJobConfigurationPanel.advancedButton.text=Advanced
IngestJob.toString.text=ScheduledTask'{'input\={0}, modules\={1}'}'
IngestJobLauncher.modName.tbirdParser.text=Thunderbird Parser
IngestJobLauncher.modName.mboxParser.text=MBox Parser
IngestJobLauncher.modName.emailParser.text=Email Parser
IngestJobLauncher.enabledMods.notFound.msg={0} was previously enabled, but could not be found
IngestDialog.title.text=Ingest Modules
IngestDialog.startButton.title=Start
IngestDialog.closeButton.title=Close
@ -49,12 +46,15 @@ IngestManager.toHtmlStr.totalErrs.text=Total errors\: {0}
IngestManager.toHtmlStr.module.text=Module
IngestManager.toHtmlStr.time.text=Time
IngestManager.toHtmlStr.errors.text=Errors
IngestManager.IngestAbstractFileProcessor.displayName=File Ingest
IngestManager.IngestAbstractFileProcessor.process.cancelling={0} (Cancelling...)
IngestManager.FileTaskWorker.displayName=File Ingest
IngestManager.FileTaskWorker.process.cancelling={0} (Cancelling...)
IngestManager.EnqueueWorker.displayName.text=Queueing Ingest
IngestManager.EnqueueWorker.process.cancelling={0} (Cancelling...)
IngestManager.DataSourceTaskWorker.progress.pending={0} (Pending...)
IngestManager.DataSourceTaskWorker.progress.cancelling={0} (Cancelling...)
IngestManager.datatSourceIngest.progress.text=DataSource Ingest {0}
IngestManager.fileIngest.progress.text=File Ingest {0}
IngestJob.DataSourceIngestPipeline.displayName.text={0} processing {1}
IngestMessage.toString.type.text=type\: {0}
IngestMessage.toString.source.text=\ source\: {0}
IngestMessage.toString.date.text=\ date\: {0}
@ -101,4 +101,3 @@ IngestScheduler.remove.exception.notSupported.msg=Not supported.
IngestScheduler.DataSourceScheduler.exception.next.msg=There is no data source tasks in the queue, check hasNext()
IngestScheduler.DataSourceScheduler.exception.remove.msg=Removing of scheduled data source ingest tasks is not supported.
IngestScheduler.DataSourceScheduler.toString.size=DataSourceQueue, size\: {0}
PipelineContext.toString.text=pipelineContext'{'task\={0}'}'

View File

@ -0,0 +1,37 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import org.sleuthkit.datamodel.Content;
/**
* Interface that must be implemented by all data source ingest modules.
*/
public interface DataSourceIngestModule extends IngestModule {
/**
* Processes a data source.
*
* @param dataSource The data source to process.
* @param statusHelper A status helper to be used to report progress and
* detect ingest job cancellation.
* @return A result code indicating success or failure of the processing.
*/
ProcessResult process(Content dataSource, DataSourceIngestModuleStatusHelper statusHelper);
}

View File

@ -0,0 +1,87 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import javax.swing.SwingWorker;
import org.netbeans.api.progress.ProgressHandle;
import org.sleuthkit.datamodel.Content;
/**
* Used by data source ingest modules to report progress and detect data source
* ingest job cancellation.
*/
public class DataSourceIngestModuleStatusHelper {
private final SwingWorker worker;
private final ProgressHandle progress;
private final Content dataSource;
DataSourceIngestModuleStatusHelper(SwingWorker worker, ProgressHandle progress, Content dataSource) {
this.worker = worker;
this.progress = progress;
this.dataSource = dataSource;
}
/**
* Checks for ingest job cancellation. This should be polled by the module
* in its process() method. If the ingest task is canceled, the module
* should return from its process() method as quickly as possible.
*
* @return True if the task has been canceled, false otherwise.
*/
public boolean isCancelled() {
return worker.isCancelled();
}
/**
* Updates the progress bar and switches it to determinate mode. This should
* be called by the module as soon as the number of total work units
* required to process the data source is known.
*
* @param workUnits Total number of work units for the processing of the
* data source.
*/
public void switchToDeterminate(int workUnits) {
if (progress != null) {
progress.switchToDeterminate(workUnits);
}
}
/**
* Switches the progress bar to indeterminate mode. This should be called if
* the total work units to process the data source is unknown.
*/
public void switchToIndeterminate() {
if (progress != null) {
progress.switchToIndeterminate();
}
}
/**
* Updates the progress bar with the number of work units performed, if in
* the determinate mode.
*
* @param workUnits Number of work units performed so far by the module.
*/
public void progress(int workUnits) {
if (progress != null) {
progress.progress(dataSource.getName(), workUnits);
}
}
}

View File

@ -1,106 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import java.util.List;
import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.Content;
/**
* Represents a data source-level task to schedule and analyze.
* Children of the data will also be scheduled.
*
* @param T type of Ingest Module / Pipeline (file or data source content) associated with this task
*/
class DataSourceTask<T extends IngestModuleAbstract> {
private Content input;
private List<T> modules;
private boolean processUnallocated;
private PipelineContext<T> pipelineContext;
public DataSourceTask(Content input, List<T> modules, boolean processUnallocated) {
this.input = input;
this.modules = modules;
this.processUnallocated = processUnallocated;
pipelineContext = new PipelineContext(this);
}
public Content getContent() {
return input;
}
public PipelineContext<T> getPipelineContext() {
return pipelineContext;
}
public List<T> getModules() {
return modules;
}
/**
* Returns value of if unallocated space should be analyzed (and scheduled)
* @return True if pipeline should process unallocated space.
*/
boolean isProcessUnalloc() {
return processUnallocated;
}
// @@@ BC: I think this should go away.
void addModules(List<T> newModules) {
for (T newModule : newModules) {
if (!modules.contains(newModule)) {
modules.add(newModule);
}
}
}
@Override
public String toString() {
return NbBundle.getMessage(this.getClass(), "DataSourceTask.toString.text", input, modules);
}
/**
* Two scheduled tasks are equal when the content and modules are the same.
* This enables us not to enqueue the equal schedules tasks twice into the
* queue/set
*
* @param obj
* @return
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
@SuppressWarnings("unchecked")
final DataSourceTask<T> other = (DataSourceTask<T>) obj;
if (this.input != other.input && (this.input == null || !this.input.equals(other.input))) {
return false;
}
if (this.modules != other.modules && (this.modules == null || !this.modules.equals(other.modules))) {
return false;
}
return true;
}
}

View File

@ -1,15 +1,15 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012 Basis Technology Corp.
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -18,32 +18,18 @@
*/
package org.sleuthkit.autopsy.ingest;
import org.sleuthkit.datamodel.AbstractFile;
/**
*
* Context passed to a module at initialization time.
* It may contain module configuration required to initialize some modules.
* Interface that must be implemented by all file ingest modules.
*/
public class IngestModuleInit {
// private String moduleArgs;
public interface FileIngestModule extends IngestModule {
/**
* Get module arguments
* @return module args string, used by some modules
* Processes a file.
*
* @param file The file.
* @return A result code indicating success or failure of the processing.
*/
// public String getModuleArgs() {
// return moduleArgs;
// }
/**
* Sets module args. string (only used by module pipeline)
* @param moduleArgs arguments to set for the module
*/
// void setModuleArgs(String moduleArgs) {
// this.moduleArgs = moduleArgs;
// }
//
ProcessResult process(AbstractFile file);
}

View File

@ -1,213 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JPanel;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.datamodel.Content;
@ServiceProvider(service = IngestConfigurator.class)
public class GeneralIngestConfigurator implements IngestConfigurator {
public static final String ENABLED_INGEST_MODULES_KEY = "Enabled_Ingest_Modules";
public static final String DISABLED_INGEST_MODULES_KEY = "Disabled_Ingest_Modules";
public static final String PARSE_UNALLOC_SPACE_KEY = "Process_Unallocated_Space";
private List<Content> contentToIngest;
private IngestManager manager;
private IngestDialogPanel ingestDialogPanel;
private String moduleContext;
public GeneralIngestConfigurator() {
this.moduleContext = IngestManager.MODULE_PROPERTIES;
ingestDialogPanel = new IngestDialogPanel();
ingestDialogPanel.setContext(moduleContext);
manager = IngestManager.getDefault();
}
@Override
public List<String> setContext(String context) {
moduleContext = context;
ingestDialogPanel.setContext(moduleContext);
return loadSettingsForContext();
}
private List<String> loadSettingsForContext() {
List<String> messages = new ArrayList<>();
List<IngestModuleAbstract> allModules = IngestManager.getDefault().enumerateAllModules();
// If there is no enabled ingest modules setting for this user, default to enabling all
// of the ingest modules the IngestManager has loaded.
if (ModuleSettings.settingExists(moduleContext, ENABLED_INGEST_MODULES_KEY) == false) {
String defaultSetting = moduleListToCsv(allModules);
ModuleSettings.setConfigSetting(moduleContext, ENABLED_INGEST_MODULES_KEY, defaultSetting);
}
String[] enabledModuleNames = ModuleSettings.getConfigSetting(moduleContext, ENABLED_INGEST_MODULES_KEY).split(", ");
ArrayList<String> enabledList = new ArrayList<>(Arrays.asList(enabledModuleNames));
// Check for modules that are missing from the config file
String[] disabledModuleNames = null;
// Older config files won't have the disabled list, so don't assume it exists
if (ModuleSettings.settingExists(moduleContext, DISABLED_INGEST_MODULES_KEY)) {
disabledModuleNames = ModuleSettings.getConfigSetting(moduleContext, DISABLED_INGEST_MODULES_KEY).split(", ");
}
for (IngestModuleAbstract module : allModules) {
boolean found = false;
// Check enabled first
for (String moduleName : enabledModuleNames) {
if (module.getName().equals(moduleName)) {
found = true;
break;
}
}
// Then check disabled
if (!found && (disabledModuleNames != null)) {
for (String moduleName : disabledModuleNames) {
if (module.getName().equals(moduleName)) {
found = true;
break;
}
}
}
if (!found) {
enabledList.add(module.getName());
// It will get saved to file later
}
}
// Get the enabled ingest modules setting, check for missing modules, and pass the setting to
// the UI component.
List<IngestModuleAbstract> enabledModules = new ArrayList<>();
for (String moduleName : enabledList) {
if (moduleName.equals(
NbBundle.getMessage(this.getClass(), "GeneralIngestConfigurator.modName.tbirdParser.text"))
|| moduleName.equals(
NbBundle.getMessage(this.getClass(), "GeneralIngestConfigurator.modName.mboxParser.text"))) {
moduleName = NbBundle.getMessage(this.getClass(), "GeneralIngestConfigurator.modName.emailParser.text");
}
IngestModuleAbstract moduleFound = null;
for (IngestModuleAbstract module : allModules) {
if (moduleName.equals(module.getName())) {
moduleFound = module;
break;
}
}
if (moduleFound != null) {
enabledModules.add(moduleFound);
}
else {
messages.add(NbBundle.getMessage(this.getClass(), "GeneralIngestConfigurator.enabledMods.notFound.msg",
moduleName));
}
}
ingestDialogPanel.setEnabledIngestModules(enabledModules);
// If there is no process unallocated space flag setting, default it to false.
if (ModuleSettings.settingExists(moduleContext, PARSE_UNALLOC_SPACE_KEY) == false) {
ModuleSettings.setConfigSetting(moduleContext, PARSE_UNALLOC_SPACE_KEY, "false");
}
// Get the process unallocated space flag setting and pass it to the UI component.
boolean processUnalloc = Boolean.parseBoolean(ModuleSettings.getConfigSetting(moduleContext, PARSE_UNALLOC_SPACE_KEY));
ingestDialogPanel.setProcessUnallocSpaceEnabled(processUnalloc);
return messages;
}
@Override
public JPanel getIngestConfigPanel() {
// Note that this panel allows for selecting modules for the ingest process,
// specifying the process unallocated space flag, and also specifying settings
// for a selected ingest module.
return ingestDialogPanel;
}
@Override
public void save() {
// Save the user's configuration of the set of enabled ingest modules.
String enabledModulesCsvList = moduleListToCsv(ingestDialogPanel.getModulesToStart());
ModuleSettings.setConfigSetting(moduleContext, ENABLED_INGEST_MODULES_KEY, enabledModulesCsvList);
// Save the user's configuration of the set of disabled ingest modules.
String disabledModulesCsvList = moduleListToCsv(ingestDialogPanel.getDisabledModules());
ModuleSettings.setConfigSetting(moduleContext, DISABLED_INGEST_MODULES_KEY, disabledModulesCsvList);
// Save the user's setting for the process unallocated space flag.
String processUnalloc = Boolean.toString(ingestDialogPanel.processUnallocSpaceEnabled());
ModuleSettings.setConfigSetting(moduleContext, PARSE_UNALLOC_SPACE_KEY, processUnalloc);
// Save the user's configuration of the currently selected ingest module.
IngestModuleAbstract currentModule = ingestDialogPanel.getCurrentIngestModule();
if (currentModule != null && currentModule.hasSimpleConfiguration()) {
currentModule.saveSimpleConfiguration();
}
}
private static String moduleListToCsv(List<IngestModuleAbstract> lst) {
if (lst == null || lst.isEmpty()) {
return "";
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < lst.size() - 1; ++i) {
sb.append(lst.get(i).getName()).append(", ");
}
// and the last one
sb.append(lst.get(lst.size() - 1).getName());
return sb.toString();
}
@Override
public void setContent(List<Content> inputContent) {
this.contentToIngest = inputContent;
}
@Override
public void start() {
// Get the list of ingest modules selected by the user.
List<IngestModuleAbstract> modulesToStart = ingestDialogPanel.getModulesToStart();
// Get the user's selection of whether or not to process unallocated space.
manager.setProcessUnallocSpace(ingestDialogPanel.processUnallocSpaceEnabled());
if (!modulesToStart.isEmpty() && contentToIngest != null) {
// Queue the ingest process.
manager.scheduleDataSource(modulesToStart, contentToIngest);
}
}
@Override
public boolean isIngestRunning() {
return manager.isIngestRunning();
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -25,21 +25,17 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentVisitor;
import org.sleuthkit.datamodel.Directory;
import org.sleuthkit.datamodel.File;
import org.sleuthkit.datamodel.FileSystem;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.VirtualDirectory;
import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.datamodel.Volume;
import org.sleuthkit.datamodel.VolumeSystem;
import org.sleuthkit.datamodel.LayoutFile;
/**
* Abstract visitor for getting all the files from content
* TODO should be moved to utility module (needs resolve cyclic deps)
* Abstract visitor for getting all the files from content.
*/
abstract class GetFilesContentVisitor implements ContentVisitor<Collection<AbstractFile>> {
abstract class GetFilesContentVisitor implements ContentVisitor<Collection<AbstractFile>> {
private static final Logger logger = Logger.getLogger(GetFilesContentVisitor.class.getName());
@ -47,7 +43,7 @@ import org.sleuthkit.datamodel.LayoutFile;
public Collection<AbstractFile> visit(VirtualDirectory ld) {
return getAllFromChildren(ld);
}
@Override
public Collection<AbstractFile> visit(Directory drctr) {
return getAllFromChildren(drctr);
@ -69,13 +65,14 @@ import org.sleuthkit.datamodel.LayoutFile;
}
/**
* Aggregate all the matches from visiting the children Content objects of the
* one passed
* @param parent
* @return
* Aggregate all the matches from visiting the children Content objects of
* a parent Content object.
*
* @param parent A content object.
* @return The child files of the content.
*/
protected Collection<AbstractFile> getAllFromChildren(Content parent) {
Collection<AbstractFile> all = new ArrayList<AbstractFile>();
Collection<AbstractFile> all = new ArrayList<>();
try {
for (Content child : parent.getChildren()) {

View File

@ -1,84 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import java.util.List;
import javax.swing.JPanel;
import org.sleuthkit.datamodel.Content;
/**
* Instances of this class provide the following services:
* 1. A way to save and load the ingest process configuration settings for a
* given ingest process context.
* 2. A UI component for configuring ingest process settings.
* 3. A way to specify input content and start the ingest process for a
* given ingest process context.
*/
// @@@ This interface needs to be re-designed. An interface for allowing the
// authors of ingest modules to expose context sensitive module configuration
// settings needs to be provided; there also needs to be a way for users to
// configure the ingest process that uses those modules. These are separate
// concerns; likewise, kicking off an ingest process for particular content in
// a particular context is a separate concern.
public interface IngestConfigurator {
/**
* Specifies the ingest process context for the purpose of choosing, saving,
* and loading ingest process configuration settings; also determines what
* configuration settings will be in effect if the setContent() and start()
* methods are called to start the ingest process for some content specified
* using the setContent() method.
* @return A list, possibly empty, of messages describing errors that
* occurred when loading the configuration settings.
*/
public List<String> setContext(String contextName);
/**
* Provides a UI component for choosing ingest process configuration
* settings for the ingest process context specified using the setContext()
* method.
*/
JPanel getIngestConfigPanel();
/**
* Saves the ingest process configuration settings for the ingest process
* context specified using the setContext() method.
*/
void save();
/**
* Sets the input content for an ingest process prior to calling start() to
* run the process using the process configuration settings for the context
* specified using setContext().
*/
void setContent(List<Content> inputContent);
/**
* Starts (queues) the ingest process for the content specified using the
* setContent() method, using the configuration settings corresponding to
* the ingest process context specified using the setContext() method.
*/
void start();
/**
* Returns true if any ingest process is running, false otherwise.
* Note that the running process may or may not be the process started
* (queued) by an invocation of the start() method.
*/
boolean isIngestRunning();
}

View File

@ -1,188 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
//ingester worker for DataSource queue
import java.awt.EventQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.SwingWorker;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.util.Cancellable;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.StopWatch;
import org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstract.IngestModuleException;
import org.sleuthkit.datamodel.Content;
/**
* Worker thread that runs a data source-level ingest module (image, file set virt dir, etc).
* Used to process only a single data-source and single module.
*/
class IngestDataSourceThread extends SwingWorker<Void, Void> {
private final Logger logger = Logger.getLogger(IngestDataSourceThread.class.getName());
private ProgressHandle progress;
private final PipelineContext<IngestModuleDataSource>pipelineContext;
private final Content dataSource;
private final IngestModuleDataSource module;
private IngestDataSourceWorkerController controller;
private final IngestManager manager;
private final IngestModuleInit init;
private boolean inited;
//current method of enqueuing data source ingest modules with locks and internal lock queue
//ensures that we init, run and complete a single data source ingest module at a time
//uses fairness policy to run them in order enqueued
//TODO use a real queue and manager to allow multiple different modules to run in parallel
private static final Lock dataSourceIngestModuleLock = new ReentrantReadWriteLock(true).writeLock();
IngestDataSourceThread(IngestManager manager, PipelineContext<IngestModuleDataSource>pipelineContext, Content dataSource, IngestModuleDataSource module, IngestModuleInit init) {
this.manager = manager;
this.pipelineContext = pipelineContext;
this.dataSource = dataSource;
this.module = module;
this.init = init;
this.inited = false;
}
PipelineContext<IngestModuleDataSource>getContext() {
return pipelineContext;
}
Content getContent() {
return pipelineContext.getDataSourceTask().getContent();
}
IngestModuleDataSource getModule() {
return module;
}
public void init() throws IngestModuleException{
logger.log(Level.INFO, "Initializing module: " + module.getName());
try {
module.init(init);
inited = true;
} catch (IngestModuleException e) {
logger.log(Level.INFO, "Failed initializing module: " + module.getName() + ", will not run.");
//will not run
inited = false;
throw e;
}
}
@Override
protected Void doInBackground() throws Exception {
logger.log(Level.INFO, "Pending module: " + module.getName());
final String displayName = NbBundle.getMessage(this.getClass(), "IngestDataSourceThread.displayName.text",
module.getName(),
dataSource.getId());
progress = ProgressHandleFactory.createHandle(
NbBundle.getMessage(this.getClass(), "IngestDataSourceThread.progress.pending", displayName), new Cancellable() {
@Override
public boolean cancel() {
logger.log(Level.INFO, "DataSource ingest module " + module.getName() + " cancelled by user.");
if (progress != null) {
progress.setDisplayName(
NbBundle.getMessage(this.getClass(), "IngestDataSourceThread.progress.cancelling", displayName));
}
return IngestDataSourceThread.this.cancel(true);
}
});
progress.start();
progress.switchToIndeterminate();
dataSourceIngestModuleLock.lock();
try {
if (this.isCancelled()) {
logger.log(Level.INFO, "Cancelled while pending, module: " + module.getName());
return Void.TYPE.newInstance();
}
logger.log(Level.INFO, "Starting module: " + module.getName());
logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo());
progress.setDisplayName(displayName);
if (inited == false) {
logger.log(Level.INFO, "Module wasn't initialized, will not run: " + module.getName());
return Void.TYPE.newInstance();
}
logger.log(Level.INFO, "Starting processing of module: " + module.getName());
controller = new IngestDataSourceWorkerController(this, progress);
if (isCancelled()) {
logger.log(Level.INFO, "Terminating DataSource ingest module " + module.getName() + " due to cancellation.");
return Void.TYPE.newInstance();
}
final StopWatch timer = new StopWatch();
timer.start();
try {
module.process(pipelineContext, dataSource, controller);
} catch (Exception e) {
logger.log(Level.WARNING, "Exception in module: " + module.getName() + " DataSource: " + dataSource.getName(), e);
} finally {
timer.stop();
logger.log(Level.INFO, "Done processing of module: " + module.getName()
+ " took " + timer.getElapsedTimeSecs() + " secs. to process()");
//cleanup queues (worker and DataSource/module)
manager.removeDataSourceIngestWorker(this);
if (!this.isCancelled()) {
logger.log(Level.INFO, "Module " + module.getName() + " completed");
try {
module.complete();
} catch (Exception e) {
logger.log(Level.INFO, "Error completing the module " + module.getName(), e);
}
IngestManager.fireModuleEvent(IngestModuleEvent.COMPLETED.toString(), module.getName());
} else {
logger.log(Level.INFO, "Module " + module.getName() + " stopped");
try {
module.stop();
} catch (Exception e) {
logger.log(Level.INFO, "Error stopping the module" + module.getName(), e);
}
IngestManager.fireModuleEvent(IngestModuleEvent.STOPPED.toString(), module.getName());
}
}
return Void.TYPE.newInstance();
} finally {
//release the lock so next module can run
dataSourceIngestModuleLock.unlock();
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
progress.finish();
}
});
logger.log(Level.INFO, "Done running module: " + module.getName());
logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo());
}
}
}

View File

@ -1,80 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import org.netbeans.api.progress.ProgressHandle;
/**
* Controller for DataSource level ingest modules
* Used by modules to check task status and to post progress to
*/
public class IngestDataSourceWorkerController {
private IngestDataSourceThread worker;
private ProgressHandle progress;
/**
* Instantiate the controller for the worker
* @param worker underlying DataSource ingest thread
* @param progress the progress handle
*/
IngestDataSourceWorkerController(IngestDataSourceThread worker, ProgressHandle progress) {
this.worker = worker;
this.progress = progress;
}
/**
* Check if the task has been cancelled. This should be polled by the module periodically
* And the module needs to act, i.e. break out of its processing loop and call its stop() to cleanup
*
* @return true if the task has been cancelled, false otherwise
*/
public boolean isCancelled() {
return worker.isCancelled();
}
/**
* Update the progress bar and switch to determinate mode once number of total work units is known
* @param workUnits total number of work units for the DataSource ingest task
*/
public void switchToDeterminate(int workUnits) {
if (progress != null) {
progress.switchToDeterminate(workUnits);
}
}
/**
* Update the progress bar and switch to non determinate mode if number of work units is not known
*/
public void switchToInDeterminate() {
if (progress != null) {
progress.switchToIndeterminate();
}
}
/**
* Update the progress bar with the number of work units performed, if in the determinate mode
* @param workUnits number of work units performed so far by the module
*/
public void progress(int workUnits) {
if (progress != null) {
progress.progress(worker.getContent().getName(), workUnits);
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2013-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -25,6 +25,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JButton;
@ -32,24 +33,24 @@ import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.Content;
/**
* Dialog box that allows ingest modules to be run on an image.
* Used outside of the wizards.
* Dialog box that allows ingest modules to be run on a data source. Used
* outside of the wizards.
*/
public class IngestDialog extends JDialog {
public final class IngestDialog extends JDialog {
private static final String TITLE = NbBundle.getMessage(IngestDialog.class, "IngestDialog.title.text");
private static Dimension DIMENSIONS = new Dimension(500, 300);
private IngestConfigurator ingestConfigurator;
private List<Content> dataSources = new ArrayList<>();
private IngestJobLauncher ingestJobLauncher;
public IngestDialog(JFrame frame, String title, boolean modal) {
super(frame, title, modal);
ingestConfigurator = new GeneralIngestConfigurator();
List<String> messages = ingestConfigurator.setContext(IngestDialog.class.getCanonicalName());
ingestJobLauncher = new IngestJobLauncher(IngestDialog.class.getCanonicalName());
List<String> messages = ingestJobLauncher.getIngestJobConfigWarnings();
if (messages.isEmpty() == false) {
StringBuilder warning = new StringBuilder();
for (String message : messages) {
@ -58,8 +59,8 @@ public class IngestDialog extends JDialog {
JOptionPane.showMessageDialog(null, warning.toString());
}
}
public IngestDialog(){
public IngestDialog() {
this(new JFrame(TITLE), TITLE, true);
}
@ -78,51 +79,49 @@ public class IngestDialog extends JDialog {
// set the location of the popUp Window on the center of the screen
setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2);
add(ingestConfigurator.getIngestConfigPanel(), BorderLayout.PAGE_START);
add(ingestJobLauncher.getIngestJobConfigPanel(), BorderLayout.PAGE_START);
JButton startButton = new JButton(NbBundle.getMessage(this.getClass(), "IngestDialog.startButton.title"));
JButton closeButton = new JButton(NbBundle.getMessage(this.getClass(), "IngestDialog.closeButton.title"));
startButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ingestConfigurator.save();
ingestConfigurator.start();
ingestJobLauncher.saveIngestJobConfig();
ingestJobLauncher.startIngestJobs(dataSources);
close();
}
});
closeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ingestConfigurator.save();
ingestJobLauncher.saveIngestJobConfig();
close();
}
});
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
ingestConfigurator.save();
ingestJobLauncher.saveIngestJobConfig();
close();
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
buttonPanel.add(new javax.swing.Box.Filler(new Dimension(10,10), new Dimension(10,10), new Dimension(10,10)));
buttonPanel.add(new javax.swing.Box.Filler(new Dimension(10, 10), new Dimension(10, 10), new Dimension(10, 10)));
buttonPanel.add(startButton);
buttonPanel.add(new javax.swing.Box.Filler(new Dimension(10,10), new Dimension(10,10), new Dimension(10,10)));
buttonPanel.add(new javax.swing.Box.Filler(new Dimension(10, 10), new Dimension(10, 10), new Dimension(10, 10)));
buttonPanel.add(closeButton);
add(buttonPanel, BorderLayout.LINE_START);
pack();
setResizable(false);
setVisible(true);
}
public void setContent(List<Content> inputContent) {
ingestConfigurator.setContent(inputContent);
}
public void setDataSources(List<Content> inputContent) {
dataSources.clear();
dataSources.addAll(inputContent);
}
/**
* Closes the Ingest dialog
*/

View File

@ -0,0 +1,389 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.swing.SwingWorker;
import org.netbeans.api.progress.ProgressHandle;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
/**
* Encapsulates a data source and the ingest module pipelines to be used to
* ingest the data source.
*/
final class IngestJob {
private final long id;
private final Content dataSource;
private final List<IngestModuleTemplate> ingestModuleTemplates;
private final boolean processUnallocatedSpace;
private final HashMap<Long, FileIngestPipeline> fileIngestPipelines = new HashMap<>();
private final HashMap<Long, DataSourceIngestPipeline> dataSourceIngestPipelines = new HashMap<>();
private FileIngestPipeline initialFileIngestPipeline = null;
private DataSourceIngestPipeline initialDataSourceIngestPipeline = null;
private boolean cancelled;
IngestJob(long id, Content dataSource, List<IngestModuleTemplate> ingestModuleTemplates, boolean processUnallocatedSpace) {
this.id = id;
this.dataSource = dataSource;
this.ingestModuleTemplates = ingestModuleTemplates;
this.processUnallocatedSpace = processUnallocatedSpace;
this.cancelled = false;
}
long getId() {
return id;
}
Content getDataSource() {
return dataSource;
}
boolean shouldProcessUnallocatedSpace() {
return processUnallocatedSpace;
}
synchronized void cancel() {
cancelled = true;
}
synchronized boolean isCancelled() {
return cancelled;
}
synchronized List<IngestModuleError> startUpIngestPipelines() {
// Create a per thread instance of each pipeline type right now to make
// (reasonably) sure that the ingest modules can be started.
initialDataSourceIngestPipeline = new DataSourceIngestPipeline(this, ingestModuleTemplates);
initialFileIngestPipeline = new FileIngestPipeline(this, ingestModuleTemplates);
List<IngestModuleError> errors = new ArrayList<>();
errors.addAll(initialDataSourceIngestPipeline.startUp());
errors.addAll(initialFileIngestPipeline.startUp());
return errors;
}
synchronized DataSourceIngestPipeline getDataSourceIngestPipelineForThread(long threadId) {
DataSourceIngestPipeline pipeline;
if (initialDataSourceIngestPipeline != null) {
pipeline = initialDataSourceIngestPipeline;
initialDataSourceIngestPipeline = null;
dataSourceIngestPipelines.put(threadId, pipeline);
} else if (!dataSourceIngestPipelines.containsKey(threadId)) {
pipeline = new DataSourceIngestPipeline(this, ingestModuleTemplates);
pipeline.startUp();
dataSourceIngestPipelines.put(threadId, pipeline);
} else {
pipeline = dataSourceIngestPipelines.get(threadId);
}
return pipeline;
}
synchronized FileIngestPipeline getFileIngestPipelineForThread(long threadId) {
FileIngestPipeline pipeline;
if (initialFileIngestPipeline != null) {
pipeline = initialFileIngestPipeline;
initialFileIngestPipeline = null;
fileIngestPipelines.put(threadId, pipeline);
} else if (!fileIngestPipelines.containsKey(threadId)) {
pipeline = new FileIngestPipeline(this, ingestModuleTemplates);
pipeline.startUp();
fileIngestPipelines.put(threadId, pipeline);
} else {
pipeline = fileIngestPipelines.get(threadId);
}
return pipeline;
}
synchronized List<IngestModuleError> releaseIngestPipelinesForThread(long threadId) {
List<IngestModuleError> errors = new ArrayList<>();
DataSourceIngestPipeline dataSourceIngestPipeline = dataSourceIngestPipelines.get(threadId);
if (dataSourceIngestPipeline != null) {
errors.addAll(dataSourceIngestPipeline.shutDown(cancelled));
}
this.dataSourceIngestPipelines.remove(threadId);
FileIngestPipeline fileIngestPipeline = fileIngestPipelines.get(threadId);
if (fileIngestPipeline != null) {
errors.addAll(fileIngestPipeline.shutDown(cancelled));
}
this.fileIngestPipelines.remove(threadId);
return errors;
}
synchronized boolean areIngestPipelinesShutDown() {
return (dataSourceIngestPipelines.isEmpty() && fileIngestPipelines.isEmpty());
}
/**
* A data source ingest pipeline composed of a sequence of data source ingest
* modules constructed from ingest module templates.
*/
static final class DataSourceIngestPipeline {
private static final Logger logger = Logger.getLogger(DataSourceIngestPipeline.class.getName());
private final IngestJob task;
private final List<IngestModuleTemplate> moduleTemplates;
private List<DataSourceIngestModuleDecorator> modules = new ArrayList<>();
private DataSourceIngestPipeline(IngestJob task, List<IngestModuleTemplate> moduleTemplates) {
this.task = task;
this.moduleTemplates = moduleTemplates;
}
private List<IngestModuleError> startUp() {
List<IngestModuleError> errors = new ArrayList<>();
// Create an ingest module instance from each ingest module template
// that has an ingest module factory capable of making data source
// ingest modules. Map the module class names to the module instance
// to allow the modules to be put in the sequence indicated by the
// ingest pipelines configuration.
Map<String, DataSourceIngestModuleDecorator> modulesByClass = new HashMap<>();
for (IngestModuleTemplate template : moduleTemplates) {
if (template.isDataSourceIngestModuleTemplate()) {
DataSourceIngestModuleDecorator module = new DataSourceIngestModuleDecorator(template.createDataSourceIngestModule(), template.getModuleName());
IngestJobContext context = new IngestJobContext(task);
try {
module.startUp(context);
modulesByClass.put(module.getClassName(), module);
IngestManager.fireModuleEvent(IngestManager.IngestEvent.STARTED.toString(), module.getDisplayName());
} catch (Exception ex) {
errors.add(new IngestModuleError(module.getDisplayName(), ex));
}
}
}
// Establish the module sequence of the core ingest modules
// indicated by the ingest pipeline configuration, adding any
// additional modules found in the global lookup to the end of the
// pipeline in arbitrary order.
List<String> pipelineConfig = IngestPipelinesConfiguration.getInstance().getDataSourceIngestPipelineConfig();
for (String moduleClassName : pipelineConfig) {
if (modulesByClass.containsKey(moduleClassName)) {
modules.add(modulesByClass.remove(moduleClassName));
}
}
for (DataSourceIngestModuleDecorator module : modulesByClass.values()) {
modules.add(module);
}
return errors;
}
List<IngestModuleError> process(SwingWorker worker, ProgressHandle progress) {
List<IngestModuleError> errors = new ArrayList<>();
Content dataSource = this.task.getDataSource();
logger.log(Level.INFO, "Processing data source {0}", dataSource.getName());
for (DataSourceIngestModuleDecorator module : this.modules) {
try {
String displayName = NbBundle.getMessage(this.getClass(), "IngestJob.DataSourceIngestPipeline.displayName.text", module.getDisplayName(), dataSource.getName());
progress.setDisplayName(displayName);
module.process(dataSource, new DataSourceIngestModuleStatusHelper(worker, progress, dataSource));
} catch (Exception ex) {
errors.add(new IngestModuleError(module.getDisplayName(), ex));
}
if (task.isCancelled()) {
break;
}
}
return errors;
}
private List<IngestModuleError> shutDown(boolean ingestJobCancelled) {
List<IngestModuleError> errors = new ArrayList<>();
for (DataSourceIngestModuleDecorator module : this.modules) {
try {
module.shutDown(ingestJobCancelled);
} catch (Exception ex) {
errors.add(new IngestModuleError(module.getDisplayName(), ex));
} finally {
IngestManager.fireModuleEvent(IngestManager.IngestEvent.COMPLETED.toString(), module.getDisplayName());
}
}
return errors;
}
private static class DataSourceIngestModuleDecorator implements DataSourceIngestModule {
private final DataSourceIngestModule module;
private final String displayName;
DataSourceIngestModuleDecorator(DataSourceIngestModule module, String displayName) {
this.module = module;
this.displayName = displayName;
}
String getClassName() {
return module.getClass().getCanonicalName();
}
String getDisplayName() {
return displayName;
}
@Override
public void startUp(IngestJobContext context) throws IngestModuleException {
module.startUp(context);
}
@Override
public IngestModule.ProcessResult process(Content dataSource, DataSourceIngestModuleStatusHelper statusHelper) {
return module.process(dataSource, statusHelper);
}
@Override
public void shutDown(boolean ingestJobWasCancelled) {
module.shutDown(ingestJobWasCancelled);
}
}
}
/**
* A file ingest pipeline composed of a sequence of file ingest modules
* constructed from ingest module templates.
*/
static final class FileIngestPipeline {
private static final Logger logger = Logger.getLogger(FileIngestPipeline.class.getName());
private final IngestJob task;
private final List<IngestModuleTemplate> moduleTemplates;
private List<FileIngestModuleDecorator> modules = new ArrayList<>();
private FileIngestPipeline(IngestJob task, List<IngestModuleTemplate> moduleTemplates) {
this.task = task;
this.moduleTemplates = moduleTemplates;
}
private List<IngestModuleError> startUp() {
List<IngestModuleError> errors = new ArrayList<>();
// Create an ingest module instance from each ingest module template
// that has an ingest module factory capable of making data source
// ingest modules. Map the module class names to the module instance
// to allow the modules to be put in the sequence indicated by the
// ingest pipelines configuration.
Map<String, FileIngestModuleDecorator> modulesByClass = new HashMap<>();
for (IngestModuleTemplate template : moduleTemplates) {
if (template.isFileIngestModuleTemplate()) {
FileIngestModuleDecorator module = new FileIngestModuleDecorator(template.createFileIngestModule(), template.getModuleName());
IngestJobContext context = new IngestJobContext(task);
try {
module.startUp(context);
modulesByClass.put(module.getClassName(), module);
IngestManager.fireModuleEvent(IngestManager.IngestEvent.STARTED.toString(), template.getModuleName());
} catch (Exception ex) {
errors.add(new IngestModuleError(module.getDisplayName(), ex));
}
}
}
// Establish the module sequence of the core ingest modules
// indicated by the ingest pipeline configuration, adding any
// additional modules found in the global lookup to the end of the
// pipeline in arbitrary order.
List<String> pipelineConfig = IngestPipelinesConfiguration.getInstance().getFileIngestPipelineConfig();
for (String moduleClassName : pipelineConfig) {
if (modulesByClass.containsKey(moduleClassName)) {
modules.add(modulesByClass.remove(moduleClassName));
}
}
for (FileIngestModuleDecorator module : modulesByClass.values()) {
modules.add(module);
}
return errors;
}
List<IngestModuleError> process(AbstractFile file) {
List<IngestModuleError> errors = new ArrayList<>();
Content dataSource = this.task.getDataSource();
logger.log(Level.INFO, String.format("Processing {0} from {1}", file.getName(), dataSource.getName()));
for (FileIngestModuleDecorator module : this.modules) {
try {
module.process(file);
} catch (Exception ex) {
errors.add(new IngestModuleError(module.getDisplayName(), ex));
}
if (task.isCancelled()) {
break;
}
}
file.close();
IngestManager.fireFileDone(file.getId());
return errors;
}
private List<IngestModuleError> shutDown(boolean ingestJobCancelled) {
List<IngestModuleError> errors = new ArrayList<>();
for (FileIngestModuleDecorator module : this.modules) {
try {
module.shutDown(ingestJobCancelled);
} catch (Exception ex) {
errors.add(new IngestModuleError(module.getDisplayName(), ex));
} finally {
IngestManager.fireModuleEvent(IngestManager.IngestEvent.COMPLETED.toString(), module.getDisplayName());
}
}
return errors;
}
private static class FileIngestModuleDecorator implements FileIngestModule {
private final FileIngestModule module;
private final String displayName;
FileIngestModuleDecorator(FileIngestModule module, String displayName) {
this.module = module;
this.displayName = displayName;
}
String getClassName() {
return module.getClass().getCanonicalName();
}
String getDisplayName() {
return displayName;
}
@Override
public void startUp(IngestJobContext context) throws IngestModuleException {
module.startUp(context);
}
@Override
public IngestModule.ProcessResult process(AbstractFile file) {
return module.process(file);
}
@Override
public void shutDown(boolean ingestJobWasCancelled) {
module.shutDown(ingestJobWasCancelled);
}
}
}
}

View File

@ -134,7 +134,7 @@
<Component class="javax.swing.JButton" name="advancedButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/ingest/Bundle.properties" key="IngestDialogPanel.advancedButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/ingest/Bundle.properties" key="IngestJobConfigurationPanel.advancedButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
@ -201,10 +201,10 @@
<Component class="javax.swing.JCheckBox" name="processUnallocCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/ingest/Bundle.properties" key="IngestDialogPanel.processUnallocCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/ingest/Bundle.properties" key="IngestJobConfigurationPanel.processUnallocCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/ingest/Bundle.properties" key="IngestDialogPanel.processUnallocCheckbox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/ingest/Bundle.properties" key="IngestJobConfigurationPanel.processUnallocCheckbox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2013 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -23,10 +23,8 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
@ -35,62 +33,56 @@ import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationDialog;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
/**
* main configuration panel for all ingest modules, reusable JPanel component
* User interface component to allow a user to set ingest module options and
* enable/disable the modules.
*/
class IngestDialogPanel extends javax.swing.JPanel {
class IngestJobConfigurationPanel extends javax.swing.JPanel {
private IngestModuleAbstract currentModule;
private ModulesTableModel tableModel;
private String context;
private List<IngestModuleModel> modules = new ArrayList<>();
private boolean processUnallocatedSpace = false;
private IngestModuleModel selectedModule = null;
/**
* Creates new form IngestDialogPanel
*/
public IngestDialogPanel() {
tableModel = new ModulesTableModel();
context = ModuleSettings.DEFAULT_CONTEXT;
IngestJobConfigurationPanel(List<IngestModuleTemplate> moduleTemplates, boolean processUnallocatedSpace) {
for (IngestModuleTemplate moduleTemplate : moduleTemplates) {
modules.add(new IngestModuleModel(moduleTemplate));
}
this.processUnallocatedSpace = processUnallocatedSpace;
initComponents();
customizeComponents();
}
public void setContext(String context) {
this.context = context;
List<IngestModuleTemplate> getIngestModuleTemplates() {
List<IngestModuleTemplate> moduleTemplates = new ArrayList<>();
for (IngestModuleModel module : modules) {
IngestModuleTemplate moduleTemplate = module.getIngestModuleTemplate();
if (module.hasModuleSettingsPanel()) {
IngestModuleSettings settings = module.getModuleSettingsPanel().getSettings();
moduleTemplate.setModuleSettings(settings);
}
moduleTemplates.add(moduleTemplate);
}
return moduleTemplates;
}
public IngestModuleAbstract getCurrentIngestModule() {
return currentModule;
}
public List<IngestModuleAbstract> getModulesToStart() {
return tableModel.getSelectedModules();
}
public List<IngestModuleAbstract> getDisabledModules() {
return tableModel.getUnSelectedModules();
}
public boolean processUnallocSpaceEnabled() {
boolean getProcessUnallocSpace() {
return processUnallocCheckbox.isSelected();
}
private void customizeComponents() {
modulesTable.setModel(tableModel);
modulesTable.setModel(new IngestModulesTableModel());
modulesTable.setTableHeader(null);
modulesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
//custom renderer for tooltips
ModulesTableRenderer renderer = new ModulesTableRenderer();
//customize column witdhs
final int width = modulesScrollPane.getPreferredSize().width;
TableColumn column = null;
for (int i = 0; i < modulesTable.getColumnCount(); i++) {
column = modulesTable.getColumnModel().getColumn(i);
if (i == 0) {
// Set the column widths in the table model and add a custom cell
// renderer that will display module descriptions from the module models
// as tooltips.
IngestModulesTableRenderer renderer = new IngestModulesTableRenderer();
int width = modulesScrollPane.getPreferredSize().width;
for (int i = 0; i < modulesTable.getColumnCount(); ++i) {
TableColumn column = modulesTable.getColumnModel().getColumn(i);
if (0 == i) {
column.setPreferredWidth(((int) (width * 0.15)));
} else {
column.setCellRenderer(renderer);
@ -98,35 +90,28 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings;
}
}
// Add a selection listener to the table model that will display the
// ingest job options panel of the currently selected module model and
// enable or disable the resources configuration panel invocation button.
modulesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource();
if (!listSelectionModel.isSelectionEmpty()) {
int index = listSelectionModel.getMinSelectionIndex();
currentModule = tableModel.getModule(index);
// add the module-specific configuration panel, if there is one
selectedModule = modules.get(index);
simplePanel.removeAll();
if (currentModule.hasSimpleConfiguration()) {
simplePanel.add(currentModule.getSimpleConfiguration(context));
if (null != selectedModule.getModuleSettingsPanel()) {
simplePanel.add(selectedModule.getModuleSettingsPanel());
}
simplePanel.revalidate();
simplePanel.repaint();
advancedButton.setEnabled(currentModule.hasAdvancedConfiguration());
} else {
currentModule = null;
advancedButton.setEnabled(null != selectedModule.getGlobalSettingsPanel());
}
}
});
}
public void setProcessUnallocSpaceEnabled(final boolean enabled) {
processUnallocCheckbox.setSelected(enabled);
}
public void setEnabledIngestModules(List<IngestModuleAbstract> enabledModules) {
tableModel.setSelectedModules(enabledModules);
processUnallocCheckbox.setSelected(processUnallocatedSpace);
}
/**
@ -172,7 +157,7 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings;
jPanel1.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160)));
jPanel1.setPreferredSize(new java.awt.Dimension(338, 257));
advancedButton.setText(org.openide.util.NbBundle.getMessage(IngestDialogPanel.class, "IngestDialogPanel.advancedButton.text")); // NOI18N
advancedButton.setText(org.openide.util.NbBundle.getMessage(IngestJobConfigurationPanel.class, "IngestJobConfigurationPanel.advancedButton.text")); // NOI18N
advancedButton.setEnabled(false);
advancedButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -210,8 +195,8 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings;
processUnallocPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160)));
processUnallocCheckbox.setText(org.openide.util.NbBundle.getMessage(IngestDialogPanel.class, "IngestDialogPanel.processUnallocCheckbox.text")); // NOI18N
processUnallocCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(IngestDialogPanel.class, "IngestDialogPanel.processUnallocCheckbox.toolTipText")); // NOI18N
processUnallocCheckbox.setText(org.openide.util.NbBundle.getMessage(IngestJobConfigurationPanel.class, "IngestJobConfigurationPanel.processUnallocCheckbox.text")); // NOI18N
processUnallocCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(IngestJobConfigurationPanel.class, "IngestJobConfigurationPanel.processUnallocCheckbox.toolTipText")); // NOI18N
processUnallocCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
processUnallocCheckboxActionPerformed(evt);
@ -264,24 +249,29 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings;
private void advancedButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_advancedButtonActionPerformed
final AdvancedConfigurationDialog dialog = new AdvancedConfigurationDialog();
dialog.addApplyButtonListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (selectedModule.hasGlobalSettingsPanel()) {
selectedModule.saveResourcesConfig();
}
dialog.close();
currentModule.saveAdvancedConfiguration();
}
});
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
dialog.close();
}
});
dialog.display(currentModule.getAdvancedConfiguration(context));
dialog.display(selectedModule.getGlobalSettingsPanel());
}//GEN-LAST:event_advancedButtonActionPerformed
private void processUnallocCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_processUnallocCheckboxActionPerformed
// nothing to do here
processUnallocatedSpace = processUnallocCheckbox.isSelected();
}//GEN-LAST:event_processUnallocCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton advancedButton;
@ -296,20 +286,77 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings;
private javax.swing.ButtonGroup timeGroup;
// End of variables declaration//GEN-END:variables
private class ModulesTableModel extends AbstractTableModel {
private List<Map.Entry<IngestModuleAbstract, Boolean>>moduleData = new ArrayList<>();
/**
* A decorator for an ingest module template that adds ingest and global
* options panels with lifetimes equal to that of the ingest configuration
* panel.
*/
static private class IngestModuleModel {
public ModulesTableModel() {
List<IngestModuleAbstract> modules = IngestManager.getDefault().enumerateAllModules();
for (IngestModuleAbstract ingestModuleAbstract : modules) {
moduleData.add(new AbstractMap.SimpleEntry<>(ingestModuleAbstract, Boolean.TRUE));
private final IngestModuleTemplate moduleTemplate;
private IngestModuleGlobalSetttingsPanel globalSettingsPanel = null;
private IngestModuleSettingsPanel moduleSettingsPanel = null;
IngestModuleModel(IngestModuleTemplate moduleTemplate) {
this.moduleTemplate = moduleTemplate;
if (moduleTemplate.hasModuleSettingsPanel()) {
moduleSettingsPanel = moduleTemplate.getModuleSettingsPanel();
}
if (moduleTemplate.hasGlobalSettingsPanel()) {
globalSettingsPanel = moduleTemplate.getGlobalSettingsPanel();
}
}
IngestModuleTemplate getIngestModuleTemplate() {
return moduleTemplate;
}
String getName() {
return moduleTemplate.getModuleName();
}
String getDescription() {
return moduleTemplate.getModuleDescription();
}
void setEnabled(boolean enabled) {
moduleTemplate.setEnabled(enabled);
}
boolean isEnabled() {
return moduleTemplate.isEnabled();
}
boolean hasModuleSettingsPanel() {
return moduleTemplate.hasModuleSettingsPanel();
}
IngestModuleSettingsPanel getModuleSettingsPanel() {
return moduleSettingsPanel;
}
boolean hasGlobalSettingsPanel() {
return moduleTemplate.hasGlobalSettingsPanel();
}
IngestModuleGlobalSetttingsPanel getGlobalSettingsPanel() {
return globalSettingsPanel;
}
void saveResourcesConfig() {
globalSettingsPanel.saveSettings();
}
}
/**
* Custom table model to display ingest module names and enable/disable
* ingest modules.
*/
private class IngestModulesTableModel extends AbstractTableModel {
@Override
public int getRowCount() {
return moduleData.size();
return modules.size();
}
@Override
@ -319,11 +366,11 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings;
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Map.Entry<IngestModuleAbstract, Boolean> entry = moduleData.get(rowIndex);
IngestModuleModel module = modules.get(rowIndex);
if (columnIndex == 0) {
return entry.getValue();
return module.isEnabled();
} else {
return entry.getKey().getName();
return module.getName();
}
}
@ -335,7 +382,7 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings;
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex == 0) {
moduleData.get(rowIndex).setValue((Boolean)aValue);
modules.get(rowIndex).setEnabled((boolean) aValue);
}
}
@ -343,103 +390,26 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings;
public Class<?> getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
public List<IngestModuleAbstract> getSelectedModules() {
List<IngestModuleAbstract> selectedModules = new ArrayList<>();
for (Map.Entry<IngestModuleAbstract, Boolean> entry : moduleData) {
if (entry.getValue().booleanValue()) {
selectedModules.add(entry.getKey());
}
}
return selectedModules;
}
public List<IngestModuleAbstract> getUnSelectedModules() {
List<IngestModuleAbstract> unselectedModules = new ArrayList<>();
for (Map.Entry<IngestModuleAbstract, Boolean> entry : moduleData) {
if (!entry.getValue().booleanValue()) {
unselectedModules.add(entry.getKey());
}
}
return unselectedModules;
}
/**
* Sets the given modules as selected in the modules table
* @param selectedModules
*/
public void setSelectedModules(List<IngestModuleAbstract> selectedModules) {
// unselect all modules
for (Map.Entry<IngestModuleAbstract, Boolean> entry : moduleData) {
entry.setValue(Boolean.FALSE);
}
// select only the given modules
for (IngestModuleAbstract selectedModule : selectedModules) {
getEntryForModule(selectedModule).setValue(Boolean.TRUE);
}
// tell everyone about it
fireTableDataChanged();
}
/**
* Sets the given modules as NOT selected in the modules table
* @param selectedModules
*/
public void setUnselectedModules(List<IngestModuleAbstract> unselectedModules) {
// select all modules
for (Map.Entry<IngestModuleAbstract, Boolean> entry : moduleData) {
entry.setValue(Boolean.TRUE);
}
// unselect only the given modules
for (IngestModuleAbstract unselectedModule : unselectedModules) {
getEntryForModule(unselectedModule).setValue(Boolean.FALSE);
}
// tell everyone about it
fireTableDataChanged();
}
public IngestModuleAbstract getModule(int row) {
return moduleData.get(row).getKey();
}
private Map.Entry<IngestModuleAbstract, Boolean> getEntryForModule(IngestModuleAbstract module) {
Map.Entry<IngestModuleAbstract, Boolean> entry = null;
for (Map.Entry<IngestModuleAbstract, Boolean> anEntry : moduleData) {
if (anEntry.getKey().equals(module)) {
entry = anEntry;
break;
}
}
return entry;
}
}
/**
* Custom cell renderer for tool tips with module description
* Custom cell renderer to create tool tips displaying ingest module
* descriptions.
*/
private class ModulesTableRenderer extends DefaultTableCellRenderer {
private class IngestModulesTableRenderer extends DefaultTableCellRenderer {
List<String> tooltips = new ArrayList<>();
public ModulesTableRenderer() {
List<IngestModuleAbstract> modules = IngestManager.getDefault().enumerateAllModules();
for (IngestModuleAbstract ingestModuleAbstract : modules) {
tooltips.add(ingestModuleAbstract.getDescription());
public IngestModulesTableRenderer() {
for (IngestModuleModel moduleTemplate : modules) {
tooltips.add(moduleTemplate.getDescription());
}
}
@Override
public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (column == 1) {
if (1 == column) {
setToolTipText(tooltips.get(row));
}
return this;

View File

@ -0,0 +1,66 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import java.util.List;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Provides an instance of an ingest module with services specific to the ingest
* job and the ingest pipeline of which the module is a part.
*/
public final class IngestJobContext {
private final IngestJob ingestJob;
IngestJobContext(IngestJob ingestJob) {
this.ingestJob = ingestJob;
}
/**
* Gets the identifier of the ingest job associated with this context.
*
* @return The ingest job identifier.
*/
public long getJobId() {
return this.ingestJob.getId();
}
/**
* Determines whether the ingest job associated with the current context has
* been canceled.
*
* @return True if the job has been canceled, false otherwise.
*/
public boolean isJobCancelled() {
return this.ingestJob.isCancelled();
}
/**
* Adds one or more files to the files to be passed through the file ingest
* pipeline of the ingest job associated with the current context.
*
* @param files The files to be processed by the file ingest pipeline.
*/
public void addFilesToPipeline(List<AbstractFile> files) {
for (AbstractFile file : files) {
IngestManager.getDefault().scheduleFile(ingestJob.getId(), file);
}
}
}

View File

@ -0,0 +1,238 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import javax.swing.JPanel;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.datamodel.Content;
/**
* Provides a mechanism for creating and persisting an ingest job configuration
* for a particular context and for launching ingest jobs that process one or
* more data sources using the ingest job configuration.
*/
public final class IngestJobLauncher {
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 PARSE_UNALLOC_SPACE_KEY = "Process_Unallocated_Space";
private final String launcherContext;
private final List<String> warnings = new ArrayList<>();
private IngestJobConfigurationPanel ingestConfigPanel;
/**
* Constructs an ingest job launcher that creates and persists an ingest job
* configuration for a particular context and launches ingest jobs that
* process one or more data sources using the ingest job configuration.
*
* @param launcherContext The context identifier.
*/
public IngestJobLauncher(String launcherContext) {
this.launcherContext = launcherContext;
// Get the ingest module factories discovered by the ingest module
// loader.
List<IngestModuleFactory> moduleFactories = IngestModuleFactoryLoader.getInstance().getIngestModuleFactories();
HashSet<String> loadedModuleNames = new HashSet<>();
for (IngestModuleFactory moduleFactory : moduleFactories) {
loadedModuleNames.add(moduleFactory.getModuleDisplayName());
}
// Get the enabled and disabled ingest modules settings for the current
// context. Observe that the default settings make all loaded ingest
// modules enabled.
HashSet<String> enabledModuleNames = getModulesNamesFromSetting(ENABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(loadedModuleNames));
HashSet<String> disabledModuleNames = getModulesNamesFromSetting(DISABLED_INGEST_MODULES_KEY, "");
// Check for missing modules.
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);
warnings.add(String.format("Previously loaded %s module could not be found", moduleName));
}
// Create ingest module templates.
List<IngestModuleTemplate> moduleTemplates = new ArrayList<>();
for (IngestModuleFactory moduleFactory : moduleFactories) {
// NOTE: In the future, this code will be modified to get the
// module settings for the current context, if available, from
// storage; for now always use the defaults.
IngestModuleTemplate moduleTemplate = new IngestModuleTemplate(moduleFactory, moduleFactory.getDefaultModuleSettings());
String moduleName = moduleTemplate.getModuleName();
if (enabledModuleNames.contains(moduleName)) {
moduleTemplate.setEnabled(true);
} else if (disabledModuleNames.contains(moduleName)) {
moduleTemplate.setEnabled(true);
} else {
// The module factory was loaded, but the module name does not
// appear in the enabled/disabled module settings. Treat the
// module as a new module and enable it by default.
moduleTemplate.setEnabled(true);
enabledModuleNames.add(moduleName);
}
moduleTemplates.add(moduleTemplate);
}
// Update the enabled/disabled ingest module settings to reflect any
// missing modules or newly discovered modules.
ModuleSettings.setConfigSetting(launcherContext, ENABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(enabledModuleNames));
ModuleSettings.setConfigSetting(launcherContext, DISABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(disabledModuleNames));
// Get the process unallocated space flag setting. If the setting does
// not exist yet, default it to false.
if (ModuleSettings.settingExists(launcherContext, PARSE_UNALLOC_SPACE_KEY) == false) {
ModuleSettings.setConfigSetting(launcherContext, PARSE_UNALLOC_SPACE_KEY, "false");
}
boolean processUnallocatedSpace = Boolean.parseBoolean(ModuleSettings.getConfigSetting(launcherContext, PARSE_UNALLOC_SPACE_KEY));
// Make the configuration panel for the context.
ingestConfigPanel = new IngestJobConfigurationPanel(moduleTemplates, processUnallocatedSpace);
}
private HashSet<String> getModulesNamesFromSetting(String key, String defaultSetting) {
// Get the ingest modules setting from the user's config file.
// If there is no such setting yet, create the default setting.
if (ModuleSettings.settingExists(launcherContext, key) == false) {
ModuleSettings.setConfigSetting(launcherContext, key, defaultSetting);
}
HashSet<String> moduleNames = new HashSet<>();
String modulesSetting = ModuleSettings.getConfigSetting(launcherContext, key);
if (!modulesSetting.isEmpty()) {
String[] settingNames = modulesSetting.split(", ");
for (String name : settingNames) {
// Map some old core module names to the current core module names.
switch (name) {
case "Thunderbird Parser":
case "MBox Parser":
moduleNames.add("Email Parser");
break;
case "File Extension Mismatch Detection":
moduleNames.add("Extension Mismatch Detector");
break;
case "EWF Verify":
case "E01 Verify":
moduleNames.add("E01 Verifier");
break;
default:
moduleNames.add(name);
}
}
}
return moduleNames;
}
/**
* Gets any warnings generated when the persisted ingest job configuration
* for the specified context is retrieved and loaded.
*
* @return A collection of warning messages.
*/
public List<String> getIngestJobConfigWarnings() {
return warnings;
}
/**
* Gets the user interface panel the launcher uses to obtain the user's
* ingest job configuration for the specified context.
*
* @return A JPanel with components that can be used to create an ingest job
* configuration.
*/
public JPanel getIngestJobConfigPanel() {
return ingestConfigPanel;
}
/**
* Persists the ingest job configuration for the specified context.
*/
public void saveIngestJobConfig() {
List<IngestModuleTemplate> moduleTemplates = ingestConfigPanel.getIngestModuleTemplates();
// Save the enabled/disabled ingest module settings for the current context.
HashSet<String> enabledModuleNames = new HashSet<>();
HashSet<String> disabledModuleNames = new HashSet<>();
for (IngestModuleTemplate moduleTemplate : moduleTemplates) {
String moduleName = moduleTemplate.getModuleName();
if (moduleTemplate.isEnabled()) {
enabledModuleNames.add(moduleName);
} else {
disabledModuleNames.add(moduleName);
}
}
ModuleSettings.setConfigSetting(launcherContext, ENABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(enabledModuleNames));
ModuleSettings.setConfigSetting(launcherContext, DISABLED_INGEST_MODULES_KEY, makeCommaSeparatedList(disabledModuleNames));
// Save the process unallocated space setting for the current context.
String processUnalloc = Boolean.toString(ingestConfigPanel.getProcessUnallocSpace());
ModuleSettings.setConfigSetting(launcherContext, PARSE_UNALLOC_SPACE_KEY, processUnalloc);
// NOTE: In the future, this code will be modified to persist the ingest
// options for each ingest module for the current launch context.
}
private static String makeCommaSeparatedList(HashSet<String> input) {
if (input == null || input.isEmpty()) {
return "";
}
ArrayList<String> list = new ArrayList<>();
list.addAll(input);
StringBuilder csvList = new StringBuilder();
for (int i = 0; i < list.size() - 1; ++i) {
csvList.append(list.get(i)).append(", ");
}
csvList.append(list.get(list.size() - 1));
return csvList.toString();
}
/**
* Launches ingest jobs for one or more data sources using the ingest job
* configuration for the selected context.
*
* @param dataSources The data sources to ingest.
*/
public void startIngestJobs(List<Content> dataSources) {
// Filter out the disabled ingest module templates.
List<IngestModuleTemplate> enabledModuleTemplates = new ArrayList<>();
List<IngestModuleTemplate> moduleTemplates = ingestConfigPanel.getIngestModuleTemplates();
for (IngestModuleTemplate moduleTemplate : moduleTemplates) {
if (moduleTemplate.isEnabled()) {
enabledModuleTemplates.add(moduleTemplate);
}
}
if ((!enabledModuleTemplates.isEmpty()) && (dataSources != null) && (!dataSources.isEmpty())) {
IngestManager.getDefault().scheduleDataSourceTasks(dataSources, enabledModuleTemplates, ingestConfigPanel.getProcessUnallocSpace());
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.ingest;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -41,7 +40,7 @@ public class IngestMessage {
private long ID;
private MessageType messageType;
private IngestModuleAbstract source;
private String source;
private String subject;
private String detailsHtml;
private String uniqueKey;
@ -53,7 +52,7 @@ public class IngestMessage {
/**
* Private constructor used by factory methods
*/
private IngestMessage(long ID, MessageType messageType, IngestModuleAbstract source, String subject, String detailsHtml, String uniqueKey) {
private IngestMessage(long ID, MessageType messageType, String source, String subject, String detailsHtml, String uniqueKey) {
this.ID = ID;
this.source = source;
this.messageType = messageType;
@ -70,7 +69,7 @@ public class IngestMessage {
return ID;
}
public IngestModuleAbstract getSource() {
public String getSource() {
return source;
}
@ -105,7 +104,7 @@ public class IngestMessage {
sb.append(NbBundle.getMessage(this.getClass(), "IngestMessage.toString.type.text", messageType.name()));
if (source != null) //can be null for manager messages
{
sb.append(NbBundle.getMessage(this.getClass(), "IngestMessage.toString.source.text", source.getName()));
sb.append(source);
}
sb.append(
NbBundle.getMessage(this.getClass(), "IngestMessage.toString.date.text", dateFormat.format(datePosted)));
@ -176,7 +175,7 @@ public class IngestMessage {
* @param detailsHtml html formatted detailed message (without leading and closing &lt;html&gt; tags), for instance, a human-readable representation of the data. Or null.
* @return
*/
public static IngestMessage createMessage(long ID, MessageType messageType, IngestModuleAbstract source, String subject, String detailsHtml) {
public static IngestMessage createMessage(long ID, MessageType messageType, String source, String subject, String detailsHtml) {
if (messageType == null || source == null || subject == null) {
throw new IllegalArgumentException(
NbBundle.getMessage(IngestMessage.class, "IngestMessage.exception.typeSrcSubjNotNull.msg"));
@ -192,7 +191,7 @@ public class IngestMessage {
* @param subject message subject to be displayed
* @return
*/
public static IngestMessage createMessage(long ID, MessageType messageType, IngestModuleAbstract source, String subject) {
public static IngestMessage createMessage(long ID, MessageType messageType, String source, String subject) {
return createMessage(ID, messageType, source, subject, null);
}
@ -205,7 +204,7 @@ public class IngestMessage {
* @param detailsHtml html formatted detailed message (without leading and closing &lt;html&gt; tags), for instance, a human-readable representation of the data. Or null
* @return
*/
public static IngestMessage createErrorMessage(long ID, IngestModuleAbstract source, String subject, String detailsHtml) {
public static IngestMessage createErrorMessage(long ID, String source, String subject, String detailsHtml) {
if (source == null || subject == null) {
throw new IllegalArgumentException(
NbBundle.getMessage(IngestMessage.class, "IngestMessage.exception.srcSubjNotNull.msg"));
@ -221,7 +220,7 @@ public class IngestMessage {
* @param detailsHtml html formatted detailed message (without leading and closing &lt;html&gt; tags), for instance, a human-readable representation of the data. Or null
* @return
*/
public static IngestMessage createWarningMessage(long ID, IngestModuleAbstract source, String subject, String detailsHtml) {
public static IngestMessage createWarningMessage(long ID, String source, String subject, String detailsHtml) {
if (source == null || subject == null) {
throw new IllegalArgumentException(
NbBundle.getMessage(IngestMessage.class, "IngestMessage.exception.srcSubjNotNull.msg"));
@ -239,7 +238,7 @@ public class IngestMessage {
* @param data blackboard artifact associated with the message, the same as fired in ModuleDataEvent by the module
* @return
*/
public static IngestMessage createDataMessage(long ID, IngestModuleAbstract source, String subject, String detailsHtml, String uniqueKey, BlackboardArtifact data) {
public static IngestMessage createDataMessage(long ID, String source, String subject, String detailsHtml, String uniqueKey, BlackboardArtifact data) {
if (source == null || subject == null || detailsHtml == null || data == null) {
throw new IllegalArgumentException(
NbBundle.getMessage(IngestMessage.class, "IngestMessage.exception.srcSubjDetailsDataNotNull.msg"));

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -35,10 +35,8 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JTable;
@ -54,6 +52,7 @@ import javax.swing.table.TableCellRenderer;
import org.sleuthkit.autopsy.ingest.IngestMessage.*;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import java.util.logging.Level;
/**
* Notification window showing messages from modules to user
@ -260,7 +259,6 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
//this should be done at the end to make it easy to initialize before events are handled
tableModel.addTableModelListener(this);
}
@Override
@ -285,15 +283,12 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
}
}
public synchronized void addMessage(IngestMessage m) {
//final int origMsgUnreadUnique = tableModel.getNumberUnreadGroups();
tableModel.addMessage(m);
//update total individual messages count
++totalMessages;
final int newMsgUnreadUnique = tableModel.getNumberUnreadGroups();
try {
messagePcs.firePropertyChange(TOTAL_NUM_MESSAGES_CHANGED, 0, newMsgUnreadUnique);
@ -310,10 +305,6 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
this.totalMessagesNameVal.setText(Long.toString(totalMessages));
final int totalMessagesUnique = tableModel.getNumberGroups();
this.totalUniqueMessagesNameVal.setText(Integer.toString(totalMessagesUnique));
//this.unreadLabelVal.setText(Integer.toString(newMsgUnreadUnique));
//autoscroll
//messageTable.scrollRectToVisible(messageTable.getCellRect(messageTable.getRowCount() - 1, messageTable.getColumnCount(), true));
}
public synchronized void clearMessages() {
@ -342,7 +333,6 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
private synchronized void setVisited(int rowNumber) {
final int origMsgGroups = tableModel.getNumberUnreadGroups();
tableModel.setVisited(rowNumber);
//renderer.setSelected(rowNumber);
lastRowSelected = rowNumber;
try {
@ -381,9 +371,9 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
NbBundle.getMessage(this.getClass(), "IngestMessagePanel.MsgTableMod.colNames.new"),
NbBundle.getMessage(this.getClass(), "IngestMessagePanel.MsgTableMod.colNames.subject"),
NbBundle.getMessage(this.getClass(), "IngestMessagePanel.MsgTableMod.colNames.timestamp")};
private List<TableEntry> messageData = new ArrayList<TableEntry>();
private List<TableEntry> messageData = new ArrayList<>();
//for keeping track of messages to group, per module, by uniqness
private Map<IngestModuleAbstract, Map<String, List<IngestMessageGroup>>> groupings = new HashMap<IngestModuleAbstract, Map<String, List<IngestMessageGroup>>>();
private Map<String, Map<String, List<IngestMessageGroup>>> groupings = new HashMap<>();
private boolean chronoSort = true; //chronological sort default
private static final int MESSAGE_GROUP_THRESH = 3; //group messages after 3 messages per module with same uniqness
private Logger logger = Logger.getLogger(MessageTableModel.class.getName());
@ -393,18 +383,11 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
}
private void init() {
final IngestManager manager = IngestManager.getDefault();
//initialize groupings map with modules
for (IngestModuleAbstract module : manager.enumerateAbstractFileModules()) {
groupings.put(module, new HashMap<String, List<IngestMessageGroup>>());
}
for (IngestModuleAbstract module : manager.enumerateDataSourceModules()) {
groupings.put(module, new HashMap<String, List<IngestMessageGroup>>());
List<IngestModuleFactory> moduleFactories = IngestModuleFactoryLoader.getInstance().getIngestModuleFactories();
for (IngestModuleFactory factory : moduleFactories) {
groupings.put(factory.getModuleDisplayName(), new HashMap<String, List<IngestMessageGroup>>());
}
}
@Override
public int getColumnCount() {
@ -486,8 +469,7 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
switch (columnIndex) {
case 0:
Object module = entry.messageGroup.getSource();
ret = module == null ? "" : entry.messageGroup.getSource().getName();
ret = entry.messageGroup.getSource();
break;
case 1:
ret = entry.messageGroup.getCount();
@ -502,7 +484,7 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
ret = entry.messageGroup.getDatePosted();
break;
default:
logger.log(Level.SEVERE, "Invalid table column index: " + columnIndex);
logger.log(Level.SEVERE, "Invalid table column index: {0}", columnIndex);
break;
}
return ret;
@ -534,17 +516,17 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
synchronized public void addMessage(IngestMessage m) {
//check how many messages per module with the same uniqness
//and add to existing group or create a new group
IngestModuleAbstract module = m.getSource();
String moduleName = m.getSource();
IngestMessageGroup messageGroup = null;
if (module != null && m.getMessageType() == IngestMessage.MessageType.DATA) {
if (moduleName != null && m.getMessageType() == IngestMessage.MessageType.DATA) {
//not a manager message, a data message, then group
final Map<String, List<IngestMessageGroup>> groups = groupings.get(module);
final Map<String, List<IngestMessageGroup>> groups = groupings.get(moduleName);
//groups for this uniqueness
final String uniqueness = m.getUniqueKey();
List<IngestMessageGroup> uniqGroups = groups.get(uniqueness);
if (uniqGroups == null) {
//first one with this uniqueness
uniqGroups = new ArrayList<IngestMessageGroup>();
uniqGroups = new ArrayList<>();
messageGroup = new IngestMessageGroup(m);
uniqGroups.add(messageGroup);
groups.put(uniqueness, uniqGroups);
@ -565,7 +547,7 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
uniqGroups.add(messageGroup);
//remove all rows with this uniquness, new merged row will be added to the bottom
int toRemove = 0;
int toRemove;
while ((toRemove = getTableEntryIndex(uniqueness)) != -1) {
messageData.remove(toRemove);
//remove the row, will be added to the bottom
@ -715,7 +697,7 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
private List<IngestMessage> messages;
IngestMessageGroup(IngestMessage message) {
messages = new ArrayList<IngestMessage>();
messages = new ArrayList<>();
messages.add(message);
}
@ -768,7 +750,6 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
} else {
return LOW_PRI_COLOR;
}
}
/**
@ -798,7 +779,7 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
/*
* return source module, should be the same for all msgs
*/
IngestModuleAbstract getSource() {
String getSource() {
return messages.get(0).getSource();
}
@ -889,7 +870,6 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
return cell;
}
}
/**
@ -965,7 +945,6 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
return cell;
}
}
/**
@ -973,8 +952,6 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
*/
private class MessageVisitedSelection implements ListSelectionListener {
private Logger logger = Logger.getLogger(MessageVisitedSelection.class.getName());
@Override
public void valueChanged(ListSelectionEvent e) {
ListSelectionModel selModel = (ListSelectionModel) e.getSource();
@ -1003,7 +980,6 @@ class IngestMessagePanel extends JPanel implements TableModelListener {
}
messageTable.setCursor(null);
}
}
}
}

View File

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

View File

@ -1,191 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2012 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
/**
* Base interface for ingest modules
*/
public abstract class IngestModuleAbstract {
private String args;
/**
* Possible module types for the implementing classes
*/
public enum ModuleType {
/**
* DataSource type module
*/
DataSource,
/**
* AbstractFile type module
*/
AbstractFile
};
public class IngestModuleException extends Exception {
public IngestModuleException(String msg) {
super(msg);
}
}
/**
* Invoked every time an ingest session is started by the framework.
* A module should support multiple invocations of init() throughout the application life-cycle.
* In this method, the module should reinitialize its internal objects and resources and get them ready
* for a brand new ingest processing.
*
* Here are some things you may do in this method if you'll need them later.
* - Get a handle to the ingest services using org.sleuthkit.autopsy.ingest.IngestServices.getDefault().
* - Get the current case using org.sleuthkit.autopsy.ingest.IngestServices.getCurrentSleuthkitCaseDb().
*
* NEVER initialize IngestServices handle in the member declaration, because it might result
* in multiple instances of the singleton -- different class loaders are used in different modules.
* @param initContext context used to initialize some modules
*
* @throws IngestModuleException if a critical error occurs in initializing the module.
*/
abstract public void init(IngestModuleInit initContext) throws IngestModuleException;
/**
* Invoked when an ingest session completes.
* The module should perform any resource (files, handles, caches)
* cleanup in this method and submit final results and post a final ingest inbox message.
*/
abstract public void complete();
/**
* Invoked on a module when an ingest session is interrupted by the user or system.
* The method implementation should be similar to complete() in that the
* module should perform any cleanup work.
* If there is pending data to be processed or pending results to be reported by the module
* then the results should be rejected and ignored and the method should return as early as possible.
* It should ensure it is in a defined state so that ingest can be rerun later.
*/
abstract public void stop();
/**
* Returns unique name of the module. Should not have collisions.
* @return unique module name
*/
abstract public String getName();
/**
* Gets the module version
* @return module version string
*/
abstract public String getVersion();
/**
* Gets user-friendly description of the module
* @return module description
*/
abstract public String getDescription();
/**
* Returns type of the module (data source-level or file-level)
* @return module type
*/
abstract public ModuleType getType();
/**
* A module can manage and use additional threads to perform some work in the background.
* This method provides insight to the manager if the module has truly completed its work or not.
*
*
* @return true if any background threads/workers managed by this module are still running or are pending to be run,
* false if all work has been done, or if background threads are not used/managed by this module
*/
abstract public boolean hasBackgroundJobsRunning();
/**
* Used to determine if a module has implemented a simple (run-time)
* configuration panel that is displayed by the ingest manager.
*
* @return true if this module has a simple (run-time) configuration
*/
public boolean hasSimpleConfiguration() {
return false;
}
/**
* Used to determine if a module has implemented an advanced (general)
* configuration that can be used for more in-depth module configuration.
*
* @return true if this module has an advanced configuration
*/
public boolean hasAdvancedConfiguration() {
return false;
}
/**
* Called by the ingest manager if the simple (run-time) configuration
* panel should save its current state so that the settings can be used
* during the ingest.
*/
public void saveSimpleConfiguration() {}
/**
* If module implements advanced configuration panel
* it should read its current state and make it persistent / save it in this method
* so that the new configuration will be in effect during the ingest.
*/
public void saveAdvancedConfiguration() {}
/**
* Returns a panel that displays the simple (run-time) configuration for the
* given configuration context (such as pipeline instance). This is
* presented to the user before ingest starts and only basic settings should
* be given here. Use the advanced (general) configuration panel for more
* in-depth interfaces. The module (or its configuration controller object)
* is responsible for preserving / saving its configuration state In
* addition, saveSimpleConfiguration() can be used as the trigger.
*
* @param context the configuration context to use in the panel
* @return JPanel containing basic configuration widgets or null if simple
* configuration is not available
*/
public javax.swing.JPanel getSimpleConfiguration(String context) {
return null;
}
/**
* Returns a panel that displays the advanced (run-time) configuration for
* the given configuration context (such as pipeline instance). Implements
* advanced module configuration exposed to the user before ingest starts.
*
* The module (or its configuration controller object) is responsible for
* preserving / saving its configuration state In addition,
* saveAdvancedConfiguration() can be used as the trigger.
*
* @param context the configuration context to use in the panel
* @return JPanel containing advanced configuration widgets or null if
* advanced configuration is not available
*/
public javax.swing.JPanel getAdvancedConfiguration(String context) {
return null;
}
}

View File

@ -1,52 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Ingest module interface that will be called for every file in the data source Content
*/
public abstract class IngestModuleAbstractFile extends IngestModuleAbstract {
/**
* Return value resulting from processing AbstractFile
* If ERROR, can be used subsequent module
* in the pipeline as a hint to stop processing the file
*/
public enum ProcessResult {
OK, ///< Indicates that processing was successful (including if the file was largely ignored by the module)
ERROR, ///< Indicates that an error was encountered while processing the file, hint for later modules that depend on this module to skip processing the file due to error condition (such as file could not be read)
UNKNOWN ///< Indicates that a return value for the module is not known. This should not be returned directly by modules, but is used to indicate the module has not set its return value (e.g. it never ran)
};
@Override
public ModuleType getType() {
return ModuleType.AbstractFile;
}
/**
* Entry point to process file / directory by the module.
*
* @param pipelineContext the context in which the ingest runs (with its own settings, modules, etc)
* @param abstractFile file to process
* @return ProcessResult result of the processing that can be used in the pipeline as a hint whether to further process this file
*/
abstract public ProcessResult process(PipelineContext<IngestModuleAbstractFile>pipelineContext, AbstractFile abstractFile);
}

View File

@ -0,0 +1,34 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
/**
* An adapter that provides a default implementation of the IngestModule
* interface.
*/
public abstract class IngestModuleAdapter implements IngestModule {
@Override
public void startUp(IngestJobContext context) throws IngestModuleException {
}
@Override
public void shutDown(boolean ingestJobCancelled) {
}
}

View File

@ -1,52 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import org.sleuthkit.datamodel.Content;
/**
* Ingest module that acts on entire image or set of logical files.
* These modules are for analysis tasks that do not operate on all files in the disk image or set of logical files.
* A new instance of this module will be created for each data source that is added.
* Therefore, data source-level modules can assume that the process() method will be called at most once after init() is called.
*/
public abstract class IngestModuleDataSource extends IngestModuleAbstract {
@Override
public ModuleType getType() {
return ModuleType.DataSource;
}
/**
* Called with the data source Content object to analyze.
*
* Modules typically use FileManager to get specific files to analyze.
*
* Results should be posted to the blackboard.
* The module should also send messages to the ingest inbox with interesting events (data, errors, warnings, infos).
* The module notifies data viewers by firing events using IngestManagerProxy.fireModuleDataEvent
*
* The module will have its own progress bar while it is running and it should update it with the IngestDataSourceWorkerController object.
*
* @param pipelineContext Context in which the ingest pipeline is running (Settings, modules, etc)
* @param dataSource data source to process (such as Image, VirtualDirectory for logical files etc, etc)
* @param controller Used to update progress bar and to check if the task has been canceled.
*/
abstract public void process(PipelineContext<IngestModuleDataSource>pipelineContext, Content dataSource, IngestDataSourceWorkerController controller);
}

View File

@ -0,0 +1,41 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
/**
* Encapsulates an exception thrown by an ingest module during an operation such
* as startup or shut down with an exception object for the error that occurred.
*/
final class IngestModuleError {
private final String moduleDisplayName;
private final Exception error;
IngestModuleError(String moduleDisplayName, Exception error) {
this.moduleDisplayName = moduleDisplayName;
this.error = error;
}
String getModuleDisplayName() {
return this.moduleDisplayName;
}
Exception getModuleError() {
return this.error;
}
}

View File

@ -0,0 +1,216 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
/**
* An interface that must be implemented by all providers of ingest modules. An
* ingest module factory will be used to create instances of a type of data
* source ingest module, a type of file ingest module, or both.
* <P>
* IMPORTANT: The factory should be stateless to support context-sensitive use
* of the factory. The ingest framework is responsible for managing context
* switching and the persistence of resource configurations and per ingest job
* options.
* <p>
* IMPORTANT: The ingest framework will create one or more instances of each
* module type for each ingest job it performs. The ingest framework may use
* multiple threads to complete an ingest job, but it is guaranteed that there
* will be no more than one module instance per thread. However, if these
* instances must share resources, the modules are responsible for synchronizing
* access to the shared resources and doing reference counting as required to
* release those resources correctly.
* <p>
* IMPORTANT: To be discovered at runtime by the ingest framework,
* IngestModuleFactory implementations must be marked with the following
* NetBeans Service provider annotation:
*
* @ServiceProvider(service=IngestModuleFactory.class)
*/
public interface IngestModuleFactory {
/**
* Gets the display name that identifies the family of ingest modules the
* factory creates.
*
* @return The module family display name.
*/
String getModuleDisplayName();
/**
* Gets a brief, user-friendly description of the family of ingest modules
* the factory creates.
*
* @return The module family description.
*/
String getModuleDescription();
/**
* Gets the version number of the family of ingest modules the factory
* creates.
*
* @return The module family version number.
*/
String getModuleVersionNumber();
/**
* Queries the factory to determine if it provides user interface panels to
* configure resources to be used by instances of the family of ingest
* modules the factory creates. For example, the core hash lookup ingest
* module factory provides resource configuration panels to import and
* create hash databases. The hash databases are then enabled or disabled
* per ingest job using ingest job options panels. If the module family does
* not have a resources configuration, the factory should extend
* IngestModuleFactoryAdapter to get an implementation of this method that
* returns false.
*
* @return True if the factory provides resource configuration panels.
*/
boolean hasGlobalSettingsPanel();
/**
* Gets a user interface panel that can be used to configure resources for
* instances of the family of ingest modules the factory creates. For
* example, the core hash lookup ingest module factory provides a resource
* configuration panel to import and create hash databases. The imported
* hash databases are then enabled or disabled per ingest job using ingest
* options panels. If the module family does not have a resources
* configuration, the factory should extend IngestModuleFactoryAdapter to
* get an implementation of this method that throws an
* UnsupportedOperationException.
* <p>
* IMPORTANT: The ingest framework assumes that ingest module factories are
* stateless to support context-sensitive use of the factory, with the
* ingest framework managing context switching and the persistence of
* resource configurations and per ingest job options. A factory should not
* retain references to the resources configuration panels it creates.
*
* @param resourcesConfig A resources configuration with which to initialize
* the panel.
* @return A user interface panel for configuring ingest module resources.
*/
IngestModuleGlobalSetttingsPanel getGlobalSettingsPanel();
/**
* Gets the default per ingest job options for instances of the family of
* ingest modules the factory creates. For example, the core hash lookup
* ingest modules family has a resources configuration consisting of hash
* databases, all of which are enabled by default for an ingest job. If the
* module family does not have per ingest job options, the factory should
* extend IngestModuleFactoryAdapter to get an implementation of this method
* that returns an instance of the NoIngestJobOptions class.
*
* @return The ingest options.
*/
IngestModuleSettings getDefaultModuleSettings();
/**
* Queries the factory to determine if it provides user interface panels to
* set per ingest job options for instances of the family of ingest modules
* the factory creates. For example, the core hash lookup ingest module
* factory provides ingest options panels to enable or disable hash
* databases per ingest job. If the module family does not have per ingest
* job options, the factory should extend IngestModuleFactoryAdapter to get
* an implementation of this method that returns false.
*
* @return True if the factory provides ingest job options panels.
*/
boolean hasModuleSettingsPanel();
/**
* Gets a user interface panel that can be used to set per ingest job
* options for instances of the family of ingest modules the factory
* creates. For example, the core hash lookup ingest module factory provides
* ingest options panels to enable or disable hash databases per ingest job.
* If the module family does not have ingest job options, the factory should
* extend IngestModuleFactoryAdapter to get an implementation of this method
* that throws an UnsupportedOperationException.
* <p>
* IMPORTANT: The ingest framework assumes that ingest module factories are
* stateless to support context-sensitive use of the factory. The ingest
* framework is responsible for managing context switching and the
* persistence of resource configurations and per ingest job options. A
* factory should not retain references to the ingest job options panels it
* creates.
*
* @param resourcesConfig
* @param ingestOptions Per ingest job options to initialize the panel.
* @return A user interface panel.
*/
IngestModuleSettingsPanel getModuleSettingsPanel(IngestModuleSettings settings);
/**
* Queries the factory to determine if it is capable of creating file ingest
* modules.
*
* @return True if the factory can create file ingest modules.
*/
boolean isDataSourceIngestModuleFactory();
/**
* Creates a data source ingest module instance.
* <p>
* IMPORTANT: The factory should be stateless to support context-sensitive
* use of the factory. The ingest framework is responsible for managing
* context switching and the persistence of resource configurations and per
* ingest job options. A factory should not retain references to the data
* source ingest module instances it creates.
* <p>
* IMPORTANT: The ingest framework will create one or more data source
* ingest module instances for each ingest job it performs. The ingest
* framework may use multiple threads to complete an ingest job, but it is
* guaranteed that there will be no more than one module instance per
* thread. However, if these instances must share resources, the modules are
* responsible for synchronizing access to the shared resources and doing
* reference counting as required to release those resources correctly.
*
* @param ingestOptions The ingest options for the module instance.
* @return A data source ingest module instance.
*/
DataSourceIngestModule createDataSourceIngestModule(IngestModuleSettings settings);
/**
* Queries the factory to determine if it is capable of creating file ingest
* module instances.
*
* @return True if the factory can create file ingest module instances.
*/
boolean isFileIngestModuleFactory();
/**
* Creates a file ingest module instance.
* <p>
* IMPORTANT: The factory should be stateless to support context-sensitive
* use of the factory. The ingest framework is responsible for managing
* context switching and the persistence of resource configurations and per
* ingest job options. A factory should not retain references to the file
* ingest module instances it creates.
* <p>
* IMPORTANT: The ingest framework will create one or more file ingest
* module instances for each ingest job it performs. The ingest framework
* may use multiple threads to complete an ingest job, but it is guaranteed
* that there will be no more than one module instance per thread. However,
* if these instances must share resources, the modules are responsible for
* synchronizing access to the shared resources and doing reference counting
* as required to release those resources correctly.
*
* @param ingestOptions The ingest options for the module instance.
* @return A file ingest module instance.
*/
FileIngestModule createFileIngestModule(IngestModuleSettings settings);
}

View File

@ -0,0 +1,80 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
/**
* An adapter that provides no-op implementations of various IngestModuleFactory
* methods.
*/
public abstract class IngestModuleFactoryAdapter implements IngestModuleFactory {
@Override
public abstract String getModuleDisplayName();
@Override
public abstract String getModuleDescription();
@Override
public abstract String getModuleVersionNumber();
@Override
public boolean hasGlobalSettingsPanel() {
return false;
}
@Override
public IngestModuleGlobalSetttingsPanel getGlobalSettingsPanel() {
throw new UnsupportedOperationException();
}
@Override
public IngestModuleSettings getDefaultModuleSettings() {
return new NoIngestModuleSettings();
}
@Override
public boolean hasModuleSettingsPanel() {
return false;
}
@Override
public IngestModuleSettingsPanel getModuleSettingsPanel(IngestModuleSettings ingestOptions) {
throw new UnsupportedOperationException();
}
@Override
public boolean isDataSourceIngestModuleFactory() {
return false;
}
@Override
public DataSourceIngestModule createDataSourceIngestModule(IngestModuleSettings ingestOptions) {
throw new UnsupportedOperationException();
}
@Override
public boolean isFileIngestModuleFactory() {
return false;
}
@Override
public FileIngestModule createFileIngestModule(IngestModuleSettings ingestOptions) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,62 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.logging.Level;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Looks up loaded ingest module factories using the NetBean global lookup.
*/
final class IngestModuleFactoryLoader {
private static final Logger logger = Logger.getLogger(IngestModuleFactoryLoader.class.getName());
private static IngestModuleFactoryLoader instance;
private IngestModuleFactoryLoader() {
}
synchronized static IngestModuleFactoryLoader getInstance() {
if (instance == null) {
instance = new IngestModuleFactoryLoader();
}
return instance;
}
synchronized List<IngestModuleFactory> getIngestModuleFactories() {
List<IngestModuleFactory> moduleFactories = new ArrayList<>();
HashSet<String> moduleDisplayNames = new HashSet<>();
Collection<? extends IngestModuleFactory> factories = Lookup.getDefault().lookupAll(IngestModuleFactory.class);
for (IngestModuleFactory factory : factories) {
logger.log(Level.INFO, "Found ingest module factory: name = {0}, version = {1}", new Object[]{factory.getModuleDisplayName(), factory.getModuleVersionNumber()});
if (!moduleDisplayNames.contains(factory.getModuleDisplayName())) {
moduleFactories.add(factory);
moduleDisplayNames.add(factory.getModuleDisplayName());
} else {
logger.log(Level.SEVERE, "Found duplicate ingest module display name, discarding ingest module factory (name = {0}", new Object[]{factory.getModuleDisplayName(), factory.getModuleVersionNumber()});
}
}
return new ArrayList<>(moduleFactories);
}
}

View File

@ -0,0 +1,29 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import javax.swing.JPanel;
/**
* Base class for ingest module resources configuration panels.
*/
public abstract class IngestModuleGlobalSetttingsPanel extends JPanel {
public abstract void saveSettings();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import java.io.Serializable;
/**
* Interface for per ingest job options for ingest modules. Options are
* serializable to support persistence of options between invocations of the
* application.
*/
public interface IngestModuleSettings extends Serializable {
}

View File

@ -0,0 +1,34 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import javax.swing.JPanel;
/**
* Abstract base class for ingest module job settings panels.
*/
public abstract class IngestModuleSettingsPanel extends JPanel {
/**
* Gets the ingest job settings for an ingest module.
*
* @return The ingest settings.
*/
public abstract IngestModuleSettings getSettings();
}

View File

@ -0,0 +1,91 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
/**
* Combines an ingest module factory with ingest module settings and an enabled
* flag to create a template for creating fully configured ingest modules.
*/
final class IngestModuleTemplate {
private final IngestModuleFactory moduleFactory;
private IngestModuleSettings settings = null;
private boolean enabled = true;
IngestModuleTemplate(IngestModuleFactory moduleFactory, IngestModuleSettings settings) {
this.moduleFactory = moduleFactory;
this.settings = settings;
}
String getModuleName() {
return moduleFactory.getModuleDisplayName();
}
String getModuleDescription() {
return moduleFactory.getModuleDescription();
}
IngestModuleSettings getModuleSettings() {
return settings;
}
void setModuleSettings(IngestModuleSettings settings) {
this.settings = settings;
}
boolean hasModuleSettingsPanel() {
return moduleFactory.hasModuleSettingsPanel();
}
IngestModuleSettingsPanel getModuleSettingsPanel() {
return moduleFactory.getModuleSettingsPanel(settings);
}
boolean hasGlobalSettingsPanel() {
return moduleFactory.hasGlobalSettingsPanel();
}
IngestModuleGlobalSetttingsPanel getGlobalSettingsPanel() {
return moduleFactory.getGlobalSettingsPanel();
}
boolean isDataSourceIngestModuleTemplate() {
return moduleFactory.isDataSourceIngestModuleFactory();
}
DataSourceIngestModule createDataSourceIngestModule() {
return moduleFactory.createDataSourceIngestModule(settings);
}
boolean isFileIngestModuleTemplate() {
return moduleFactory.isFileIngestModuleFactory();
}
FileIngestModule createFileIngestModule() {
return moduleFactory.createFileIngestModule(settings);
}
void setEnabled(boolean enabled) {
this.enabled = enabled;
}
boolean isEnabled() {
return enabled;
}
}

View File

@ -38,14 +38,14 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
/**
* Monitor health of the system and stop ingest if necessary
*/
public class IngestMonitor {
public final class IngestMonitor {
public static final int DISK_FREE_SPACE_UNKNOWN = -1;
private static final int INITIAL_INTERVAL_MS = 60000; //1 min.
private final Logger logger = Logger.getLogger(IngestMonitor.class.getName());
private Timer timer;
private static final java.util.logging.Logger MONITOR_LOGGER = java.util.logging.Logger.getLogger("monitor");
private MonitorAction monitor;
public static final int DISK_FREE_SPACE_UNKNOWN = -1;
IngestMonitor() {
@ -166,7 +166,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
MONITOR_LOGGER.log(Level.SEVERE, "Stopping ingest due to low disk space on disk " + diskPath);
logger.log(Level.SEVERE, "Stopping ingest due to low disk space on disk " + diskPath);
manager.stopAll();
manager.postMessage(IngestMessage.createManagerErrorMessage(
IngestServices.getDefault().postMessage(IngestMessage.createManagerErrorMessage(
NbBundle.getMessage(this.getClass(), "IngestMonitor.mgrErrMsg.lowDiskSpace.title", diskPath),
NbBundle.getMessage(this.getClass(), "IngestMonitor.mgrErrMsg.lowDiskSpace.msg", diskPath)));
}

View File

@ -0,0 +1,137 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.XMLUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Provides data source and file ingest pipeline configurations as ordered lists
* of ingest module class names. The order of the module class names indicates
* the desired sequence of ingest module instances in an ingest modules
* pipeline.
*/
final class IngestPipelinesConfiguration {
private static final Logger logger = Logger.getLogger(IngestPipelinesConfiguration.class.getName());
private final static String PIPELINES_CONFIG_FILE = "pipeline_config.xml";
private final static String PIPELINES_CONFIG_FILE_XSD = "PipelineConfigSchema.xsd";
private static final String XML_PIPELINE_ELEM = "PIPELINE";
private static final String XML_PIPELINE_TYPE_ATTR = "type";
private final static String DATA_SOURCE_INGEST_PIPELINE_TYPE = "ImageAnalysis";
private final static String FILE_INGEST_PIPELINE_TYPE = "FileAnalysis";
private static final String XML_MODULE_ELEM = "MODULE";
private static final String XML_MODULE_CLASS_NAME_ATTR = "location";
private static IngestPipelinesConfiguration instance;
private final List<String> dataSourceIngestPipelineConfig = new ArrayList<>();
private final List<String> fileIngestPipelineConfig = new ArrayList<>();
private IngestPipelinesConfiguration() {
readPipelinesConfigurationFile();
}
synchronized static IngestPipelinesConfiguration getInstance() {
if (instance == null) {
Logger.getLogger(IngestPipelinesConfiguration.class.getName()).log(Level.INFO, "Creating ingest module loader instance");
instance = new IngestPipelinesConfiguration();
}
return instance;
}
List<String> getDataSourceIngestPipelineConfig() {
return new ArrayList<>(dataSourceIngestPipelineConfig);
}
List<String> getFileIngestPipelineConfig() {
return new ArrayList<>(fileIngestPipelineConfig);
}
private void readPipelinesConfigurationFile() {
try {
PlatformUtil.extractResourceToUserConfigDir(IngestPipelinesConfiguration.class, PIPELINES_CONFIG_FILE);
} catch (IOException ex) {
logger.log(Level.SEVERE, "Error copying default pipeline configuration to user dir", ex);
return;
}
String configFilePath = PlatformUtil.getUserConfigDirectory() + File.separator + PIPELINES_CONFIG_FILE;
Document doc = XMLUtil.loadDoc(IngestPipelinesConfiguration.class, configFilePath, PIPELINES_CONFIG_FILE_XSD);
if (doc == null) {
return;
}
Element rootElement = doc.getDocumentElement();
if (rootElement == null) {
logger.log(Level.SEVERE, "Invalid pipelines config file");
return;
}
NodeList pipelineElements = rootElement.getElementsByTagName(XML_PIPELINE_ELEM);
int numPipelines = pipelineElements.getLength();
if (numPipelines < 1 || numPipelines > 2) {
logger.log(Level.SEVERE, "Invalid pipelines config file");
return;
}
List<String> pipelineConfig = null;
for (int pipelineNum = 0; pipelineNum < numPipelines; ++pipelineNum) {
Element pipelineElement = (Element) pipelineElements.item(pipelineNum);
String pipelineTypeAttr = pipelineElement.getAttribute(XML_PIPELINE_TYPE_ATTR);
if (pipelineTypeAttr != null) {
switch (pipelineTypeAttr) {
case DATA_SOURCE_INGEST_PIPELINE_TYPE:
pipelineConfig = dataSourceIngestPipelineConfig;
break;
case FILE_INGEST_PIPELINE_TYPE:
pipelineConfig = fileIngestPipelineConfig;
break;
default:
logger.log(Level.SEVERE, "Invalid pipelines config file");
return;
}
}
// Create an ordered list of class names. The sequence of class
// names defines the sequence of modules in the pipeline.
if (pipelineConfig != null) {
NodeList modulesElems = pipelineElement.getElementsByTagName(XML_MODULE_ELEM);
int numModules = modulesElems.getLength();
if (numModules == 0) {
break;
}
for (int moduleNum = 0; moduleNum < numModules; ++moduleNum) {
Element moduleElement = (Element) modulesElems.item(moduleNum);
final String moduleClassName = moduleElement.getAttribute(XML_MODULE_CLASS_NAME_ATTR);
if (moduleClassName != null) {
pipelineConfig.add(moduleClassName);
}
}
}
}
}
}

View File

@ -31,9 +31,8 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.ingest.IngestScheduler.FileScheduler.FileTask;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentVisitor;
@ -51,21 +50,21 @@ import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
import org.sleuthkit.datamodel.TskData.TSK_FS_META_TYPE_ENUM;
/**
* Schedules data source (images, file-sets, etc) and files with their associated modules for ingest, and
* manage queues of the scheduled tasks.
* Schedules data source (images, file-sets, etc) and files with their
* associated modules for ingest, and manage queues of the scheduled tasks.
*
* Currently a singleton object only (as there is one pipeline at a time)
*
* Contains internal schedulers for content objects into data source and and file ingest
* pipelines.
* Contains internal schedulers for content objects into data source and and
* file ingest pipelines.
*
*/
class IngestScheduler {
final class IngestScheduler {
private static IngestScheduler instance;
private static final Logger logger = Logger.getLogger(IngestScheduler.class.getName());
private final DataSourceScheduler dataSourceScheduler = new DataSourceScheduler();
private final FileScheduler fileScheduler = new FileScheduler();
private IngestScheduler() {
}
@ -102,64 +101,125 @@ class IngestScheduler {
*
*/
static class FileScheduler implements Iterator<FileScheduler.FileTask> {
//root folders enqueued
private TreeSet<FileTask> rootProcessTasks;
//root folders enqueued
private TreeSet<FileTask> rootDirectoryTasks;
//stack of current dirs to be processed recursively
private List<FileTask> curDirProcessTasks;
private List<FileTask> directoryTasks;
//list of files being processed in the currently processed directory
private LinkedList<FileTask> curFileProcessTasks; //need to add to start and end quickly
private LinkedList<FileTask> fileTasks; //need to add to start and end quickly
//estimated total files to be enqueued for currently scheduled content objects
private int filesEnqueuedEst;
private int filesDequeued;
private final static int FAT_NTFS_FLAGS =
TskData.TSK_FS_TYPE_ENUM.TSK_FS_TYPE_FAT12.getValue()
//estimated total files to be enqueued for currently scheduled content objects
private int filesEnqueuedEst = 0;
private int filesDequeued = 0;
private final static int FAT_NTFS_FLAGS = TskData.TSK_FS_TYPE_ENUM.TSK_FS_TYPE_FAT12.getValue()
| TskData.TSK_FS_TYPE_ENUM.TSK_FS_TYPE_FAT16.getValue()
| TskData.TSK_FS_TYPE_ENUM.TSK_FS_TYPE_FAT32.getValue()
| TskData.TSK_FS_TYPE_ENUM.TSK_FS_TYPE_NTFS.getValue();
private FileScheduler() {
rootProcessTasks = new TreeSet<>(new RootTaskComparator());
curDirProcessTasks = new ArrayList<>();
curFileProcessTasks = new LinkedList<>();
resetCounters();
rootDirectoryTasks = new TreeSet<>(new RootTaskComparator());
directoryTasks = new ArrayList<>();
fileTasks = new LinkedList<>();
resetCounters();
}
private void resetCounters() {
filesEnqueuedEst = 0;
filesDequeued = 0;
}
}
@Override
public synchronized String toString() {
StringBuilder sb = new StringBuilder();
sb.append(NbBundle.getMessage(this.getClass(), "IngestScheduler.FileSched.toString.rootDirs.text",
rootProcessTasks.size()));
for (FileTask task : rootProcessTasks) {
sb.append("\nRootDirs(sorted), size: ").append(rootDirectoryTasks.size());
for (FileTask task : rootDirectoryTasks) {
sb.append(task.toString()).append(" ");
}
sb.append(NbBundle.getMessage(this.getClass(), "IngestScheduler.FileSched.toString.curDirs.text",
curDirProcessTasks.size()));
for (FileTask task : curDirProcessTasks) {
sb.append("\nCurDirs(stack), size: ").append(directoryTasks.size());
for (FileTask task : directoryTasks) {
sb.append(task.toString()).append(" ");
}
sb.append(NbBundle.getMessage(this.getClass(), "IngestScheduler.FileSched.toString.curFiles.text",
curFileProcessTasks.size()));
for (FileTask task : curFileProcessTasks) {
sb.append("\nCurFiles, size: ").append(fileTasks.size());
for (FileTask task : fileTasks) {
sb.append(task.toString()).append(" ");
}
return sb.toString();
}
synchronized void scheduleIngestOfFiles(IngestJob dataSourceTask) {
Content dataSource = dataSourceTask.getDataSource();
Collection<AbstractFile> rootObjects = dataSource.accept(new GetRootDirVisitor());
List<AbstractFile> firstLevelFiles = new ArrayList<>();
if (rootObjects.isEmpty() && dataSource instanceof AbstractFile) {
// The data source is file.
firstLevelFiles.add((AbstractFile)dataSource);
}
else {
for (AbstractFile root : rootObjects) {
List<Content> children;
try {
children = root.getChildren();
if (children.isEmpty()) {
//add the root itself, could be unalloc file, child of volume or image
firstLevelFiles.add(root);
}
else {
//root for fs root dir, schedule children dirs/files
for (Content child : children) {
if (child instanceof AbstractFile) {
firstLevelFiles.add((AbstractFile) child);
}
}
}
}
catch (TskCoreException ex) {
logger.log(Level.WARNING, "Could not get children of root to enqueue: " + root.getId() + ": " + root.getName(), ex);
}
}
}
for (AbstractFile firstLevelFile : firstLevelFiles) {
FileTask fileTask = new FileTask(firstLevelFile, dataSourceTask);
if (shouldEnqueueTask(fileTask)) {
rootDirectoryTasks.add(fileTask);
}
}
// Update approx count of files to process in queues
filesEnqueuedEst = queryNumFilesinEnqueuedContents();
// Reshuffle/update the dir and file level queues if needed
updateQueues();
}
/**
* Schedule a file to the file ingest, with associated modules. This
* will add the file to beginning of the file queue. The method is
* intended for rescheduling a file that is a derivative of another
* content object that has already ingested and produced this file. As a
* result, the derivative file will be scheduled with the same priority
* as the parent origin file.
*
* @param file file to be scheduled
* @param originalContext original content schedule context that was used
* to schedule the parent origin content, with the modules, settings, etc.
*/
synchronized void scheduleFile(IngestJob ingestJob, AbstractFile file) {
FileTask fileTask = new FileTask(file, ingestJob);
if (shouldEnqueueTask(fileTask)) {
fileTasks.addFirst(fileTask);
fileTasks.add(fileTask);
++filesEnqueuedEst;
}
}
float getPercentageDone() {
if (filesEnqueuedEst == 0) {
return 0;
}
return ((100.f) * filesDequeued) / filesEnqueuedEst;
}
/**
@ -203,230 +263,12 @@ class IngestScheduler {
int getFilesDequeued() {
return filesDequeued;
}
/**
* Task for a specific file to process. More specific than the
* higher-level DataSourceTask.
*/
static class FileTask {
private final AbstractFile file;
private final DataSourceTask dataSourceTask;
public FileTask(AbstractFile file, DataSourceTask dataSourceTask) {
this.file = file;
this.dataSourceTask = dataSourceTask;
}
public DataSourceTask getDataSourceTask() {
return dataSourceTask;
}
public AbstractFile getFile() {
return file;
}
@Override
public String toString() {
try {
return NbBundle.getMessage(this.getClass(), "IngestScheduler.fileTask.toString.long", file.getId(),
file.getUniquePath()); // + ", dataSourceTask=" + dataSourceTask + '}';
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Cound not get unique path of file in queue, ", ex);
}
return NbBundle.getMessage(this.getClass(), "IngestScheduler.fileTask.toString.short", file.getId(),
file.getName());
}
/**
* two process tasks are equal when the file/dir and modules are the
* same this enables are not to queue up the same file/dir, modules
* tuples into the root dir set
*
* @param obj
* @return
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final FileTask other = (FileTask) obj;
if (this.file != other.file && (this.file == null || !this.file.equals(other.file))) {
return false;
}
DataSourceTask<IngestModuleAbstractFile> thisTask = this.getDataSourceTask();
DataSourceTask<IngestModuleAbstractFile> otherTask = other.getDataSourceTask();
if (thisTask != otherTask
&& (thisTask == null || !thisTask.equals(otherTask))) {
return false;
}
return true;
}
/**
* Create 1 or more ProcessTasks for each root dir in the Content from
* the context supplied
*
* @param context the original ingest context
* @return
*/
private static List<FileTask> createFromScheduledTask(DataSourceTask<IngestModuleAbstractFile> scheduledTask) {
final Content scheduledContent = scheduledTask.getContent();
Collection<AbstractFile> rootObjects = scheduledContent.accept(new GetRootDirVisitor());
List<AbstractFile> firstLevelFiles = new ArrayList<>();
if (rootObjects.isEmpty() && scheduledContent instanceof AbstractFile) {
//add the root, which is a leaf itself
firstLevelFiles.add((AbstractFile) scheduledContent);
} else {
for (AbstractFile root : rootObjects) {
//TODO the type-specific AbstractFile getChildren() method
List<Content> children;
try {
children = root.getChildren();
if (children.isEmpty()) {
//add the root itself, could be unalloc file, child of volume or image
firstLevelFiles.add(root);
} else {
//root for fs root dir, schedule children dirs/files
for (Content child : children) {
if (child instanceof AbstractFile) {
firstLevelFiles.add((AbstractFile) child);
}
}
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Could not get children of root to enqueue: "
+ root.getId() + ": " + root.getName(), ex);
}
}
}
List<FileTask> processTasks = new ArrayList<>();
for (AbstractFile firstLevelFile : firstLevelFiles) {
FileTask newTask = new FileTask(firstLevelFile, scheduledTask);
if (shouldEnqueueTask(newTask)) {
processTasks.add(newTask);
}
}
return processTasks;
}
}
/**
* Remove duplicated tasks from previous ingest enqueue currently it
* removes all previous tasks scheduled in queues for this Content
*
* @param task tasks similar to this one should be removed
*/
private void removeDupTasks(DataSourceTask task) {
final Content inputContent = task.getContent();
//remove from root queue
List<FileTask> toRemove = new ArrayList<>();
for (FileTask pt : rootProcessTasks) {
if (pt.getDataSourceTask().getContent().equals(inputContent)) {
toRemove.add(pt);
}
}
rootProcessTasks.removeAll(toRemove);
//remove from dir stack
toRemove = new ArrayList<>();
for (FileTask pt : curDirProcessTasks) {
if (pt.getDataSourceTask().getContent().equals(inputContent)) {
toRemove.add(pt);
}
}
curDirProcessTasks.removeAll(toRemove);
//remove from file queue
toRemove = new ArrayList<>();
for (FileTask pt : curFileProcessTasks) {
if (pt.getDataSourceTask().getContent().equals(inputContent)) {
toRemove.add(pt);
}
}
curFileProcessTasks.removeAll(toRemove);
}
/**
* Schedule a file to the file ingest, with associated modules. This
* will add the file to beginning of the file queue. The method is
* intended for rescheduling a file that is a derivative of another
* content object that has already ingested and produced this file. As a
* result, the derivative file will be scheduled with the same priority
* as the parent origin file.
*
* @param file file to be scheduled
* @param originalContext original content schedule context that was used
* to schedule the parent origin content, with the modules, settings, etc.
*/
synchronized void schedule(AbstractFile file, PipelineContext<IngestModuleAbstractFile> originalContext) {
DataSourceTask<IngestModuleAbstractFile> originalTask = originalContext.getDataSourceTask();
//skip if task contains no modules
if (originalTask.getModules().isEmpty()) {
return;
}
FileTask fileTask = new FileTask(file, originalContext.getDataSourceTask());
if (shouldEnqueueTask(fileTask)) {
this.curFileProcessTasks.addFirst(fileTask);
++filesEnqueuedEst;
}
}
/**
* Schedule new Content object for a file ingest with associated
* modules.
*
* @param context context to schedule, with scheduled task containing content to process and modules
*/
synchronized void schedule(DataSourceTask<IngestModuleAbstractFile> task) {
//skip if task contains no modules
if (task.getModules().isEmpty()) {
return;
}
final Content contentToSchedule = task.getContent();
if (getSourceContent().contains(contentToSchedule)) {
//reset counters if the same content enqueued twice
//Note, not very accurate, because we may have processed some files from
//another content
this.filesDequeued = 0;
}
//remove duplicate scheduled tasks still in queues for this content if enqueued previously
removeDupTasks(task);
List<FileTask> rootTasks = FileTask.createFromScheduledTask(task);
//adds and resorts the tasks
this.rootProcessTasks.addAll(rootTasks);
//update approx count of files to process in queues
this.filesEnqueuedEst = this.queryNumFilesinEnqueuedContents();
//reshuffle/update the dir and file level queues if needed
updateQueues();
}
@Override
public synchronized boolean hasNext() {
if (curFileProcessTasks.isEmpty()) {
resetCounters();
if (fileTasks.isEmpty()) {
filesEnqueuedEst = 0;
filesDequeued = 0;
return false;
}
return true;
@ -435,12 +277,11 @@ class IngestScheduler {
@Override
public synchronized FileTask next() {
if (!hasNext()) {
throw new IllegalStateException(
NbBundle.getMessage(this.getClass(), "IngestScheduler.FileTask.next.exception.msg"));
throw new IllegalStateException("No next ProcessTask, check hasNext() first!");
}
//dequeue the last in the list
final FileTask task = curFileProcessTasks.pollLast();
final FileTask task = fileTasks.pollLast();
filesDequeued++;
updateQueues();
@ -457,28 +298,28 @@ class IngestScheduler {
// that do not get enqueued
while (true) {
// There are files in the queue, we're done
if (this.curFileProcessTasks.isEmpty() == false) {
if (this.fileTasks.isEmpty() == false) {
return;
}
// fill in the directory queue if it is empty.
if (this.curDirProcessTasks.isEmpty()) {
if (this.directoryTasks.isEmpty()) {
// bail out if root is also empty -- we are done
if (rootProcessTasks.isEmpty()) {
if (rootDirectoryTasks.isEmpty()) {
return;
}
FileTask rootTask = this.rootProcessTasks.pollFirst();
curDirProcessTasks.add(rootTask);
FileTask rootTask = this.rootDirectoryTasks.pollFirst();
directoryTasks.add(rootTask);
}
//pop and push AbstractFile directory children if any
//add the popped and its leaf children onto cur file list
FileTask parentTask = curDirProcessTasks.remove(curDirProcessTasks.size() - 1);
FileTask parentTask = directoryTasks.remove(directoryTasks.size() - 1);
final AbstractFile parentFile = parentTask.file;
// add itself to the file list
if (shouldEnqueueTask(parentTask)) {
this.curFileProcessTasks.addLast(parentTask);
this.fileTasks.addLast(parentTask);
}
// add its children to the file and directory lists
@ -487,13 +328,13 @@ class IngestScheduler {
for (Content c : children) {
if (c instanceof AbstractFile) {
AbstractFile childFile = (AbstractFile) c;
FileTask childTask = new FileTask(childFile, parentTask.getDataSourceTask());
FileTask childTask = new FileTask(childFile, parentTask.getJob());
if (childFile.hasChildren()) {
this.curDirProcessTasks.add(childTask);
this.directoryTasks.add(childTask);
}
else if (shouldEnqueueTask(childTask)) {
this.curFileProcessTasks.addLast(childTask);
this.fileTasks.addLast(childTask);
}
}
}
@ -506,8 +347,7 @@ class IngestScheduler {
@Override
public void remove() {
throw new UnsupportedOperationException(
NbBundle.getMessage(this.getClass(), "IngestScheduler.remove.exception.notSupported.msg"));
throw new UnsupportedOperationException("Not supported.");
}
/**
@ -520,61 +360,25 @@ class IngestScheduler {
* enqueued
*/
synchronized List<Content> getSourceContent() {
final Set<Content> contentSet = new HashSet<Content>();
final Set<Content> contentSet = new HashSet<>();
for (FileTask task : rootProcessTasks) {
contentSet.add(task.getDataSourceTask().getContent());
for (FileTask task : rootDirectoryTasks) {
contentSet.add(task.getJob().getDataSource());
}
for (FileTask task : curDirProcessTasks) {
contentSet.add(task.getDataSourceTask().getContent());
for (FileTask task : directoryTasks) {
contentSet.add(task.getJob().getDataSource());
}
for (FileTask task : curFileProcessTasks) {
contentSet.add(task.getDataSourceTask().getContent());
for (FileTask task : fileTasks) {
contentSet.add(task.getJob().getDataSource());
}
return new ArrayList<Content>(contentSet);
}
/**
* Determine if a module is in a pipeline in the queue.
* @param module
* @return true if it is in the queue.
*/
synchronized boolean hasModuleEnqueued(IngestModuleAbstractFile module) {
for (FileTask task : rootProcessTasks) {
List<IngestModuleAbstractFile> modules = task.getDataSourceTask().getModules();
for (IngestModuleAbstractFile m : modules) {
if (m.getName().equals(module.getName())) {
return true;
}
}
}
for (FileTask task : curDirProcessTasks) {
List<IngestModuleAbstractFile> modules = task.getDataSourceTask().getModules();
for (IngestModuleAbstractFile m : modules) {
if (m.getName().equals(module.getName())) {
return true;
}
}
}
for (FileTask task : curFileProcessTasks) {
List<IngestModuleAbstractFile> modules = task.getDataSourceTask().getModules();
for (IngestModuleAbstractFile m : modules) {
if (m.getName().equals(module.getName())) {
return true;
}
}
}
return false;
return new ArrayList<>(contentSet);
}
synchronized void empty() {
this.rootProcessTasks.clear();
this.curDirProcessTasks.clear();
this.curFileProcessTasks.clear();
this.rootDirectoryTasks.clear();
this.directoryTasks.clear();
this.fileTasks.clear();
}
/**
@ -588,7 +392,7 @@ class IngestScheduler {
final AbstractFile aFile = processTask.file;
//if it's unalloc file, skip if so scheduled
if (processTask.getDataSourceTask().isProcessUnalloc() == false
if (processTask.getJob().shouldProcessUnallocatedSpace() == false
&& aFile.getType().equals(TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS //unalloc files
)) {
return false;
@ -642,6 +446,70 @@ class IngestScheduler {
return true;
}
/**
* Task for a specific file to process. More specific than the
* higher-level DataSourceTask.
*/
static class FileTask {
private final AbstractFile file;
private final IngestJob task;
public FileTask(AbstractFile file, IngestJob task) {
this.file = file;
this.task = task;
}
public IngestJob getJob() {
return task;
}
public AbstractFile getFile() {
return file;
}
@Override
public String toString() {
try {
return "ProcessTask{" + "file=" + file.getId() + ": "
+ file.getUniquePath() + "}"; // + ", dataSourceTask=" + dataSourceTask + '}';
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Cound not get unique path of file in queue, ", ex);
}
return "ProcessTask{" + "file=" + file.getId() + ": "
+ file.getName() + '}';
}
/**
* two process tasks are equal when the file/dir and modules are the
* same this enables are not to queue up the same file/dir, modules
* tuples into the root dir set
*
* @param obj
* @return
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final FileTask other = (FileTask) obj;
if (this.file != other.file && (this.file == null || !this.file.equals(other.file))) {
return false;
}
IngestJob thisTask = this.getJob();
IngestJob otherTask = other.getJob();
if (thisTask != otherTask
&& (thisTask == null || !thisTask.equals(otherTask))) {
return false;
}
return true;
}
}
/**
* Root dir sorter
*/
@ -888,61 +756,36 @@ class IngestScheduler {
/**
* DataSourceScheduler ingest scheduler
*/
static class DataSourceScheduler implements Iterator<DataSourceTask<IngestModuleDataSource>> {
static class DataSourceScheduler implements Iterator<IngestJob> {
private LinkedList<DataSourceTask<IngestModuleDataSource>> tasks;
private LinkedList<IngestJob> tasks;
DataSourceScheduler() {
tasks = new LinkedList<DataSourceTask<IngestModuleDataSource>>();
tasks = new LinkedList<>();
}
synchronized void schedule(DataSourceTask<IngestModuleDataSource> task) {
//skip if task contains no modules
if (task.getModules().isEmpty()) {
return;
}
synchronized void schedule(IngestJob task) {
try {
if (task.getContent().getParent() != null) {
if (task.getDataSource().getParent() != null) {
//only accepting parent-less content objects (Image, parentless VirtualDirectory)
logger.log(Level.SEVERE, "Only parent-less Content (data sources) can be scheduled for DataSource ingest, skipping: " + task.getContent());
logger.log(Level.SEVERE, "Only parent-less Content (data sources) can be scheduled for DataSource ingest, skipping: {0}", task.getDataSource());
return;
}
} catch (TskCoreException e) {
logger.log(Level.SEVERE, "Error validating data source to be scheduled for DataSource ingest" + task.getContent(), e);
logger.log(Level.SEVERE, "Error validating data source to be scheduled for DataSource ingest" + task.getDataSource(), e);
return;
}
// see if we already have a task for this data source
DataSourceTask<IngestModuleDataSource> existTask = null;
for (DataSourceTask<IngestModuleDataSource> curTask : tasks) {
if (curTask.getContent().equals(task.getContent())) {
existTask = curTask;
break;
}
}
// add these modules to the existing task for the data source
// @@@ BC: I'm not sure I like this and it will probably break a more formal pipeline structure
// @@@ TODO: Verify that if this is called mid-way during ingest that all of the already ingested files get scheduled with the new modules...
if (existTask != null) {
//merge modules for the data source task
existTask.addModules(task.getModules());
} else {
//enqueue a new task
tasks.addLast(task);
}
tasks.addLast(task);
}
@Override
public synchronized DataSourceTask<IngestModuleDataSource> next() throws IllegalStateException {
public synchronized IngestJob next() throws IllegalStateException {
if (!hasNext()) {
throw new IllegalStateException(
NbBundle.getMessage(this.getClass(), "IngestScheduler.DataSourceScheduler.exception.next.msg"));
throw new IllegalStateException("There is no data source tasks in the queue, check hasNext()");
}
final DataSourceTask<IngestModuleDataSource> ret = tasks.pollFirst();
final IngestJob ret = tasks.pollFirst();
return ret;
}
@ -953,8 +796,8 @@ class IngestScheduler {
*/
synchronized List<org.sleuthkit.datamodel.Content> getContents() {
List<org.sleuthkit.datamodel.Content> contents = new ArrayList<org.sleuthkit.datamodel.Content>();
for (DataSourceTask<IngestModuleDataSource> task : tasks) {
contents.add(task.getContent());
for (IngestJob task : tasks) {
contents.add(task.getDataSource());
}
return contents;
}
@ -966,8 +809,7 @@ class IngestScheduler {
@Override
public void remove() {
throw new UnsupportedOperationException(
NbBundle.getMessage(this.getClass(), "IngestScheduler.DataSourceScheduler.exception.remove.msg"));
throw new UnsupportedOperationException("Removing of scheduled data source ingest tasks is not supported. ");
}
synchronized void empty() {
@ -981,12 +823,11 @@ class IngestScheduler {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(NbBundle.getMessage(this.getClass(), "IngestScheduler.DataSourceScheduler.toString.size",
getCount()));
for (DataSourceTask<IngestModuleDataSource> task : tasks) {
sb.append("DataSourceQueue, size: ").append(getCount());
for (IngestJob task : tasks) {
sb.append(task.toString()).append(" ");
}
return sb.toString();
}
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2013 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -16,8 +16,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import java.util.Map;
@ -28,27 +26,25 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.SleuthkitCase;
/**
* Singleton class that provides services for ingest modules.
* These exist to make it easier to write modules. Use the getDefault()
* method to get the singleton instance.
* Singleton class that provides services for ingest modules. These exist to
* make it easier to write modules. Use the getDefault() method to get the
* singleton instance.
*/
public class IngestServices {
public final class IngestServices {
private static final Logger logger = Logger.getLogger(IngestServices.class.getName());
private IngestManager manager;
private Logger logger = Logger.getLogger(IngestServices.class.getName());
private static IngestServices instance;
private IngestServices() {
this.manager = IngestManager.getDefault();
}
/**
* Get handle to singletone module services
* @return the services handle
* Get the ingest services.
*
* @return The ingest services singleton.
*/
public static synchronized IngestServices getDefault() {
if (instance == null) {
@ -56,117 +52,90 @@ public class IngestServices {
}
return instance;
}
/**
* Get access to the current Case handle.
* Note: When storing the Case database handle as a member variable in a module,
* this method needs to be called within the module's init() method and the
* member variable needs to be updated at each init(),
* to ensure the correct Case handle is being used if the Case is changed.
*
* @return current Case
* Get the current Autopsy case.
*
* @return The current case.
*/
public Case getCurrentCase() {
return Case.getCurrentCase();
}
/**
* Get access to the current Case database handle. Like storing
* the Case handle, call this method and update member variables for each
* call to the module's init() method to ensure it is correct.
*
* @return current Case database
/**
* Get the current SleuthKit case. The SleuthKit case is the case database.
*
* @return The current case database.
*/
public SleuthkitCase getCurrentSleuthkitCaseDb() {
return Case.getCurrentCase().getSleuthkitCase();
}
/**
* Get a logger to be used by the module to log messages to log files.
* @param module module to get the logger for
* @return logger object
/**
* Get a logger that incorporates the display name of an ingest module in
* messages written to the Autopsy log files.
*
* @param moduleClassName The display name of the ingest module.
* @return The custom logger for the ingest module.
*/
public Logger getLogger(IngestModuleAbstract module) {
return Logger.getLogger(module.getName());
public Logger getLogger(String moduleDisplayName) {
return Logger.getLogger(moduleDisplayName);
}
/**
* Post ingest message to the inbox. This should be done for
* analysis messages.
* @param message ingest message to be posted by ingest module
* Post message to the ingest messages in box.
*
* @param message An ingest message
*/
public void postMessage(final IngestMessage message) {
manager.postMessage(message);
manager.postIngestMessage(message);
}
/**
* Fire module event to notify registered module event listeners
* @param eventType the event type, defined in IngestManager.IngestManagerEvents
*
* @param eventType the event type, defined in
* IngestManager.IngestManagerEvents
* @param moduleName the module name
*/
public void fireModuleEvent(String eventType, String moduleName) {
IngestManager.fireModuleEvent(eventType, moduleName);
}
/**
* Fire module data event to notify registered module data event listeners that there
* is new data of a given type from a module
* @param moduleDataEvent module data event, encapsulating blackboard artifact data
* Fire module data event to notify registered module data event listeners
* that there is new data of a given type from a module
*
* @param moduleDataEvent module data event, encapsulating blackboard
* artifact data
*/
public void fireModuleDataEvent(ModuleDataEvent moduleDataEvent) {
IngestManager.fireModuleDataEvent(moduleDataEvent);
}
/**
* Fire module content event to notify registered module content event listeners
* that there is new content (from ZIP file contents, carving, etc.)
* @param moduleContentEvent module content event, encapsulating content changed
/**
* Fire module content event to notify registered module content event
* listeners that there is new content (from ZIP file contents, carving,
* etc.)
*
* @param moduleContentEvent module content event, encapsulating content
* changed
*/
public void fireModuleContentEvent(ModuleContentEvent moduleContentEvent) {
IngestManager.fireModuleContentEvent(moduleContentEvent);
}
/**
* Schedule a new file for ingest with the same settings as the file
* being analyzed. This is used, for example, when opening an archive file.
* File needs to have already been added to the database.
*
* @param file file to be scheduled
* @param pipelineContext the ingest context for the file ingest pipeline
*/
public void scheduleFile(AbstractFile file, PipelineContext<IngestModuleAbstractFile> pipelineContext) {
logger.log(Level.INFO, "Scheduling file: " + file.getName());
manager.scheduleFile(file, pipelineContext);
}
/**
* Get free disk space of a drive where ingest data are written to
* That drive is being monitored by IngestMonitor thread when ingest is running.
*
* Get free disk space of a drive where ingest data are written to That
* drive is being monitored by IngestMonitor thread when ingest is running.
*
* @return amount of disk space, -1 if unknown
*/
public long getFreeDiskSpace() {
return manager.getFreeDiskSpace();
}
}
/**
* Facility for a file ingest module to check a return value from a previously run file ingest module
* that executed for the same file.
* The module return value can be used as a guideline to skip processing the file
*
* @param moduleName registered module name of the module to check the return value of
* @return the return value of the previously executed module for the currently processed file in the file ingest pipeline
*/
public IngestModuleAbstractFile.ProcessResult getAbstractFileModuleResult(String moduleName) {
return manager.getAbstractFileModuleResult(moduleName);
}
/**
/**
* Gets a specific name/value configuration setting for a module
* @param moduleName moduleName identifier unique to that module
* @param settingName setting name to retrieve

View File

@ -51,7 +51,7 @@ public class Installer extends ModuleInstall {
@Override
public void run() {
//at this point UI top component is present for sure, ensure manager has it
manager.initUI();
manager.initIngestMessageInbox();
//force ingest inbox closed, even if previous state was open
//IngestMessageTopComponent.findInstance().close();
}

View File

@ -43,7 +43,4 @@ public class ModuleContentEvent extends ChangeEvent {
public String getModuleName() {
return moduleName;
}
}

View File

@ -0,0 +1,38 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
/**
* Implementation of the IngestModuleOptions interface for use by ingest modules
* that do not have per ingest job options.
*/
public final class NoIngestModuleSettings implements IngestModuleSettings {
private final String setting = "None";
/**
* Gets the string used as an ingest options placeholder for serialization
* purposes.
*
* @return The string "None"
*/
String getSetting() {
return setting;
}
}

View File

@ -1,77 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import org.openide.util.NbBundle;
import java.util.Objects;
/**
* Stores information about a given pipeline, which is a series of modules.
* This is passed into modules for their reference.
*
* @param T type of the ingest associated with the context (file or data source Content)
*
*/
public class PipelineContext <T extends IngestModuleAbstract> {
private final DataSourceTask<T> task;
PipelineContext(DataSourceTask<T> task) {
this.task = task;
}
/**
* Returns the currently scheduled task.
* @return
*/
DataSourceTask<T> getDataSourceTask() {
return task;
}
@Override
public String toString() {
return NbBundle.getMessage(this.getClass(), "PipelineContext.toString.text", task);
}
@Override
public int hashCode() {
int hash = 5;
hash = 53 * hash + Objects.hashCode(this.task);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
@SuppressWarnings("unchecked")
final PipelineContext<T> other = (PipelineContext<T>) obj;
if (!Objects.equals(this.task, other.task)) {
return false;
}
return true;
}
}

View File

@ -963,7 +963,7 @@ import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
StringBuilder summary = new StringBuilder();
boolean running = false;
if (IngestManager.getDefault().isIngestRunning() || IngestManager.getDefault().areModulesRunning()) {
if (IngestManager.getDefault().isIngestRunning() || IngestManager.getDefault().isIngestRunning()) {
running = true;
}

View File

@ -11,7 +11,15 @@
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
<specification-version>8.25.1</specification-version>
<specification-version>8.29.3</specification-version>
</run-dependency>
</dependency>
<dependency>
<code-name-base>org.openide.util.lookup</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
<specification-version>8.19.1</specification-version>
</run-dependency>
</dependency>
<dependency>

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2013 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -33,15 +33,11 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.PipelineContext;
import org.sleuthkit.autopsy.ingest.IngestModuleAdapter;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -57,59 +53,44 @@ import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
* files. Ingests an image file and, if available, adds it's date, latitude,
* longitude, altitude, device model, and device make to a blackboard artifact.
*/
public final class ExifParserFileIngestModule extends IngestModuleAbstractFile {
public final class ExifParserFileIngestModule extends IngestModuleAdapter implements FileIngestModule {
private IngestServices services;
final public static String MODULE_NAME = NbBundle.getMessage(ExifParserFileIngestModule.class,
"ExifParserFileIngestModule.moduleName.text");
final public static String MODULE_VERSION = Version.getVersion();
private static final Logger logger = Logger.getLogger(ExifParserFileIngestModule.class.getName());
private static ExifParserFileIngestModule defaultInstance = null;
private final IngestServices services = IngestServices.getDefault();
private int filesProcessed = 0;
private boolean filesToFire = false;
//file ingest modules require a private constructor
//to ensure singleton instances
private ExifParserFileIngestModule() {
}
//default instance used for module registration
public static synchronized ExifParserFileIngestModule getDefault() {
if (defaultInstance == null) {
defaultInstance = new ExifParserFileIngestModule();
}
return defaultInstance;
ExifParserFileIngestModule() {
}
@Override
public IngestModuleAbstractFile.ProcessResult process(PipelineContext<IngestModuleAbstractFile> pipelineContext, AbstractFile content) {
public ProcessResult process(AbstractFile content) {
//skip unalloc
if (content.getType().equals(TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) {
return IngestModuleAbstractFile.ProcessResult.OK;
return ProcessResult.OK;
}
// skip known
if (content.getKnown().equals(TskData.FileKnown.KNOWN)) {
return IngestModuleAbstractFile.ProcessResult.OK;
return ProcessResult.OK;
}
// update the tree every 1000 files if we have EXIF data that is not being being displayed
filesProcessed++;
if ((filesToFire) && (filesProcessed % 1000 == 0)) {
services.fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF));
services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF));
filesToFire = false;
}
//skip unsupported
if (!parsableFormat(content)) {
return IngestModuleAbstractFile.ProcessResult.OK;
return ProcessResult.OK;
}
return processFile(content);
}
public IngestModuleAbstractFile.ProcessResult processFile(AbstractFile f) {
ProcessResult processFile(AbstractFile f) {
InputStream in = null;
BufferedInputStream bin = null;
@ -117,7 +98,7 @@ public final class ExifParserFileIngestModule extends IngestModuleAbstractFile {
in = new ReadContentInputStream(f);
bin = new BufferedInputStream(in);
Collection<BlackboardAttribute> attributes = new ArrayList<BlackboardAttribute>();
Collection<BlackboardAttribute> attributes = new ArrayList<>();
Metadata metadata = ImageMetadataReader.readMetadata(bin, true);
// Date
@ -125,7 +106,7 @@ public final class ExifParserFileIngestModule extends IngestModuleAbstractFile {
if (exifDir != null) {
Date date = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);
if (date != null) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID(), MODULE_NAME, date.getTime() / 1000));
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID(), ExifParserModuleFactory.getModuleName(), date.getTime() / 1000));
}
}
@ -136,13 +117,13 @@ public final class ExifParserFileIngestModule extends IngestModuleAbstractFile {
if (loc != null) {
double latitude = loc.getLatitude();
double longitude = loc.getLongitude();
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(), MODULE_NAME, latitude));
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID(), MODULE_NAME, longitude));
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));
}
Rational altitude = gpsDir.getRational(GpsDirectory.TAG_GPS_ALTITUDE);
if (altitude != null) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID(), MODULE_NAME, altitude.doubleValue()));
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), altitude.doubleValue()));
}
}
@ -151,12 +132,12 @@ public final class ExifParserFileIngestModule extends IngestModuleAbstractFile {
if (devDir != null) {
String model = devDir.getString(ExifIFD0Directory.TAG_MODEL);
if (model != null && !model.isEmpty()) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL.getTypeID(), MODULE_NAME, model));
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL.getTypeID(), ExifParserModuleFactory.getModuleName(), model));
}
String make = devDir.getString(ExifIFD0Directory.TAG_MAKE);
if (make != null && !make.isEmpty()) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE.getTypeID(), MODULE_NAME, make));
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE.getTypeID(), ExifParserModuleFactory.getModuleName(), make));
}
}
@ -167,14 +148,16 @@ public final class ExifParserFileIngestModule extends IngestModuleAbstractFile {
filesToFire = true;
}
return IngestModuleAbstractFile.ProcessResult.OK;
return ProcessResult.OK;
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Failed to create blackboard artifact for exif metadata (" + ex.getLocalizedMessage() + ").");
logger.log(Level.WARNING, "Failed to create blackboard artifact for exif metadata ({0}).", ex.getLocalizedMessage());
return ProcessResult.ERROR;
} catch (ImageProcessingException ex) {
logger.log(Level.WARNING, "Failed to process the image file: " + 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 ProcessResult.ERROR;
} catch (IOException ex) {
logger.log(Level.WARNING, "IOException when parsing image file: " + f.getParentPath() + "/" + f.getName(), ex);
return ProcessResult.ERROR;
} finally {
try {
if (in != null) {
@ -185,11 +168,9 @@ public final class ExifParserFileIngestModule extends IngestModuleAbstractFile {
}
} catch (IOException ex) {
logger.log(Level.WARNING, "Failed to close InputStream.", ex);
return ProcessResult.ERROR;
}
}
// If we got here, there was an error
return IngestModuleAbstractFile.ProcessResult.ERROR;
}
/**
@ -205,44 +186,10 @@ public final class ExifParserFileIngestModule extends IngestModuleAbstractFile {
}
@Override
public void complete() {
logger.log(Level.INFO, "completed exif parsing " + this.toString());
public void shutDown(boolean ingestJobCancelled) {
if (filesToFire) {
//send the final new data event
services.fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF));
services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF));
}
}
@Override
public String getVersion() {
return MODULE_VERSION;
}
@Override
public String getName() {
return NbBundle.getMessage(this.getClass(), "ExifParserFileIngestModule.getName.text");
}
@Override
public String getDescription() {
return NbBundle.getMessage(this.getClass(), "ExifParserFileIngestModule.getDesc.text");
}
@Override
public void init(IngestModuleInit initContext) throws IngestModuleException {
services = IngestServices.getDefault();
logger.log(Level.INFO, "init() " + this.toString());
filesProcessed = 0;
filesToFire = false;
}
@Override
public void stop() {
}
@Override
public boolean hasBackgroundJobsRunning() {
return false;
}
}

View File

@ -0,0 +1,66 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.exifparser;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.openide.util.NbBundle;
/**
* 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)
public class ExifParserModuleFactory extends IngestModuleFactoryAdapter {
@Override
public String getModuleDisplayName() {
return getModuleName();
}
static String getModuleName() {
return NbBundle.getMessage(ExifParserFileIngestModule.class,
"ExifParserFileIngestModule.moduleName.text");
}
@Override
public String getModuleDescription() {
return NbBundle.getMessage(ExifParserFileIngestModule.class,
"ExifParserFileIngestModule.getDesc.text");
}
@Override
public String getModuleVersionNumber() {
return Version.getVersion();
}
@Override
public boolean isFileIngestModuleFactory() {
return true;
}
@Override
public FileIngestModule createFileIngestModule(IngestModuleSettings ingestOptions) {
return new ExifParserFileIngestModule();
}
}

View File

@ -16,12 +16,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.fileextmismatch;
import org.openide.util.NbBundle;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Arrays;
@ -30,36 +27,35 @@ import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
/**
* Do the context menu action for adding a new filename extension to
* the mismatch list for the MIME type of the selected node.
* Do the context menu action for adding a new filename extension to the
* mismatch list for the MIME type of the selected node.
*/
class AddFileExtensionAction extends AbstractAction {
class AddFileExtensionAction extends AbstractAction {
private String extStr;
private String mimeTypeStr;
public AddFileExtensionAction(String menuItemStr, String extStr, String mimeTypeStr) {
public AddFileExtensionAction(String menuItemStr, String extStr, String mimeTypeStr) {
super(menuItemStr);
this.mimeTypeStr = mimeTypeStr;
this.extStr = extStr;
}
@Override
public void actionPerformed(ActionEvent event) {
HashMap<String, String[]> editableMap = FileExtMismatchXML.getDefault().load();
ArrayList<String> editedExtensions = new ArrayList<>(Arrays.asList(editableMap.get(mimeTypeStr)));
ArrayList<String> editedExtensions = new ArrayList<>(Arrays.asList(editableMap.get(mimeTypeStr)));
editedExtensions.add(extStr);
// Old array will be replaced by new array for this key
editableMap.put(mimeTypeStr, editedExtensions.toArray(new String[0]));
if (!FileExtMismatchXML.getDefault().save(editableMap)) {
editableMap.put(mimeTypeStr, editedExtensions.toArray(new String[0]));
if (!FileExtMismatchXML.getDefault().save(editableMap)) {
//error
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(), "AddFileExtensionAction.msgDlg.msg"),
NbBundle.getMessage(this.getClass(), "AddFileExtensionAction.msgDlg.title"),
JOptionPane.ERROR_MESSAGE);
} // else //in the future we might want to update the statusbar to give feedback to the user
}
NbBundle.getMessage(this.getClass(), "AddFileExtensionAction.msgDlg.msg"),
NbBundle.getMessage(this.getClass(), "AddFileExtensionAction.msgDlg.title"),
JOptionPane.ERROR_MESSAGE);
} // else //in the future we might want to update the statusbar to give feedback to the user
}
}

View File

@ -1,22 +1,6 @@
OpenIDE-Module-Name=FileExtMismatch
OptionsCategory_Name_FileExtMismatchOptions=File Extension Mismatch
OptionsCategory_FileExtMismatch=File Extension Mismatch
FileExtMismatchConfigPanel.extHeaderLabel.text=Allowed Extensions:
FileExtMismatchConfigPanel.userExtTextField.text=
FileExtMismatchConfigPanel.addExtButton.text=Add Extension
FileExtMismatchConfigPanel.removeExtButton.text=Remove Selected Extension
FileExtMismatchConfigPanel.saveButton.text=Save Configuration
FileExtMismatchConfigPanel.jLabel1.text=File Types:
FileExtMismatchConfigPanel.removeTypeButton.text=Remove Selected Type
FileExtMismatchConfigPanel.addTypeButton.text=Add Type
FileExtMismatchConfigPanel.userTypeTextField.text=
FileExtMismatchConfigPanel.extErrorLabel.text=\
FileExtMismatchConfigPanel.mimeErrLabel.text=\
FileExtMismatchConfigPanel.mimeRemoveErrLabel.text=\
FileExtMismatchConfigPanel.extRemoveErrLabel.text=\
FileExtMismatchConfigPanel.saveMsgLabel.text=\
FileExtMismatchSimpleConfigPanel.skipNoExtCheckBox.text=Skip files without extensions
FileExtMismatchSimpleConfigPanel.skipTextPlain.text=Skip text files
AddFileExtensionAction.msgDlg.msg=Writing XML configuration file failed.
AddFileExtensionAction.msgDlg.title=Add Mismatch Extension Error
AddFileExtensionAction.extHeaderLbl.text=Allowed Extensions for
@ -50,3 +34,20 @@ FileExtMismatchIngestModule.complete.totalFiles=Total Files Processed
FileExtMismatchIngestModule.complete.svcMsg.text=File Extension Mismatch Results
FileExtMismatchOptionsPanelController.moduleErr=Module Error
FileExtMismatchOptionsPanelController.moduleErr.msg=A module caused an error listening to FileExtMismatchOptionsPanelController updates. See log to determine which module. Some data could be incomplete.
FileExtMismatchModuleSettingsPanel.skipKnownFilesCheckbox.text=Skip known files (NSRL)
FileExtMismatchModuleSettingsPanel.skipTextPlain.text=Skip text files
FileExtMismatchModuleSettingsPanel.skipNoExtCheckBox.text=Skip files without extensions
FileExtMismatchSettingsPanel.addTypeButton.text=Add Type
FileExtMismatchSettingsPanel.extErrorLabel.text=\
FileExtMismatchSettingsPanel.extHeaderLabel.text=Allowed Extensions:
FileExtMismatchSettingsPanel.saveMsgLabel.text=\
FileExtMismatchSettingsPanel.mimeRemoveErrLabel.text=\
FileExtMismatchSettingsPanel.extRemoveErrLabel.text=\
FileExtMismatchSettingsPanel.mimeErrLabel.text=\
FileExtMismatchSettingsPanel.removeTypeButton.text=Remove Selected Type
FileExtMismatchSettingsPanel.saveButton.text=Save Configuration
FileExtMismatchSettingsPanel.jLabel1.text=File Types:
FileExtMismatchSettingsPanel.userExtTextField.text=
FileExtMismatchSettingsPanel.addExtButton.text=Add Extension
FileExtMismatchSettingsPanel.removeExtButton.text=Remove Selected Extension
FileExtMismatchSettingsPanel.userTypeTextField.text=

View File

@ -1,45 +1,46 @@
OpenIDE-Module-Name=\u30D5\u30A1\u30A4\u30EB\u62E1\u5F35\u5B50\u4E0D\u4E00\u81F4
OptionsCategory_Name_FileExtMismatchOptions=\u30D5\u30A1\u30A4\u30EB\u62E1\u5F35\u5B50\u4E0D\u4E00\u81F4
OptionsCategory_FileExtMismatch=\u30D5\u30A1\u30A4\u30EB\u62E1\u5F35\u5B50\u4E0D\u4E00\u81F4
FileExtMismatchConfigPanel.extHeaderLabel.text=\u8A31\u53EF\u3055\u308C\u305F\u62E1\u5F35\u5B50\uFF1A
FileExtMismatchConfigPanel.addExtButton.text=\u62E1\u5F35\u5B50\u3092\u8FFD\u52A0
FileExtMismatchConfigPanel.removeExtButton.text=\u9078\u629E\u3057\u305F\u62E1\u5F35\u5B50\u3092\u524A\u9664
FileExtMismatchConfigPanel.saveButton.text=\u8A2D\u5B9A\u3092\u4FDD\u5B58
FileExtMismatchConfigPanel.jLabel1.text=\u30D5\u30A1\u30A4\u30EB\u30BF\u30A4\u30D7\uFF1A
FileExtMismatchConfigPanel.removeTypeButton.text=\u9078\u629E\u3057\u305F\u30BF\u30A4\u30D7\u3092\u524A\u9664
FileExtMismatchConfigPanel.addTypeButton.text=\u30BF\u30A4\u30D7\u3092\u8FFD\u52A0
FileExtMismatchSimpleConfigPanel.skipNoExtCheckBox.text=\u62E1\u5F35\u5B50\u306E\u7121\u3044\u30D5\u30A1\u30A4\u30EB\u306F\u30B9\u30AD\u30C3\u30D7
FileExtMismatchSimpleConfigPanel.skipTextPlain.text=\u30C6\u30AD\u30B9\u30C8\u30D5\u30A1\u30A4\u30EB\u306F\u30B9\u30AD\u30C3\u30D7
AddFileExtensionAction.msgDlg.msg=XML\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u3092\u66F8\u304F\u306E\u3092\u5931\u6557\u3057\u307E\u3057\u305F\u3002
AddFileExtensionAction.msgDlg.title=\u4E0D\u4E00\u81F4\u62E1\u5F35\u5B50\u306E\u8FFD\u52A0\u30A8\u30E9\u30FC
FileExtMismatchConfigPanel.name.text=\u30A2\u30C9\u30D0\u30F3\u30B9\u30D5\u30A1\u30A4\u30EB\u62E1\u5F35\u5B50\u4E0D\u4E00\u81F4\u8A2D\u5B9A
FileExtMismatchConfigPanel.addExtButton.errLabel.empty=\u62E1\u5F35\u5B50\u30C6\u30AD\u30B9\u30C8\u304C\u7A7A\u767D\u3067\u3059\uFF01
FileExtMismatchConfigPanel.addExtButton.errLabel.noMimeType=MIME\u30BF\u30A4\u30D7\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\uFF01
FileExtMismatchConfigPanel.addExtButton.errLabel.extExists=\u62E1\u5F35\u5B50\u306F\u3059\u3067\u306B\u5B58\u5728\u3057\u307E\u3059\uFF01
FileExtMismatchConfigPanel.addExtButton.errLabel.extAdded=\u62E1\u5F35\u5B50{0}\u306F\u8FFD\u52A0\u3055\u308C\u307E\u3057\u305F\u3002
FileExtMismatchConfigPanel.addTypeButton.empty=MIME\u30BF\u30A4\u30D7\u30C6\u30AD\u30B9\u30C8\u304C\u7A7A\u767D\u3067\u3059\uFF01
FileExtMismatchConfigPanel.addTypeButton.mimeTypeNotSupported=MIME\u30BF\u30A4\u30D7\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093\uFF01
FileExtMismatchConfigPanel.addTypeButton.mimeTypeExists=MIME\u30BF\u30A4\u30D7\u306F\u3059\u3067\u306B\u5B58\u5728\u3057\u307E\u3059\uFF01
FileExtMismatchConfigPanel.addTypeButton.mimeTypeNotDetectable=MIME\u30BF\u30A4\u30D7\u306F\u3053\u306E\u30E2\u30B8\u30E5\u30FC\u30EB\u3067\u306F\u691C\u51FA\u3067\u304D\u307E\u305B\u3093\u3002
FileExtMismatchConfigPanel.addTypeButton.mimeTypeAdded=MIME\u30BF\u30A4\u30D7{0}\u306F\u8FFD\u52A0\u3055\u308C\u307E\u3057\u305F\u3002
FileExtMismatchConfigPanel.removeTypeButton.noneSelected=MIME\u30BF\u30A4\u30D7\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\uFF01
FileExtMismatchConfigPanel.remoteTypeButton.deleted=MIME\u30BF\u30A4\u30D7{0}\u306F\u524A\u9664\u3055\u308C\u307E\u3057\u305F\u3002
FileExtMismatchConfigPanel.removeExtButton.noneSelected=\u62E1\u5F35\u5B50\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\uFF01
FileExtMismatchConfigPanel.removeExtButton.noMimeTypeSelected=MIME\u30BF\u30A4\u30D7\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\uFF01
FileExtMismatchConfigPanel.removeExtButton.deleted=\u62E1\u5F35\u5B50{0}\u306F\u524A\u9664\u3055\u308C\u307E\u3057\u305F\u3002
FileExtMismatchConfigPanel.store.msg=\u4FDD\u5B58\u3055\u308C\u307E\u3057\u305F\u3002
FileExtMismatchConfigPanel.store.msgDlg.msg=XML\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u3092\u66F8\u304F\u306E\u3092\u5931\u6557\u3057\u307E\u3057\u305F\u3002
FileExtMismatchConfigPanel.save.msgDlg.title=\u4FDD\u5B58\u30A8\u30E9\u30FC
FileExtMismatchConfigPanel.ok.confDlg.msg=\u8A2D\u5B9A\u5909\u66F4\u3092\u4FDD\u5B58\u3057\u307E\u3059\u304B\uFF1F
FileExtMismatchConfigPanel.confDlg.title=\u4FDD\u5B58\u3055\u308C\u3066\u3044\u306A\u3044\u5909\u66F4
FileExtMismatchConfigPanel.mimeTableModel.colName=MIME\u30BF\u30A4\u30D7
FileExtMismatchConfigPanel.extTableModel.colName=\u62E1\u5F35\u5B50
FileExtMismatchContextMenuActionsProvider.menuItemStr=\u62E1\u5F35\u5B50{0}\u3092MIME\u30BF\u30A4\u30D7{1}\u306E\u4E00\u81F4\u3068\u3057\u3066\u8FFD\u52A0
FileExtMismatchIngestModule.moduleName=\u62E1\u5F35\u5B50\u4E0D\u4E00\u81F4\u30C7\u30A3\u30C6\u30AF\u30BF\u30FC
FileExtMismatchIngestModule.moduleDesc.text=\u30D5\u30A1\u30A4\u30EB\u30BF\u30A4\u30D7\u306B\u57FA\u3065\u3044\u3066\u3001\u6A19\u6E96\u7684\u3067\u306F\u306A\u3044\u62E1\u5F35\u5B50\u3092\u6301\u3064\u30D5\u30A1\u30A4\u30EB\u3092\u30D5\u30E9\u30B0\u4ED8\u3051\u3057\u307E\u3059\u3002d
FileExtMismatchIngestModule.complete.totalProcTime=\u5408\u8A08\u51E6\u7406\u6642\u9593
FileExtMismatchIngestModule.complete.totalFiles=\u5408\u8A08\u51E6\u7406\u30D5\u30A1\u30A4\u30EB\u6570
FileExtMismatchIngestModule.complete.svcMsg.text=\u30D5\u30A1\u30A4\u30EB\u62E1\u5F35\u5B50\u4E0D\u4E00\u81F4\u7D50\u679C
FileExtMismatchOptionsPanelController.moduleErr=\u30E2\u30B8\u30E5\u30FC\u30EB\u30A8\u30E9\u30FC
FileExtMismatchOptionsPanelController.moduleErr.msg=FileExtMismatchOptionsPanelController\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u306E\u78BA\u8A8D\u4E2D\u306B\u30E2\u30B8\u30E5\u30FC\u30EB\u304C\u30A8\u30E9\u30FC\u3092\u8D77\u3053\u3057\u307E\u3057\u305F\u3002\u3069\u306E\u30E2\u30B8\u30E5\u30FC\u30EB\u304B\u30ED\u30B0\u3067\u78BA\u8A8D\u3057\u3066\u4E0B\u3055\u3044\u3002\u4E00\u90E8\u306E\u30C7\u30FC\u30BF\u304C\u4E0D\u5B8C\u5168\u304B\u3082\u3057\u308C\u307E\u305B\u3093\u3002
AddFileExtensionAction.extHeaderLbl.text=\u4E0B\u8A18\u7528\u306B\u8A31\u53EF\u3055\u308C\u305F\u62E1\u5F35\u5B50
OpenIDE-Module-Name=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50\u4e0d\u4e00\u81f4
OptionsCategory_Name_FileExtMismatchOptions=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50\u4e0d\u4e00\u81f4
OptionsCategory_FileExtMismatch=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50\u4e0d\u4e00\u81f4
AddFileExtensionAction.msgDlg.msg=XML\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3092\u66f8\u304f\u306e\u3092\u5931\u6557\u3057\u307e\u3057\u305f\u3002
AddFileExtensionAction.msgDlg.title=\u4e0d\u4e00\u81f4\u62e1\u5f35\u5b50\u306e\u8ffd\u52a0\u30a8\u30e9\u30fc
FileExtMismatchConfigPanel.name.text=\u30a2\u30c9\u30d0\u30f3\u30b9\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50\u4e0d\u4e00\u81f4\u8a2d\u5b9a
FileExtMismatchConfigPanel.addExtButton.errLabel.empty=\u62e1\u5f35\u5b50\u30c6\u30ad\u30b9\u30c8\u304c\u7a7a\u767d\u3067\u3059\uff01
FileExtMismatchConfigPanel.addExtButton.errLabel.noMimeType=MIME\u30bf\u30a4\u30d7\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093\uff01
FileExtMismatchConfigPanel.addExtButton.errLabel.extExists=\u62e1\u5f35\u5b50\u306f\u3059\u3067\u306b\u5b58\u5728\u3057\u307e\u3059\uff01
FileExtMismatchConfigPanel.addExtButton.errLabel.extAdded=\u62e1\u5f35\u5b50{0}\u306f\u8ffd\u52a0\u3055\u308c\u307e\u3057\u305f\u3002
FileExtMismatchConfigPanel.addTypeButton.empty=MIME\u30bf\u30a4\u30d7\u30c6\u30ad\u30b9\u30c8\u304c\u7a7a\u767d\u3067\u3059\uff01
FileExtMismatchConfigPanel.addTypeButton.mimeTypeNotSupported=MIME\u30bf\u30a4\u30d7\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\uff01
FileExtMismatchConfigPanel.addTypeButton.mimeTypeExists=MIME\u30bf\u30a4\u30d7\u306f\u3059\u3067\u306b\u5b58\u5728\u3057\u307e\u3059\uff01
FileExtMismatchConfigPanel.addTypeButton.mimeTypeNotDetectable=MIME\u30bf\u30a4\u30d7\u306f\u3053\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u3067\u306f\u691c\u51fa\u3067\u304d\u307e\u305b\u3093\u3002
FileExtMismatchConfigPanel.addTypeButton.mimeTypeAdded=MIME\u30bf\u30a4\u30d7{0}\u306f\u8ffd\u52a0\u3055\u308c\u307e\u3057\u305f\u3002
FileExtMismatchConfigPanel.removeTypeButton.noneSelected=MIME\u30bf\u30a4\u30d7\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093\uff01
FileExtMismatchConfigPanel.remoteTypeButton.deleted=MIME\u30bf\u30a4\u30d7{0}\u306f\u524a\u9664\u3055\u308c\u307e\u3057\u305f\u3002
FileExtMismatchConfigPanel.removeExtButton.noneSelected=\u62e1\u5f35\u5b50\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093\uff01
FileExtMismatchConfigPanel.removeExtButton.noMimeTypeSelected=MIME\u30bf\u30a4\u30d7\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093\uff01
FileExtMismatchConfigPanel.removeExtButton.deleted=\u62e1\u5f35\u5b50{0}\u306f\u524a\u9664\u3055\u308c\u307e\u3057\u305f\u3002
FileExtMismatchConfigPanel.store.msg=\u4fdd\u5b58\u3055\u308c\u307e\u3057\u305f\u3002
FileExtMismatchConfigPanel.store.msgDlg.msg=XML\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3092\u66f8\u304f\u306e\u3092\u5931\u6557\u3057\u307e\u3057\u305f\u3002
FileExtMismatchConfigPanel.save.msgDlg.title=\u4fdd\u5b58\u30a8\u30e9\u30fc
FileExtMismatchConfigPanel.ok.confDlg.msg=\u8a2d\u5b9a\u5909\u66f4\u3092\u4fdd\u5b58\u3057\u307e\u3059\u304b\uff1f
FileExtMismatchConfigPanel.confDlg.title=\u4fdd\u5b58\u3055\u308c\u3066\u3044\u306a\u3044\u5909\u66f4
FileExtMismatchConfigPanel.mimeTableModel.colName=MIME\u30bf\u30a4\u30d7
FileExtMismatchConfigPanel.extTableModel.colName=\u62e1\u5f35\u5b50
FileExtMismatchContextMenuActionsProvider.menuItemStr=\u62e1\u5f35\u5b50{0}\u3092MIME\u30bf\u30a4\u30d7{1}\u306e\u4e00\u81f4\u3068\u3057\u3066\u8ffd\u52a0
FileExtMismatchIngestModule.moduleName=\u62e1\u5f35\u5b50\u4e0d\u4e00\u81f4\u30c7\u30a3\u30c6\u30af\u30bf\u30fc
FileExtMismatchIngestModule.moduleDesc.text=\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u306b\u57fa\u3065\u3044\u3066\u3001\u6a19\u6e96\u7684\u3067\u306f\u306a\u3044\u62e1\u5f35\u5b50\u3092\u6301\u3064\u30d5\u30a1\u30a4\u30eb\u3092\u30d5\u30e9\u30b0\u4ed8\u3051\u3057\u307e\u3059\u3002d
FileExtMismatchIngestModule.complete.totalProcTime=\u5408\u8a08\u51e6\u7406\u6642\u9593
FileExtMismatchIngestModule.complete.totalFiles=\u5408\u8a08\u51e6\u7406\u30d5\u30a1\u30a4\u30eb\u6570
FileExtMismatchIngestModule.complete.svcMsg.text=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50\u4e0d\u4e00\u81f4\u7d50\u679c
FileExtMismatchOptionsPanelController.moduleErr=\u30e2\u30b8\u30e5\u30fc\u30eb\u30a8\u30e9\u30fc
FileExtMismatchOptionsPanelController.moduleErr.msg=FileExtMismatchOptionsPanelController\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u306e\u78ba\u8a8d\u4e2d\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u30a8\u30e9\u30fc\u3092\u8d77\u3053\u3057\u307e\u3057\u305f\u3002\u3069\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u304b\u30ed\u30b0\u3067\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\u3002\u4e00\u90e8\u306e\u30c7\u30fc\u30bf\u304c\u4e0d\u5b8c\u5168\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002
AddFileExtensionAction.extHeaderLbl.text=\u4e0b\u8a18\u7528\u306b\u8a31\u53ef\u3055\u308c\u305f\u62e1\u5f35\u5b50
FileExtMismatchModuleSettingsPanel.skipTextPlain.text=\u30c6\u30ad\u30b9\u30c8\u30d5\u30a1\u30a4\u30eb\u306f\u30b9\u30ad\u30c3\u30d7
FileExtMismatchModuleSettingsPanel.skipNoExtCheckBox.text=\u62e1\u5f35\u5b50\u306e\u7121\u3044\u30d5\u30a1\u30a4\u30eb\u306f\u30b9\u30ad\u30c3\u30d7
FileExtMismatchSettingsPanel.addTypeButton.text=\u30bf\u30a4\u30d7\u3092\u8ffd\u52a0
FileExtMismatchSettingsPanel.extHeaderLabel.text=\u8a31\u53ef\u3055\u308c\u305f\u62e1\u5f35\u5b50\uff1a
FileExtMismatchSettingsPanel.removeTypeButton.text=\u9078\u629e\u3057\u305f\u30bf\u30a4\u30d7\u3092\u524a\u9664
FileExtMismatchSettingsPanel.saveButton.text=\u8a2d\u5b9a\u3092\u4fdd\u5b58
FileExtMismatchSettingsPanel.jLabel1.text=\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\uff1a
FileExtMismatchSettingsPanel.addExtButton.text=\u62e1\u5f35\u5b50\u3092\u8ffd\u52a0
FileExtMismatchSettingsPanel.removeExtButton.text=\u9078\u629e\u3057\u305f\u62e1\u5f35\u5b50\u3092\u524a\u9664

View File

@ -27,14 +27,13 @@ import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import javax.swing.Action;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestConfigurator;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -51,8 +50,7 @@ public class FileExtMismatchContextMenuActionsProvider implements ContextMenuAct
ArrayList<Action> actions = new ArrayList<>();
// Ignore if file ingest is in progress.
IngestConfigurator ingestConfigurator = Lookup.getDefault().lookup(IngestConfigurator.class);
if (ingestConfigurator != null && !ingestConfigurator.isIngestRunning()) {
if (!IngestManager.getDefault().isIngestRunning()) {
final Collection<? extends BlackboardArtifact> selectedArts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
@ -127,4 +125,4 @@ public class FileExtMismatchContextMenuActionsProvider implements ContextMenuAct
return actions;
}
}
}

View File

@ -0,0 +1,104 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.fileextmismatch;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleSettingsPanel;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel;
/**
* An factory that creates file ingest modules that detect mismatches between
* the types of files and their extensions.
*/
@ServiceProvider(service = IngestModuleFactory.class)
public class FileExtMismatchDetectorModuleFactory extends IngestModuleFactoryAdapter {
static String getModuleName() {
return NbBundle.getMessage(FileExtMismatchIngestModule.class,
"FileExtMismatchIngestModule.moduleName");
}
@Override
public String getModuleDisplayName() {
return getModuleName();
}
@Override
public String getModuleDescription() {
return NbBundle.getMessage(FileExtMismatchIngestModule.class,
"FileExtMismatchIngestModule.moduleDesc.text");
}
@Override
public String getModuleVersionNumber() {
return Version.getVersion();
}
@Override
public IngestModuleSettings getDefaultModuleSettings() {
return new FileExtMismatchDetectorModuleSettings();
}
@Override
public boolean hasModuleSettingsPanel() {
return true;
}
@Override
public IngestModuleSettingsPanel getModuleSettingsPanel(IngestModuleSettings settings) {
assert settings instanceof FileExtMismatchDetectorModuleSettings;
if (!(settings instanceof FileExtMismatchDetectorModuleSettings)) {
throw new IllegalArgumentException("Expected settings argument to be instanceof FileExtMismatchDetectorModuleSettings");
}
FileExtMismatchModuleSettingsPanel settingsPanel = new FileExtMismatchModuleSettingsPanel((FileExtMismatchDetectorModuleSettings) settings);
return settingsPanel;
}
@Override
public boolean hasGlobalSettingsPanel() {
return true;
}
@Override
public IngestModuleGlobalSetttingsPanel getGlobalSettingsPanel() {
FileExtMismatchSettingsPanel globalOptionsPanel = new FileExtMismatchSettingsPanel();
globalOptionsPanel.load();
return globalOptionsPanel;
}
@Override
public boolean isFileIngestModuleFactory() {
return true;
}
@Override
public FileIngestModule createFileIngestModule(IngestModuleSettings settings) {
assert settings instanceof FileExtMismatchDetectorModuleSettings;
if (!(settings instanceof FileExtMismatchDetectorModuleSettings)) {
throw new IllegalArgumentException("Expected settings argument to be instanceof FileExtMismatchDetectorModuleSettings");
}
return new FileExtMismatchIngestModule((FileExtMismatchDetectorModuleSettings) settings);
}
}

View File

@ -0,0 +1,64 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.fileextmismatch;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
/**
* Ingest options for the file extension mismatch detector ingest module.
*/
final class FileExtMismatchDetectorModuleSettings implements IngestModuleSettings {
private boolean skipKnownFiles = false;
private boolean skipFilesWithNoExtension = true;
private boolean skipFilesWithTextPlainMimeType = false;
FileExtMismatchDetectorModuleSettings() {
}
FileExtMismatchDetectorModuleSettings(boolean skipKnownFiles, boolean skipFilesWithNoExtension, boolean skipFilesWithTextPlainMimeType) {
this.skipKnownFiles = skipKnownFiles;
this.skipFilesWithNoExtension = skipFilesWithNoExtension;
this.skipFilesWithTextPlainMimeType = skipFilesWithTextPlainMimeType;
}
void setSkipKnownFiles(boolean enabled) {
skipKnownFiles = enabled;
}
boolean skipKnownFiles() {
return skipKnownFiles;
}
void setSkipFilesWithNoExtension(boolean enabled) {
skipFilesWithNoExtension = enabled;
}
boolean skipFilesWithNoExtension() {
return skipFilesWithNoExtension;
}
void setSkipFilesWithTextPlainMimeType(boolean enabled) {
skipFilesWithTextPlainMimeType = enabled;
}
boolean skipFilesWithTextPlainMimeType() {
return skipFilesWithTextPlainMimeType;
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 - 2013 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -16,8 +16,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.fileextmismatch;
import java.util.ArrayList;
@ -26,16 +24,14 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.IngestModuleAdapter;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.autopsy.ingest.PipelineContext;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
@ -48,86 +44,57 @@ import org.sleuthkit.datamodel.TskException;
/**
* Flags mismatched filename extensions based on file signature.
*/
public class FileExtMismatchIngestModule extends org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile {
private static FileExtMismatchIngestModule defaultInstance = null;
private static final Logger logger = Logger.getLogger(FileExtMismatchIngestModule.class.getName());
public static final String MODULE_NAME = NbBundle.getMessage(FileExtMismatchIngestModule.class,
"FileExtMismatchIngestModule.moduleName");
public static final String MODULE_DESCRIPTION = NbBundle.getMessage(FileExtMismatchIngestModule.class,
"FileExtMismatchIngestModule.moduleDesc.text");
public static final String MODULE_VERSION = Version.getVersion();
public class FileExtMismatchIngestModule extends IngestModuleAdapter implements FileIngestModule {
private static long processTime = 0;
private static int messageId = 0;
private static long numFiles = 0;
// note: because of current design, these values must be in sync with default GUI values
// they only get updated when the user changes from the default UI values
private static boolean skipNoExt = true;
private static boolean skipTextPlain = true;
private FileExtMismatchSimpleConfigPanel simpleConfigPanel;
private FileExtMismatchConfigPanel advancedConfigPanel;
private IngestServices services;
private static final Logger logger = Logger.getLogger(FileExtMismatchIngestModule.class.getName());
private static int messageId = 0; // RJCTODO: This is not thread safe
private final IngestServices services = IngestServices.getDefault();
private final FileExtMismatchDetectorModuleSettings settings;
private HashMap<String, String[]> SigTypeToExtMap = new HashMap<>();
// Private to ensure Singleton status
private FileExtMismatchIngestModule() {
private long processTime = 0;
private long numFiles = 0;
}
// File-level ingest modules are currently singleton -- this is required
public static synchronized FileExtMismatchIngestModule getDefault() {
//defaultInstance is a private static class variable
if (defaultInstance == null) {
defaultInstance = new FileExtMismatchIngestModule();
}
return defaultInstance;
FileExtMismatchIngestModule(FileExtMismatchDetectorModuleSettings settings) {
this.settings = settings;
}
@Override
public void init(IngestModuleInit initContext) throws IngestModuleException {
services = IngestServices.getDefault();
// Load mapping
public void startUp(IngestJobContext context) throws IngestModuleException {
FileExtMismatchXML xmlLoader = FileExtMismatchXML.getDefault();
SigTypeToExtMap = xmlLoader.load();
}
@Override
public ProcessResult process(PipelineContext<IngestModuleAbstractFile> pipelineContext, AbstractFile abstractFile) {
public ProcessResult process(AbstractFile abstractFile) {
// skip non-files
if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) ||
(abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) {
return ProcessResult.OK;
}
// deleted files often have content that was not theirs and therefor causes mismatch
if ((abstractFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)) ||
(abstractFile.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC))) {
if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
|| (abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) {
return ProcessResult.OK;
}
if (abstractFile.getKnown() == FileKnown.KNOWN) {
// deleted files often have content that was not theirs and therefor causes mismatch
if ((abstractFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC))
|| (abstractFile.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC))) {
return ProcessResult.OK;
}
try
{
if (settings.skipKnownFiles() && (abstractFile.getKnown() == FileKnown.KNOWN)) {
return ProcessResult.OK;
}
try {
long startTime = System.currentTimeMillis();
boolean mismatchDetected = compareSigTypeToExt(abstractFile);
processTime += (System.currentTimeMillis() - startTime);
numFiles++;
if (mismatchDetected) {
// add artifact
BlackboardArtifact bart = abstractFile.newArtifact(ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED);
services.fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, 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 ProcessResult.OK;
} catch (TskException ex) {
@ -135,18 +102,19 @@ public class FileExtMismatchIngestModule extends org.sleuthkit.autopsy.ingest.In
return ProcessResult.ERROR;
}
}
/**
* Compare file type for file and extension.
*
* @param abstractFile
* @return false if the two match. True if there is a mismatch.
* @return false if the two match. True if there is a mismatch.
*/
private boolean compareSigTypeToExt(AbstractFile abstractFile) {
try {
String currActualExt = abstractFile.getNameExtension();
// If we are skipping names with no extension
if (skipNoExt && currActualExt.isEmpty()) {
if (settings.skipFilesWithNoExtension() && currActualExt.isEmpty()) {
return false;
}
@ -155,7 +123,7 @@ public class FileExtMismatchIngestModule extends org.sleuthkit.autopsy.ingest.In
ArrayList<BlackboardAttribute> attributes = abstractFile.getGenInfoAttributes(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG);
for (BlackboardAttribute attribute : attributes) {
String currActualSigType = attribute.getValueString();
if (skipTextPlain) {
if (settings.skipFilesWithTextPlainMimeType()) {
if (!currActualExt.isEmpty() && currActualSigType.equals("text/plain")) {
return false;
}
@ -183,97 +151,22 @@ public class FileExtMismatchIngestModule extends org.sleuthkit.autopsy.ingest.In
return false;
}
@Override
public void complete() {
public void shutDown(boolean ingestJobCancelled) {
StringBuilder detailsSb = new StringBuilder();
//details
detailsSb.append("<table border='0' cellpadding='4' width='280'>");
detailsSb.append("<tr><td>"+MODULE_DESCRIPTION+"</td></tr>");
detailsSb.append("<tr><td>").append(FileExtMismatchDetectorModuleFactory.getModuleName()).append("</td></tr>");
detailsSb.append("<tr><td>").append(
NbBundle.getMessage(this.getClass(), "FileExtMismatchIngestModule.complete.totalProcTime"))
.append("</td><td>").append(processTime).append("</td></tr>\n");
.append("</td><td>").append(processTime).append("</td></tr>\n");
detailsSb.append("<tr><td>").append(
NbBundle.getMessage(this.getClass(), "FileExtMismatchIngestModule.complete.totalFiles"))
.append("</td><td>").append(numFiles).append("</td></tr>\n");
.append("</td><td>").append(numFiles).append("</td></tr>\n");
detailsSb.append("</table>");
services.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this,
NbBundle.getMessage(this.getClass(),
"FileExtMismatchIngestModule.complete.svcMsg.text"),
detailsSb.toString()));
}
@Override
public void stop() {
//do nothing
}
@Override
public String getName() {
return MODULE_NAME;
}
@Override
public String getDescription() {
return MODULE_DESCRIPTION;
}
@Override
public String getVersion() {
return MODULE_VERSION;
}
@Override
public boolean hasSimpleConfiguration() {
return true;
}
@Override
public boolean hasAdvancedConfiguration() {
return true;
}
@Override
public javax.swing.JPanel getSimpleConfiguration(String context) {
if (simpleConfigPanel == null) {
simpleConfigPanel = new FileExtMismatchSimpleConfigPanel();
}
return simpleConfigPanel;
}
@Override
public javax.swing.JPanel getAdvancedConfiguration(String context) {
getPanel().load();
return getPanel();
}
private FileExtMismatchConfigPanel getPanel() {
if (advancedConfigPanel == null) {
advancedConfigPanel = new FileExtMismatchConfigPanel();
}
return advancedConfigPanel;
}
@Override
public void saveAdvancedConfiguration() {
getPanel().store();
}
@Override
public boolean hasBackgroundJobsRunning() {
// we're single threaded...
return false;
}
protected static void setSkipNoExt(boolean flag) {
skipNoExt = flag;
}
protected static void setSkipTextPlain(boolean flag) {
skipTextPlain = flag;
services.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, FileExtMismatchDetectorModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"FileExtMismatchIngestModule.complete.svcMsg.text"),
detailsSb.toString()));
}
}

View File

@ -21,6 +21,7 @@
<Group type="103" groupAlignment="0" attributes="0">
<Component id="skipTextPlain" min="-2" max="-2" attributes="0"/>
<Component id="skipNoExtCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="skipKnownFilesCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="138" max="32767" attributes="0"/>
</Group>
@ -32,7 +33,9 @@
<Component id="skipNoExtCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="skipTextPlain" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="51" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="skipKnownFilesCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="28" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -42,7 +45,7 @@
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSimpleConfigPanel.skipNoExtCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchModuleSettingsPanel.skipNoExtCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
@ -52,7 +55,7 @@
<Component class="javax.swing.JCheckBox" name="skipTextPlain">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSimpleConfigPanel.skipTextPlain.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchModuleSettingsPanel.skipTextPlain.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
@ -62,5 +65,15 @@
<AuxValue name="JavaCodeGenerator_InitCodePost" type="java.lang.String" value="skipTextPlain.setSelected(true);"/>
</AuxValues>
</Component>
<Component class="javax.swing.JCheckBox" name="skipKnownFilesCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchModuleSettingsPanel.skipKnownFilesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="skipKnownFilesCheckboxActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 - 2013 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,26 +18,38 @@
*/
package org.sleuthkit.autopsy.fileextmismatch;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleSettingsPanel;
/**
* Instances of this class provide a simplified UI for managing the hash sets configuration.
* UI component used to set ingest job options for file extension mismatch
* detector ingest modules.
*/
class FileExtMismatchSimpleConfigPanel extends javax.swing.JPanel {
final class FileExtMismatchModuleSettingsPanel extends IngestModuleSettingsPanel {
public FileExtMismatchSimpleConfigPanel() {
private final FileExtMismatchDetectorModuleSettings settings;
FileExtMismatchModuleSettingsPanel(FileExtMismatchDetectorModuleSettings settings) {
this.settings = settings;
initComponents();
customizeComponents();
}
private void customizeComponents() {
private void customizeComponents() {
skipNoExtCheckBox.setSelected(settings.skipFilesWithNoExtension());
skipTextPlain.setSelected(settings.skipFilesWithTextPlainMimeType());
skipKnownFilesCheckbox.setSelected(settings.skipKnownFiles());
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
@Override
public IngestModuleSettings getSettings() {
return settings;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
@ -45,16 +57,17 @@ class FileExtMismatchSimpleConfigPanel extends javax.swing.JPanel {
skipNoExtCheckBox = new javax.swing.JCheckBox();
skipTextPlain = new javax.swing.JCheckBox();
skipKnownFilesCheckbox = new javax.swing.JCheckBox();
skipNoExtCheckBox.setSelected(true);
skipNoExtCheckBox.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSimpleConfigPanel.class, "FileExtMismatchSimpleConfigPanel.skipNoExtCheckBox.text")); // NOI18N
skipNoExtCheckBox.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchModuleSettingsPanel.class, "FileExtMismatchModuleSettingsPanel.skipNoExtCheckBox.text")); // NOI18N
skipNoExtCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
skipNoExtCheckBoxActionPerformed(evt);
}
});
skipTextPlain.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSimpleConfigPanel.class, "FileExtMismatchSimpleConfigPanel.skipTextPlain.text")); // NOI18N
skipTextPlain.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchModuleSettingsPanel.class, "FileExtMismatchModuleSettingsPanel.skipTextPlain.text")); // NOI18N
skipTextPlain.setSelected(true);
skipTextPlain.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -62,6 +75,13 @@ class FileExtMismatchSimpleConfigPanel extends javax.swing.JPanel {
}
});
skipKnownFilesCheckbox.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchModuleSettingsPanel.class, "FileExtMismatchModuleSettingsPanel.skipKnownFilesCheckbox.text")); // NOI18N
skipKnownFilesCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
skipKnownFilesCheckboxActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@ -70,7 +90,8 @@ class FileExtMismatchSimpleConfigPanel extends javax.swing.JPanel {
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(skipTextPlain)
.addComponent(skipNoExtCheckBox))
.addComponent(skipNoExtCheckBox)
.addComponent(skipKnownFilesCheckbox))
.addGap(0, 138, Short.MAX_VALUE))
);
layout.setVerticalGroup(
@ -79,20 +100,26 @@ class FileExtMismatchSimpleConfigPanel extends javax.swing.JPanel {
.addComponent(skipNoExtCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(skipTextPlain)
.addContainerGap(51, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(skipKnownFilesCheckbox)
.addContainerGap(28, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
private void skipNoExtCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_skipNoExtCheckBoxActionPerformed
FileExtMismatchIngestModule.setSkipNoExt(skipNoExtCheckBox.isSelected());
settings.setSkipFilesWithNoExtension(skipNoExtCheckBox.isSelected());
}//GEN-LAST:event_skipNoExtCheckBoxActionPerformed
private void skipTextPlainActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_skipTextPlainActionPerformed
FileExtMismatchIngestModule.setSkipTextPlain(skipTextPlain.isSelected());
settings.setSkipFilesWithTextPlainMimeType(skipTextPlain.isSelected());
}//GEN-LAST:event_skipTextPlainActionPerformed
private void skipKnownFilesCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_skipKnownFilesCheckboxActionPerformed
settings.setSkipKnownFiles(skipKnownFilesCheckbox.isSelected());
}//GEN-LAST:event_skipKnownFilesCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox skipKnownFilesCheckbox;
private javax.swing.JCheckBox skipNoExtCheckBox;
private javax.swing.JCheckBox skipTextPlain;
// End of variables declaration//GEN-END:variables

View File

@ -16,19 +16,18 @@ import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
@OptionsPanelController.TopLevelRegistration(
categoryName = "#OptionsCategory_Name_FileExtMismatchOptions",
iconBase = "org/sleuthkit/autopsy/fileextmismatch/options-icon.png",
position = 4,
keywords = "#OptionsCategory_FileExtMismatch",
keywordsCategory = "KeywordSearchOptions")
// migrated to Bundle
//@org.openide.util.NbBundle.Messages({"OptionsCategory_Name_FileExtMismatchOptions=File Ext Mismatch", "OptionsCategory_FileExtMismatch=File Ext Mismatch"})
categoryName = "#OptionsCategory_Name_FileExtMismatchOptions",
iconBase = "org/sleuthkit/autopsy/fileextmismatch/options-icon.png",
position = 4,
keywords = "#OptionsCategory_FileExtMismatch",
keywordsCategory = "KeywordSearchOptions")
public final class FileExtMismatchOptionsPanelController extends OptionsPanelController {
private FileExtMismatchConfigPanel panel;
private FileExtMismatchSettingsPanel panel;
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private boolean changed;
private static final Logger logger = Logger.getLogger(FileExtMismatchOptionsPanelController.class.getName());
@Override
public void update() {
getPanel().load();
@ -77,9 +76,9 @@ public final class FileExtMismatchOptionsPanelController extends OptionsPanelCon
pcs.removePropertyChangeListener(l);
}
private FileExtMismatchConfigPanel getPanel() {
private FileExtMismatchSettingsPanel getPanel() {
if (panel == null) {
panel = new FileExtMismatchConfigPanel();
panel = new FileExtMismatchSettingsPanel();
}
return panel;
}
@ -87,11 +86,10 @@ public final class FileExtMismatchOptionsPanelController extends OptionsPanelCon
void changed() {
if (!changed) {
changed = true;
try {
pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true);
}
catch (Exception e) {
} catch (Exception e) {
logger.log(Level.SEVERE, "FileExtMismatchOptionsPanelController listener threw exception", e);
MessageNotifyUtil.Notify.show(
NbBundle.getMessage(this.getClass(), "FileExtMismatchOptionsPanelController.moduleErr"),
@ -99,16 +97,15 @@ public final class FileExtMismatchOptionsPanelController extends OptionsPanelCon
MessageNotifyUtil.MessageType.ERROR);
}
}
try {
pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
}
catch (Exception e) {
logger.log(Level.SEVERE, "FileExtMismatchOptionsPanelController listener threw exception", e);
MessageNotifyUtil.Notify.show(
NbBundle.getMessage(this.getClass(), "FileExtMismatchOptionsPanelController.moduleErr"),
NbBundle.getMessage(this.getClass(), "FileExtMismatchOptionsPanelController.moduleErr.msg"),
MessageNotifyUtil.MessageType.ERROR);
}
try {
pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
} catch (Exception e) {
logger.log(Level.SEVERE, "FileExtMismatchOptionsPanelController listener threw exception", e);
MessageNotifyUtil.Notify.show(
NbBundle.getMessage(this.getClass(), "FileExtMismatchOptionsPanelController.moduleErr"),
NbBundle.getMessage(this.getClass(), "FileExtMismatchOptionsPanelController.moduleErr.msg"),
MessageNotifyUtil.MessageType.ERROR);
}
}
}

View File

@ -53,7 +53,7 @@
<Image iconType="3" name="/org/sleuthkit/autopsy/fileextmismatch/save16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchConfigPanel.saveButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSettingsPanel.saveButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
@ -128,7 +128,7 @@
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchConfigPanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSettingsPanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -148,7 +148,7 @@
<Component class="javax.swing.JTextField" name="userTypeTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchConfigPanel.userTypeTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSettingsPanel.userTypeTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
@ -158,7 +158,7 @@
<Component class="javax.swing.JButton" name="addTypeButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchConfigPanel.addTypeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSettingsPanel.addTypeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
@ -168,7 +168,7 @@
<Component class="javax.swing.JButton" name="removeTypeButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchConfigPanel.removeTypeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSettingsPanel.removeTypeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
@ -181,14 +181,14 @@
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchConfigPanel.mimeErrLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSettingsPanel.mimeErrLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="mimeRemoveErrLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchConfigPanel.mimeRemoveErrLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSettingsPanel.mimeRemoveErrLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -254,7 +254,7 @@
<Component class="javax.swing.JTextField" name="userExtTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchConfigPanel.userExtTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSettingsPanel.userExtTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
@ -264,7 +264,7 @@
<Component class="javax.swing.JButton" name="addExtButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchConfigPanel.addExtButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSettingsPanel.addExtButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
@ -287,7 +287,7 @@
<Component class="javax.swing.JButton" name="removeExtButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchConfigPanel.removeExtButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSettingsPanel.removeExtButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
@ -297,7 +297,7 @@
<Component class="javax.swing.JLabel" name="extHeaderLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchConfigPanel.extHeaderLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSettingsPanel.extHeaderLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -307,14 +307,14 @@
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchConfigPanel.extErrorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSettingsPanel.extErrorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="extRemoveErrLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchConfigPanel.extRemoveErrLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSettingsPanel.extRemoveErrLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -328,7 +328,7 @@
<Color blue="ff" green="0" red="0" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchConfigPanel.saveMsgLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/fileextmismatch/Bundle.properties" key="FileExtMismatchSettingsPanel.saveMsgLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>

View File

@ -16,7 +16,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.fileextmismatch;
import java.awt.Color;
@ -30,50 +29,51 @@ import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
import org.sleuthkit.autopsy.coreutils.Logger;
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 javax.swing.JPanel implements OptionsPanel {
private static Logger logger = Logger.getLogger(FileExtMismatchConfigPanel.class.getName());
final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSetttingsPanel implements OptionsPanel {
private static Logger logger = Logger.getLogger(FileExtMismatchSettingsPanel.class.getName());
private HashMap<String, String[]> editableMap = new HashMap<>();
private ArrayList<String> mimeList = null;
private ArrayList<String> currentExtensions = null;
private MimeTableModel mimeTableModel;
private ExtTableModel extTableModel;
private final String EXT_HEADER_LABEL = NbBundle.getMessage(FileExtMismatchConfigPanel.class,
"AddFileExtensionAction.extHeaderLbl.text");
private final String EXT_HEADER_LABEL = NbBundle.getMessage(FileExtMismatchSettingsPanel.class,
"AddFileExtensionAction.extHeaderLbl.text");
private String selectedMime = "";
private String selectedExt = "";
ListSelectionModel lsm = null;
public FileExtMismatchConfigPanel() {
public FileExtMismatchSettingsPanel() {
mimeTableModel = new MimeTableModel();
extTableModel = new ExtTableModel();
initComponents();
customizeComponents();
}
private void customizeComponents() {
setName(NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.name.text"));
// Handle selections on the left table
lsm = mimeTable.getSelectionModel();
lsm.addListSelectionListener(new ListSelectionListener() {
lsm.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource();
if (!listSelectionModel.isSelectionEmpty()) {
int index = listSelectionModel.getMinSelectionIndex();
listSelectionModel.setSelectionInterval(index, index);
selectedMime = mimeList.get(index);
String labelStr = EXT_HEADER_LABEL + selectedMime + ":";
if (labelStr.length() > 80) {
@ -81,7 +81,7 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
}
extHeaderLabel.setText(labelStr);
updateExtList();
extTableModel.resync();
//initButtons();
} else {
@ -89,32 +89,31 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
currentExtensions = null;
extTableModel.resync();
}
clearErrLabels();
}
}
});
// Handle selections on the right table
ListSelectionModel extLsm = extTable.getSelectionModel();
extLsm.addListSelectionListener(new ListSelectionListener() {
extLsm.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource();
if (!listSelectionModel.isSelectionEmpty()) {
int index = listSelectionModel.getMinSelectionIndex();
listSelectionModel.setSelectionInterval(index, index);
selectedExt = currentExtensions.get(index);
} else {
selectedExt = "";
}
extRemoveErrLabel.setText(" ");
}
});
}
});
}
private void clearErrLabels() {
@ -122,9 +121,9 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
mimeRemoveErrLabel.setText(" ");
extRemoveErrLabel.setText(" ");
extErrorLabel.setText(" ");
saveMsgLabel.setText(" ");
}
saveMsgLabel.setText(" ");
}
/**
* 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
@ -156,7 +155,7 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
saveMsgLabel = new javax.swing.JLabel();
saveButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/fileextmismatch/save16.png"))); // NOI18N
saveButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchConfigPanel.class, "FileExtMismatchConfigPanel.saveButton.text")); // NOI18N
saveButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.saveButton.text")); // NOI18N
saveButton.setEnabled(false);
saveButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -166,26 +165,26 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
jSplitPane1.setDividerLocation(430);
jLabel1.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchConfigPanel.class, "FileExtMismatchConfigPanel.jLabel1.text")); // NOI18N
jLabel1.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.jLabel1.text")); // NOI18N
mimeTable.setModel(mimeTableModel);
jScrollPane2.setViewportView(mimeTable);
userTypeTextField.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchConfigPanel.class, "FileExtMismatchConfigPanel.userTypeTextField.text")); // NOI18N
userTypeTextField.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.userTypeTextField.text")); // NOI18N
userTypeTextField.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusGained(java.awt.event.FocusEvent evt) {
userTypeTextFieldFocusGained(evt);
}
});
addTypeButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchConfigPanel.class, "FileExtMismatchConfigPanel.addTypeButton.text")); // NOI18N
addTypeButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.addTypeButton.text")); // NOI18N
addTypeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
addTypeButtonActionPerformed(evt);
}
});
removeTypeButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchConfigPanel.class, "FileExtMismatchConfigPanel.removeTypeButton.text")); // NOI18N
removeTypeButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.removeTypeButton.text")); // NOI18N
removeTypeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
removeTypeButtonActionPerformed(evt);
@ -193,9 +192,9 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
});
mimeErrLabel.setForeground(new java.awt.Color(255, 0, 0));
mimeErrLabel.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchConfigPanel.class, "FileExtMismatchConfigPanel.mimeErrLabel.text")); // NOI18N
mimeErrLabel.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.mimeErrLabel.text")); // NOI18N
mimeRemoveErrLabel.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchConfigPanel.class, "FileExtMismatchConfigPanel.mimeRemoveErrLabel.text")); // NOI18N
mimeRemoveErrLabel.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.mimeRemoveErrLabel.text")); // NOI18N
javax.swing.GroupLayout mimePanelLayout = new javax.swing.GroupLayout(mimePanel);
mimePanel.setLayout(mimePanelLayout);
@ -240,14 +239,14 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
jSplitPane1.setLeftComponent(mimePanel);
userExtTextField.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchConfigPanel.class, "FileExtMismatchConfigPanel.userExtTextField.text")); // NOI18N
userExtTextField.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.userExtTextField.text")); // NOI18N
userExtTextField.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusGained(java.awt.event.FocusEvent evt) {
userExtTextFieldFocusGained(evt);
}
});
addExtButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchConfigPanel.class, "FileExtMismatchConfigPanel.addExtButton.text")); // NOI18N
addExtButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.addExtButton.text")); // NOI18N
addExtButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
addExtButtonActionPerformed(evt);
@ -257,19 +256,19 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
extTable.setModel(extTableModel);
jScrollPane3.setViewportView(extTable);
removeExtButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchConfigPanel.class, "FileExtMismatchConfigPanel.removeExtButton.text")); // NOI18N
removeExtButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.removeExtButton.text")); // NOI18N
removeExtButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
removeExtButtonActionPerformed(evt);
}
});
extHeaderLabel.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchConfigPanel.class, "FileExtMismatchConfigPanel.extHeaderLabel.text")); // NOI18N
extHeaderLabel.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.extHeaderLabel.text")); // NOI18N
extErrorLabel.setForeground(new java.awt.Color(255, 0, 0));
extErrorLabel.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchConfigPanel.class, "FileExtMismatchConfigPanel.extErrorLabel.text")); // NOI18N
extErrorLabel.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.extErrorLabel.text")); // NOI18N
extRemoveErrLabel.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchConfigPanel.class, "FileExtMismatchConfigPanel.extRemoveErrLabel.text")); // NOI18N
extRemoveErrLabel.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.extRemoveErrLabel.text")); // NOI18N
javax.swing.GroupLayout extensionPanelLayout = new javax.swing.GroupLayout(extensionPanel);
extensionPanel.setLayout(extensionPanelLayout);
@ -315,7 +314,7 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
jSplitPane1.setRightComponent(extensionPanel);
saveMsgLabel.setForeground(new java.awt.Color(0, 0, 255));
saveMsgLabel.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchConfigPanel.class, "FileExtMismatchConfigPanel.saveMsgLabel.text")); // NOI18N
saveMsgLabel.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.saveMsgLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
@ -349,41 +348,41 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
private void addExtButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addExtButtonActionPerformed
String newExt = userExtTextField.getText();
if (newExt.isEmpty()) {
extErrorLabel.setForeground(Color.red);
extErrorLabel.setForeground(Color.red);
extErrorLabel.setText(
NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addExtButton.errLabel.empty"));
return;
}
if (selectedMime.isEmpty()) {
extErrorLabel.setForeground(Color.red);
extErrorLabel.setForeground(Color.red);
extErrorLabel.setText(
NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addExtButton.errLabel.noMimeType"));
return;
}
if (currentExtensions.contains(newExt)) {
extErrorLabel.setForeground(Color.red);
extErrorLabel.setText(
NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addExtButton.errLabel.extExists"));
return;
}
ArrayList<String> editedExtensions = new ArrayList<>(Arrays.asList(editableMap.get(selectedMime)));
return;
}
ArrayList<String> editedExtensions = new ArrayList<>(Arrays.asList(editableMap.get(selectedMime)));
editedExtensions.add(newExt);
// 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
updateExtList();
updateExtList();
extTableModel.resync();
// user feedback for successful add
extErrorLabel.setForeground(Color.blue);
extErrorLabel.setText(
NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addExtButton.errLabel.extAdded",
newExt));
newExt));
extRemoveErrLabel.setText(" ");
userExtTextField.setText("");
setIsModified();
@ -400,26 +399,26 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
mimeErrLabel.setText(NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addTypeButton.empty"));
return;
}
if (newMime.equals( "application/octet-stream")){
if (newMime.equals("application/octet-stream")) {
mimeErrLabel.setForeground(Color.red);
mimeErrLabel.setText(NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.addTypeButton.mimeTypeNotSupported"));
return;
"FileExtMismatchConfigPanel.addTypeButton.mimeTypeNotSupported"));
return;
}
if (mimeList.contains(newMime)) {
mimeErrLabel.setForeground(Color.red);
mimeErrLabel.setText(
NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.addTypeButton.mimeTypeExists"));
return;
return;
}
if (!FileTypeIdIngestModule.isMimeTypeDetectable(newMime)) {
mimeErrLabel.setForeground(Color.red);
mimeErrLabel.setText(NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.addTypeButton.mimeTypeNotDetectable"));
return;
"FileExtMismatchConfigPanel.addTypeButton.mimeTypeNotDetectable"));
return;
}
editableMap.put(newMime, new String[0]);
// Refresh table
@ -450,15 +449,15 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
mimeRemoveErrLabel.setText(
NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.removeTypeButton.noneSelected"));
return;
}
editableMap.remove(selectedMime);
}
editableMap.remove(selectedMime);
String deadMime = selectedMime;
// Refresh table
updateMimeList();
mimeTableModel.resync();
mimeTableModel.resync();
// user feedback for successful add
mimeRemoveErrLabel.setForeground(Color.blue);
mimeRemoveErrLabel.setText(
@ -472,26 +471,26 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
extRemoveErrLabel.setText(
NbBundle.getMessage(this.getClass(), "FileExtMismatchConfigPanel.removeExtButton.noneSelected"));
return;
}
}
if (selectedMime.isEmpty()) {
extErrorLabel.setForeground(Color.red);
extErrorLabel.setForeground(Color.red);
extErrorLabel.setText(NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.removeExtButton.noMimeTypeSelected"));
"FileExtMismatchConfigPanel.removeExtButton.noMimeTypeSelected"));
return;
}
ArrayList<String> editedExtensions = new ArrayList<>(Arrays.asList(editableMap.get(selectedMime)));
}
ArrayList<String> editedExtensions = new ArrayList<>(Arrays.asList(editableMap.get(selectedMime)));
editedExtensions.remove(selectedExt);
String deadExt = selectedExt;
// 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
updateExtList();
extTableModel.resync();
extTableModel.resync();
// user feedback for successful add
extRemoveErrLabel.setForeground(Color.blue);
extRemoveErrLabel.setText(
@ -505,7 +504,7 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
Collections.sort(mimeList);
}
}
private void updateExtList() {
String[] temp = editableMap.get(selectedMime);
if (temp != null) {
@ -517,68 +516,72 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
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
public void load() {
// Load the XML into a buffer that the user can modify. They can choose
// to save it back to the file after making changes.
editableMap = FileExtMismatchXML.getDefault().load();
updateMimeList();
updateExtList();
updateExtList();
}
@Override
public void store() {
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);
}
saveSettings();
}
private void setIsModified() {
saveButton.setEnabled(true);
saveMsgLabel.setText(" ");
}
public void cancel() {
clearErrLabels();
load(); // The next time this panel is opened, we want it to be fresh
}
public void ok() {
// if data is unsaved
if (saveButton.isEnabled()) {
int choice = JOptionPane.showConfirmDialog(this,
NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.ok.confDlg.msg"),
NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.confDlg.title"),
JOptionPane.YES_NO_OPTION);
if (choice == JOptionPane.YES_OPTION) {
store();
}
int choice = JOptionPane.showConfirmDialog(this,
NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.ok.confDlg.msg"),
NbBundle.getMessage(this.getClass(),
"FileExtMismatchConfigPanel.confDlg.title"),
JOptionPane.YES_NO_OPTION);
if (choice == JOptionPane.YES_OPTION) {
store();
}
}
clearErrLabels();
clearErrLabels();
load(); // The next time this panel is opened, we want it to be fresh
}
boolean valid() {
return true;
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton addExtButton;
private javax.swing.JButton addTypeButton;
@ -666,7 +669,7 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
fireTableDataChanged();
}
}
private class ExtTableModel extends AbstractTableModel {
@Override
@ -697,7 +700,7 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object ret = null;
if ((currentExtensions == null) || (currentExtensions.size() == 0) || (rowIndex > currentExtensions.size())) {
return "";
}
@ -730,6 +733,5 @@ final class FileExtMismatchConfigPanel extends javax.swing.JPanel implements Opt
void resync() {
fireTableDataChanged();
}
}
}
}

View File

@ -1,8 +1,8 @@
OpenIDE-Module-Name=FileTypeId
FileTypeIdSimpleConfigPanel.skipKnownCheckBox.toolTipText=Depending on how many files have known hashes, checking this box will improve the speed of file type identification.
FileTypeIdSimpleConfigPanel.skipKnownCheckBox.text=Skip Known Files (NSRL)
FileTypeIdModuleSettingsPanel.skipKnownCheckBox.text=Skip known files (NSRL)
FileTypeIdModuleSettingsPanel.skipKnownCheckBox.toolTipText=Depending on how many files have known hashes, checking this box will improve the speed of file type identification.
FileTypeIdIngestModule.moduleName.text=File Type Identification
FileTypeIdIngestModule.moduleDesc.text=Matches file types based on binary signatures.
FileTypeIdIngestModule.complete.totalProcTime=Total Processing Time
FileTypeIdIngestModule.complete.totalFiles=Total Files Processed
FileTypeIdIngestModule.complete.srvMsg.text=File Type Id Results
FileTypeIdIngestModule.complete.srvMsg.text=File Type Id Results

View File

@ -1,8 +1,7 @@
OpenIDE-Module-Name=\u30D5\u30A1\u30A4\u30EB\u30BF\u30A4\u30D7\u306E\u7279\u5B9A
FileTypeIdSimpleConfigPanel.skipKnownCheckBox.toolTipText=\u65E2\u77E5\u306E\u30CF\u30C3\u30B7\u30E5\u5024\u3092\u6301\u3064\u30D5\u30A1\u30A4\u30EB\u6570\u306B\u3088\u3063\u3066\u306F\u3001\u3053\u306E\u30DC\u30C3\u30AF\u30B9\u3092\u9078\u629E\u3059\u308B\u306E\u306B\u3088\u308A\u3001\u30D5\u30A1\u30A4\u30EB\u30BF\u30A4\u30D7\u306E\u7279\u5B9A\u3092\u52A0\u901F\u3057\u307E\u3059\u3002
FileTypeIdSimpleConfigPanel.skipKnownCheckBox.text=\u65E2\u77E5\u30D5\u30A1\u30A4\u30EB\u3092\u30B9\u30AD\u30C3\u30D7(NSRL)
FileTypeIdIngestModule.moduleName.text=\u30D5\u30A1\u30A4\u30EB\u30BF\u30A4\u30D7\u306E\u7279\u5B9A
FileTypeIdIngestModule.moduleDesc.text=\u30D0\u30A4\u30CA\u30EA\u7F72\u540D\u306B\u57FA\u3065\u3044\u3066\u30D5\u30A1\u30A4\u30EB\u30BF\u30A4\u30D7\u3092\u4E00\u81F4\u3059\u308B\u3002
FileTypeIdIngestModule.complete.totalProcTime=\u5408\u8A08\u51E6\u7406\u6642\u9593
FileTypeIdIngestModule.complete.totalFiles=\u5408\u8A08\u51E6\u7406\u30D5\u30A1\u30A4\u30EB\u6570
FileTypeIdIngestModule.complete.srvMsg.text=\u30D5\u30A1\u30A4\u30EB\u30BF\u30A4\u30D7\u7279\u5B9A\u306E\u7D50\u679C
OpenIDE-Module-Name=\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u306e\u7279\u5b9a
FileTypeIdModuleSettingsPanel.skipKnownCheckBox.toolTipText=\u65e2\u77e5\u306e\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u6301\u3064\u30d5\u30a1\u30a4\u30eb\u6570\u306b\u3088\u3063\u3066\u306f\u3001\u3053\u306e\u30dc\u30c3\u30af\u30b9\u3092\u9078\u629e\u3059\u308b\u306e\u306b\u3088\u308a\u3001\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u306e\u7279\u5b9a\u3092\u52a0\u901f\u3057\u307e\u3059\u3002
FileTypeIdIngestModule.moduleName.text=\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u306e\u7279\u5b9a
FileTypeIdIngestModule.moduleDesc.text=\u30d0\u30a4\u30ca\u30ea\u7f72\u540d\u306b\u57fa\u3065\u3044\u3066\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u3092\u4e00\u81f4\u3059\u308b\u3002
FileTypeIdIngestModule.complete.totalProcTime=\u5408\u8a08\u51e6\u7406\u6642\u9593
FileTypeIdIngestModule.complete.totalFiles=\u5408\u8a08\u51e6\u7406\u30d5\u30a1\u30a4\u30eb\u6570
FileTypeIdIngestModule.complete.srvMsg.text=\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u7279\u5b9a\u306e\u7d50\u679c

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2013-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -27,16 +27,15 @@ import org.sleuthkit.datamodel.AbstractFile;
* to an extension string list instead of the third-party library's extension
* reporting.
*/
interface FileTypeDetectionInterface {
// Struct to hold multiple values for return
interface FileTypeDetectionInterface {
public class FileIdInfo {
public String type;
public String extension;
public String type;
public String extension;
}
// You only have one job
FileIdInfo attemptMatch(AbstractFile abstractFile);
boolean isMimeTypeDetectable(String mimeType);
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2013-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -16,19 +16,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filetypeid;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.PipelineContext;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -36,84 +32,57 @@ import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskData.FileKnown;
import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.autopsy.ingest.IngestModule.ProcessResult;
import org.sleuthkit.autopsy.ingest.IngestModuleAdapter;
/**
* Detects the type of a file based on signature (magic) values.
* Posts results to the blackboard.
* Detects the type of a file based on signature (magic) values. Posts results
* to the blackboard.
*/
public class FileTypeIdIngestModule extends org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile {
private static FileTypeIdIngestModule defaultInstance = null;
public final static String MODULE_NAME = NbBundle.getMessage(FileTypeIdIngestModule.class,
"FileTypeIdIngestModule.moduleName.text");
public final static String MODULE_DESCRIPTION = NbBundle.getMessage(FileTypeIdIngestModule.class,
"FileTypeIdIngestModule.moduleDesc.text");
public final static String MODULE_VERSION = Version.getVersion();
public class FileTypeIdIngestModule extends IngestModuleAdapter implements FileIngestModule {
private static final Logger logger = Logger.getLogger(FileTypeIdIngestModule.class.getName());
private static long matchTime = 0;
private static int messageId = 0;
private static long numFiles = 0;
// NOTE: This value needs to be in sync with the default GUI value
// given the current design of only updating this when the user changes the default.
private static boolean skipKnown = true;
private static long MIN_FILE_SIZE = 512;
private FileTypeIdSimpleConfigPanel simpleConfigPanel;
private IngestServices services;
private static final long MIN_FILE_SIZE = 512;
private final FileTypeIdModuleSettings settings;
private long matchTime = 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;
// 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
// actually have a list of detectors which are called in order until a match is found.
private FileTypeDetectionInterface detector = new TikaFileTypeDetector();
//private FileTypeDetectionInterface detector = new JMimeMagicFileTypeDetector();
//private FileTypeDetectionInterface detector = new MimeUtilFileTypeDetector();
// Private to ensure Singleton status
private FileTypeIdIngestModule() {
}
// File-level ingest modules are currently singleton -- this is required
public static synchronized FileTypeIdIngestModule getDefault() {
//defaultInstance is a private static class variable
if (defaultInstance == null) {
defaultInstance = new FileTypeIdIngestModule();
}
return defaultInstance;
private FileTypeDetectionInterface detector = new TikaFileTypeDetector();
FileTypeIdIngestModule(FileTypeIdModuleSettings settings) {
this.settings = settings;
}
@Override
public void init(IngestModuleInit initContext) throws IngestModuleException {
services = IngestServices.getDefault();
}
@Override
public ProcessResult process(PipelineContext<IngestModuleAbstractFile> pipelineContext, AbstractFile abstractFile) {
public ProcessResult process(AbstractFile abstractFile) {
// skip non-files
if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) ||
(abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) {
if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
|| (abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) {
return ProcessResult.OK;
}
if (skipKnown && (abstractFile.getKnown() == FileKnown.KNOWN)) {
if (settings.skipKnownFiles() && (abstractFile.getKnown() == FileKnown.KNOWN)) {
return ProcessResult.OK;
}
if (abstractFile.getSize() < MIN_FILE_SIZE) {
return ProcessResult.OK;
}
try
{
return ProcessResult.OK;
}
try {
long startTime = System.currentTimeMillis();
FileTypeDetectionInterface.FileIdInfo fileId = detector.attemptMatch(abstractFile);
matchTime += (System.currentTimeMillis() - startTime);
numFiles++;
if (!fileId.type.isEmpty()) {
// add artifact
BlackboardArtifact bart = abstractFile.getGenInfoArtifact();
BlackboardAttribute batt = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID(), MODULE_NAME, fileId.type);
BlackboardAttribute batt = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID(), FileTypeIdModuleFactory.getModuleName(), fileId.type);
bart.addAttribute(batt);
// we don't fire the event because we just updated TSK_GEN_INFO, which isn't displayed in the tree and is vague.
@ -122,88 +91,38 @@ import org.sleuthkit.datamodel.TskException;
} catch (TskException ex) {
logger.log(Level.WARNING, "Error matching file signature", ex);
return ProcessResult.ERROR;
}
catch (Exception e) {
} catch (Exception e) {
logger.log(Level.WARNING, "Error matching file signature", e);
return ProcessResult.ERROR;
}
}
@Override
public void complete() {
public void shutDown(boolean ingestJobCancelled) {
StringBuilder detailsSb = new StringBuilder();
//details
detailsSb.append("<table border='0' cellpadding='4' width='280'>");
detailsSb.append("<tr><td>"+MODULE_DESCRIPTION+"</td></tr>");
detailsSb.append("<tr><td>").append(FileTypeIdModuleFactory.getModuleName()).append("</td></tr>");
detailsSb.append("<tr><td>")
.append(NbBundle.getMessage(this.getClass(), "FileTypeIdIngestModule.complete.totalProcTime"))
.append("</td><td>").append(matchTime).append("</td></tr>\n");
.append(NbBundle.getMessage(this.getClass(), "FileTypeIdIngestModule.complete.totalProcTime"))
.append("</td><td>").append(matchTime).append("</td></tr>\n");
detailsSb.append("<tr><td>")
.append(NbBundle.getMessage(this.getClass(), "FileTypeIdIngestModule.complete.totalFiles"))
.append("</td><td>").append(numFiles).append("</td></tr>\n");
.append(NbBundle.getMessage(this.getClass(), "FileTypeIdIngestModule.complete.totalFiles"))
.append("</td><td>").append(numFiles).append("</td></tr>\n");
detailsSb.append("</table>");
services.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this,
NbBundle.getMessage(this.getClass(),
"FileTypeIdIngestModule.complete.srvMsg.text"),
detailsSb.toString()));
IngestServices.getDefault().postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, FileTypeIdModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"FileTypeIdIngestModule.complete.srvMsg.text"),
detailsSb.toString()));
}
@Override
public void stop() {
//do nothing
}
@Override
public String getName() {
return MODULE_NAME;
}
@Override
public String getDescription() {
return MODULE_DESCRIPTION;
}
@Override
public String getVersion() {
return MODULE_VERSION;
}
@Override
public boolean hasSimpleConfiguration() {
return true;
}
@Override
public javax.swing.JPanel getSimpleConfiguration(String context) {
if (simpleConfigPanel == null) {
simpleConfigPanel = new FileTypeIdSimpleConfigPanel();
}
return simpleConfigPanel;
}
@Override
public boolean hasBackgroundJobsRunning() {
// we're single threaded...
return false;
}
protected static void setSkipKnown(boolean flag) {
skipKnown = flag;
}
/**
* Validate if a given mime type is in the detector's registry.
*
* @param mimeType Full string of mime type, e.g. "text/html"
* @return true if detectable
*/
public static boolean isMimeTypeDetectable(String mimeType) {
FileTypeDetectionInterface detector = new TikaFileTypeDetector();
FileTypeDetectionInterface detector = new TikaFileTypeDetector();
return detector.isMimeTypeDetectable(mimeType);
}
}
}

View File

@ -0,0 +1,90 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filetypeid;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleSettingsPanel;
/**
* An factory that creates file ingest modules that determine the types of
* files.
*/
@ServiceProvider(service = IngestModuleFactory.class)
public class FileTypeIdModuleFactory extends IngestModuleFactoryAdapter {
@Override
public String getModuleDisplayName() {
return getModuleName();
}
static String getModuleName() {
return NbBundle.getMessage(FileTypeIdIngestModule.class,
"FileTypeIdIngestModule.moduleName.text");
}
@Override
public String getModuleDescription() {
return NbBundle.getMessage(FileTypeIdIngestModule.class,
"FileTypeIdIngestModule.moduleDesc.text");
}
@Override
public String getModuleVersionNumber() {
return Version.getVersion();
}
@Override
public IngestModuleSettings getDefaultModuleSettings() {
return new FileTypeIdModuleSettings();
}
@Override
public boolean hasModuleSettingsPanel() {
return true;
}
@Override
public IngestModuleSettingsPanel getModuleSettingsPanel(IngestModuleSettings settings) {
assert settings instanceof FileTypeIdModuleSettings;
if (!(settings instanceof FileTypeIdModuleSettings)) {
throw new IllegalArgumentException("Expected settings argument to be instanceof FileTypeIdModuleSettings");
}
return new FileTypeIdModuleSettingsPanel((FileTypeIdModuleSettings) settings);
}
@Override
public boolean isFileIngestModuleFactory() {
return true;
}
@Override
public FileIngestModule createFileIngestModule(IngestModuleSettings settings) {
assert settings instanceof FileTypeIdModuleSettings;
if (!(settings instanceof FileTypeIdModuleSettings)) {
throw new IllegalArgumentException("Expected settings argument to be instanceof FileTypeIdModuleSettings");
}
return new FileTypeIdIngestModule((FileTypeIdModuleSettings) settings);
}
}

View File

@ -0,0 +1,44 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filetypeid;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
/**
* Ingest job options for the file type identifier ingest module instances.
*/
public class FileTypeIdModuleSettings implements IngestModuleSettings {
private boolean skipKnownFiles = true;
FileTypeIdModuleSettings() {
}
FileTypeIdModuleSettings(boolean skipKnownFiles) {
this.skipKnownFiles = skipKnownFiles;
}
void setSkipKnownFiles(boolean enabled) {
skipKnownFiles = enabled;
}
boolean skipKnownFiles() {
return skipKnownFiles;
}
}

View File

@ -19,7 +19,7 @@
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Component id="skipKnownCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="138" max="32767" attributes="0"/>
<EmptySpace pref="608" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -28,7 +28,7 @@
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="11" max="-2" attributes="0"/>
<Component id="skipKnownCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="45" max="32767" attributes="0"/>
<EmptySpace pref="47" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -38,10 +38,13 @@
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filetypeid/Bundle.properties" key="FileTypeIdSimpleConfigPanel.skipKnownCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/filetypeid/Bundle.properties" key="FileTypeIdModuleSettingsPanel.skipKnownCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filetypeid/Bundle.properties" key="FileTypeIdSimpleConfigPanel.skipKnownCheckBox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/filetypeid/Bundle.properties" key="FileTypeIdModuleSettingsPanel.skipKnownCheckBox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="label" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filetypeid/Bundle.properties" key="FileTypeIdModuleSettingsPanel.skipKnownCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 - 2013 Basis Technology Corp.
* Copyright 2013 - 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,25 +18,36 @@
*/
package org.sleuthkit.autopsy.filetypeid;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleSettingsPanel;
/**
* Instances of this class provide a simplified UI for managing the hash sets configuration.
* UI component used to set ingest job options for file type identifier ingest
* modules.
*/
class FileTypeIdSimpleConfigPanel extends javax.swing.JPanel {
final class FileTypeIdModuleSettingsPanel extends IngestModuleSettingsPanel {
public FileTypeIdSimpleConfigPanel() {
private final FileTypeIdModuleSettings settings;
public FileTypeIdModuleSettingsPanel(FileTypeIdModuleSettings settings) {
this.settings = settings;
initComponents();
customizeComponents();
}
private void customizeComponents() {
skipKnownCheckBox.setSelected(settings.skipKnownFiles());
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
@Override
public IngestModuleSettings getSettings() {
return settings;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
@ -45,8 +56,9 @@ package org.sleuthkit.autopsy.filetypeid;
skipKnownCheckBox = new javax.swing.JCheckBox();
skipKnownCheckBox.setSelected(true);
skipKnownCheckBox.setText(org.openide.util.NbBundle.getMessage(FileTypeIdSimpleConfigPanel.class, "FileTypeIdSimpleConfigPanel.skipKnownCheckBox.text")); // NOI18N
skipKnownCheckBox.setToolTipText(org.openide.util.NbBundle.getMessage(FileTypeIdSimpleConfigPanel.class, "FileTypeIdSimpleConfigPanel.skipKnownCheckBox.toolTipText")); // NOI18N
skipKnownCheckBox.setText(org.openide.util.NbBundle.getMessage(FileTypeIdModuleSettingsPanel.class, "FileTypeIdModuleSettingsPanel.skipKnownCheckBox.text")); // NOI18N
skipKnownCheckBox.setToolTipText(org.openide.util.NbBundle.getMessage(FileTypeIdModuleSettingsPanel.class, "FileTypeIdModuleSettingsPanel.skipKnownCheckBox.toolTipText")); // NOI18N
skipKnownCheckBox.setLabel(org.openide.util.NbBundle.getMessage(FileTypeIdModuleSettingsPanel.class, "FileTypeIdModuleSettingsPanel.skipKnownCheckBox.text")); // NOI18N
skipKnownCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
skipKnownCheckBoxActionPerformed(evt);
@ -60,21 +72,20 @@ package org.sleuthkit.autopsy.filetypeid;
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(skipKnownCheckBox)
.addContainerGap(138, Short.MAX_VALUE))
.addContainerGap(608, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(11, 11, 11)
.addComponent(skipKnownCheckBox)
.addContainerGap(45, Short.MAX_VALUE))
.addContainerGap(47, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
private void skipKnownCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_skipKnownCheckBoxActionPerformed
FileTypeIdIngestModule.setSkipKnown(skipKnownCheckBox.isSelected());
settings.setSkipKnownFiles(skipKnownCheckBox.isSelected());
}//GEN-LAST:event_skipKnownCheckBoxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox skipKnownCheckBox;
// End of variables declaration//GEN-END:variables

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 - 2013 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -16,10 +16,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.filetypeid;
import java.util.SortedSet;
import org.openide.util.Exceptions;
import org.apache.tika.Tika;
import org.apache.tika.mime.MediaType;
import org.apache.tika.mime.MimeTypes;
@ -29,14 +28,13 @@ import org.sleuthkit.datamodel.AbstractFile;
class TikaFileTypeDetector implements FileTypeDetectionInterface {
private static Tika tikaInst = new Tika();
@Override
public FileTypeDetectionInterface.FileIdInfo attemptMatch(AbstractFile abstractFile) {
try {
try {
FileTypeDetectionInterface.FileIdInfo ret = new FileTypeDetectionInterface.FileIdInfo();
final int maxBytesInitial = 100; //how many bytes to read on first pass
byte buffer[] = new byte[maxBytesInitial];
int len = abstractFile.read(buffer, 0, maxBytesInitial);
boolean found = false;
try {
@ -66,23 +64,24 @@ class TikaFileTypeDetector implements FileTypeDetectionInterface {
} catch (Exception ex) {
return new FileTypeDetectionInterface.FileIdInfo();
}
}
}
/**
* Validate if a given mime type is in the registry.
* For Tika, we remove the string "tika" from all MIME names,
* e.g. use "application/x-msoffice" NOT "application/x-tika-msoffice"
* Validate if a given mime type is in the registry. For Tika, we remove the
* string "tika" from all MIME names, e.g. use "application/x-msoffice" NOT
* "application/x-tika-msoffice"
*
* @param mimeType Full string of mime type, e.g. "text/html"
* @return true if detectable
*/
@Override
public boolean isMimeTypeDetectable(String mimeType) {
boolean ret = false;
SortedSet<MediaType> m = MimeTypes.getDefaultMimeTypes().getMediaTypeRegistry().getTypes();
SortedSet<MediaType> m = MimeTypes.getDefaultMimeTypes().getMediaTypeRegistry().getTypes();
String[] split = mimeType.split("/");
if (split.length == 2) {
String type = split[0];
String subtype = split[1];
@ -90,6 +89,6 @@ class TikaFileTypeDetector implements FileTypeDetectionInterface {
ret = m.contains(mediaType);
}
return ret;
return ret;
}
}

View File

@ -32,11 +32,12 @@ import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.openide.util.Lookup;
import org.openide.util.actions.Presenter;
import org.sleuthkit.autopsy.ingest.IngestConfigurator;
import org.sleuthkit.autopsy.ingest.IngestJobLauncher;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException;
import static org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
import org.sleuthkit.autopsy.ingest.IngestManager;
/**
* Instances of this Action allow users to content to a hash database.
@ -81,8 +82,7 @@ final class AddContentToHashDbAction extends AbstractAction implements Presenter
super(SINGLE_SELECTION_NAME);
// Disable the menu if file ingest is in progress.
IngestConfigurator ingestConfigurator = Lookup.getDefault().lookup(IngestConfigurator.class);
if (null != ingestConfigurator && ingestConfigurator.isIngestRunning()) {
if (IngestManager.getDefault().isIngestRunning()) {
setEnabled(false);
return;
}

View File

@ -30,33 +30,10 @@ HashDbImportDatabaseDialog.cancelButton.text=Cancel
HashDbCreateDatabaseDialog.jLabel2.text=Type:
HashDbCreateDatabaseDialog.knownBadRadioButton.text=Known Bad
HashDbCreateDatabaseDialog.cancelButton.text=Cancel
HashDbConfigPanel.nameLabel.text=Hash Set Name:
HashDbConfigPanel.hashDbNameLabel.text=No database selected
HashDbConfigPanel.hashDatabasesLabel.text=Hash Databases:
HashDbConfigPanel.hashDbLocationLabel.text=No database selected
HashDbConfigPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes.
HashDbConfigPanel.jButton3.text=Import Database
HashDbConfigPanel.jLabel6.text=Type:
HashDbConfigPanel.jLabel4.text=Location:
HashDbConfigPanel.jLabel2.text=Name:
HashDbConfigPanel.optionsLabel.text=Options
HashDbConfigPanel.typeLabel.text=Type:
HashDbConfigPanel.locationLabel.text=Database Path:
HashDbConfigPanel.hashDbIndexStatusLabel.text=No database selected
HashDbConfigPanel.hashDbTypeLabel.text=No database selected
HashDbConfigPanel.indexButton.text=Index
HashDbConfigPanel.indexLabel.text=Index Status:
HashDbConfigPanel.informationLabel.text=Information
HashDbConfigPanel.importDatabaseButton.text=Import Database
HashDbConfigPanel.deleteDatabaseButton.text=Delete Database
HashDbConfigPanel.indexPathLabelLabel.text=Index Path:
HashDbConfigPanel.indexPathLabel.text=No database selected
ModalNoButtons.CURRENTDB_LABEL.text=(CurrentDb)
ModalNoButtons.CURRENTLYON_LABEL.text=Currently Indexing x of y
ModalNoButtons.GO_GET_COFFEE_LABEL.text=Hash databases are currently being indexed, this may take some time.
ModalNoButtons.CANCEL_BUTTON.text=Cancel
HashDbSimpleConfigPanel.knownBadHashDbsLabel.text=Select known BAD hash databases to use:
HashDbSimpleConfigPanel.knownHashDbsLabel.text=Select known hash databases to use:
HashDbImportDatabaseDialog.knownRadioButton.text=Known (NSRL or other)
HashDbCreateDatabaseDialog.knownRadioButton.text=Known
HashDbCreateDatabaseDialog.jLabel1.text=Database Path:
@ -66,13 +43,10 @@ HashDbImportDatabaseDialog.jLabel3.text=Database Path:
HashDbCreateDatabaseDialog.sendIngestMessagesCheckbox.text=Send ingest inbox messages for each hit
HashDbImportDatabaseDialog.sendIngestMessagesCheckbox.text=Send ingest inbox message for each hit
HashDbImportDatabaseDialog.hashSetNameTextField.text=
HashDbConfigPanel.createDatabaseButton.text=Create Database
HashDbImportDatabaseDialog.openButton.text=Open...
HashDbSimpleConfigPanel.alwaysCalcHashesCheckbox.text=Calculate MD5 even if no hash database is selected
HashDbCreateDatabaseDialog.jLabel3.text=Hash Set Name:
HashDbCreateDatabaseDialog.okButton.text=OK
HashDbCreateDatabaseDialog.databasePathTextField.text=
HashDbConfigPanel.sendIngestMessagesCheckBox.text=Send ingest inbox message for each hit
AddContentToHashDbAction.ContentMenu.noHashDbsConfigd=No hash databases configured
AddContentToHashDbAction.ContentMenu.createDbItem=Create database...
AddContentToHashDbAction.addFilesToHashSet.addToHashDbErr=Add to Hash Database Error
@ -202,3 +176,29 @@ AddContentToHashDbAction.singleSelectionName=Add file to hash database
AddContentToHashDbAction.multipleSelectionName=Add files to hash database
HashDbManager.ingestRunningExceptionMsg=Ingest is ongoing; this service will be unavailable until it finishes.
HashDbManager.saveErrorExceptionMsg=Error saving hash configuration
HashLookupSettingsPanel.optionsLabel.text=Options
HashLookupSettingsPanel.jButton3.text=Import Database
HashLookupSettingsPanel.indexPathLabelLabel.text=Index Path:
HashLookupSettingsPanel.createDatabaseButton.text=Create Database
HashLookupSettingsPanel.jLabel6.text=Type:
HashLookupSettingsPanel.jLabel4.text=Location:
HashLookupSettingsPanel.jLabel2.text=Name:
HashLookupSettingsPanel.indexPathLabel.text=No database selected
HashLookupSettingsPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes.
HashLookupSettingsPanel.deleteDatabaseButton.text=Delete Database
HashLookupSettingsPanel.importDatabaseButton.text=Import Database
HashLookupSettingsPanel.hashDatabasesLabel.text=Hash Databases:
HashLookupSettingsPanel.nameLabel.text=Hash Set Name:
HashLookupSettingsPanel.informationLabel.text=Information
HashLookupSettingsPanel.sendIngestMessagesCheckBox.text=Send ingest inbox message for each hit
HashLookupSettingsPanel.hashDbLocationLabel.text=No database selected
HashLookupSettingsPanel.hashDbNameLabel.text=No database selected
HashLookupSettingsPanel.typeLabel.text=Type:
HashLookupSettingsPanel.locationLabel.text=Database Path:
HashLookupSettingsPanel.hashDbIndexStatusLabel.text=No database selected
HashLookupSettingsPanel.hashDbTypeLabel.text=No database selected
HashLookupSettingsPanel.indexButton.text=Index
HashLookupSettingsPanel.indexLabel.text=Index Status:
HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text=Calculate MD5 even if no hash database is selected
HashLookupModuleSettingsPanel.knownHashDbsLabel.text=Select known hash databases to use:
HashLookupModuleSettingsPanel.knownBadHashDbsLabel.text=Select known BAD hash databases to use:

View File

@ -23,31 +23,9 @@ HashDbImportDatabaseDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb
HashDbCreateDatabaseDialog.jLabel2.text=\u7a2e\u985e\uff1a
HashDbCreateDatabaseDialog.knownBadRadioButton.text=\u65e2\u77e5\u306e\u60aa\u8cea
HashDbCreateDatabaseDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb
HashDbConfigPanel.nameLabel.text=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u306e\u540d\u524d\uff1a
HashDbConfigPanel.hashDbNameLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093
HashDbConfigPanel.hashDatabasesLabel.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\uff1a
HashDbConfigPanel.hashDbLocationLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093
HashDbConfigPanel.ingestWarningLabel.text=\u51e6\u7406\u4e2d\u3067\u3059\u3002\u5b8c\u4e86\u3059\u308b\u307e\u3067\u4e00\u90e8\u306e\u8a2d\u5b9a\u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002
HashDbConfigPanel.jButton3.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30dd\u30fc\u30c8
HashDbConfigPanel.jLabel6.text=\u7a2e\u985e\uff1a
HashDbConfigPanel.jLabel4.text=\u30ed\u30b1\u30fc\u30b7\u30e7\u30f3\uff1a
HashDbConfigPanel.jLabel2.text=\u540d\u524d\uff1a
HashDbConfigPanel.optionsLabel.text=\u30aa\u30d7\u30b7\u30e7\u30f3
HashDbConfigPanel.typeLabel.text=\u7a2e\u985e\uff1a
HashDbConfigPanel.locationLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\uff1a
HashDbConfigPanel.hashDbIndexStatusLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093
HashDbConfigPanel.hashDbTypeLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093
HashDbConfigPanel.indexButton.text=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9
HashDbConfigPanel.indexLabel.text=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u30b9\u30c6\u30fc\u30bf\u30b9\uff1a
HashDbConfigPanel.informationLabel.text=\u30a4\u30f3\u30d5\u30a9\u30e1\u30fc\u30b7\u30e7\u30f3
HashDbConfigPanel.importDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30dd\u30fc\u30c8
HashDbConfigPanel.deleteDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u524a\u9664
HashDbConfigPanel.indexPathLabelLabel.text=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u30d1\u30b9\uff1a
HashDbConfigPanel.indexPathLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093
ModalNoButtons.CURRENTLYON_LABEL.text=y\u306ex\u3092\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u4e2d
ModalNoButtons.GO_GET_COFFEE_LABEL.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u4e2d\u3067\u3059\u3002\u6642\u9593\u304c\u304b\u304b\u308b\u5834\u5408\u304c\u3042\u308a\u307e\u3059\u3002
ModalNoButtons.CANCEL_BUTTON.text=\u30ad\u30e3\u30f3\u30bb\u30eb
HashDbSimpleConfigPanel.knownBadHashDbsLabel.text=\u65e2\u77e5\u306e\u60aa\u8cea\u306a\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u51e6\u7406\u306b\u5229\u7528\uff1a
HashDbImportDatabaseDialog.knownRadioButton.text=\u65e2\u77e5\uff08NSRL\u307e\u305f\u306f\u305d\u306e\u4ed6\uff09
HashDbCreateDatabaseDialog.knownRadioButton.text=\u65e2\u77e5
HashDbCreateDatabaseDialog.jLabel1.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\uff1a
@ -55,12 +33,9 @@ HashDbCreateDatabaseDialog.saveAsButton.text=\u540d\u524d\u3092\u3064\u3051\u306
HashDbImportDatabaseDialog.jLabel3.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\uff1a
HashDbCreateDatabaseDialog.sendIngestMessagesCheckbox.text=\u51e6\u7406\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u9001\u308b
HashDbImportDatabaseDialog.sendIngestMessagesCheckbox.text=\u51e6\u7406\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u9001\u308b
HashDbConfigPanel.createDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u4f5c\u6210
HashDbImportDatabaseDialog.openButton.text=\u958b\u304f...
HashDbSimpleConfigPanel.alwaysCalcHashesCheckbox.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u306a\u304f\u3066\u3082\u3001\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u8a08\u7b97
HashDbCreateDatabaseDialog.jLabel3.text=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u306e\u540d\u524d\uff1a
HashDbCreateDatabaseDialog.okButton.text=OK
HashDbConfigPanel.sendIngestMessagesCheckBox.text=\u51e6\u7406\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u9001\u308b
AddContentToHashDbAction.ContentMenu.noHashDbsConfigd=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093
AddContentToHashDbAction.ContentMenu.createDbItem=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u4f5c\u6210...
AddContentToHashDbAction.addFilesToHashSet.addToHashDbErr=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30a8\u30e9\u30fc\u306b\u8ffd\u52a0
@ -110,7 +85,6 @@ HashDbIngestModule.moduleDescription=\u6a19\u6e96\u306eNSRL\u30c7\u30fc\u30bf\u3
HashDbIngestModule.noKnownHashDbSetMsg=\u65e2\u77e5\u306e\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u5b58\u5728\u3057\u307e\u305b\u3093\u3002
HashDbIngestModule.knownFileSearchWillNotExecuteWarn=\u65e2\u77e5\u306e\u30d5\u30a1\u30a4\u30eb\u691c\u7d22\u304c\u5b9f\u884c\u3055\u308c\u307e\u305b\u3093\u3002
HashDbIngestModule.noKnownBadHashDbSetMsg=\u65e2\u77e5\u306e\u60aa\u8cea\u306a\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30bb\u30c3\u30c8\u306f\u3042\u308a\u307e\u305b\u3093\u3002
HashDbSimpleConfigPanel.knownHashDbsLabel.text=\u65e2\u77e5\u306e\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u51e6\u7406\u306b\u5229\u7528\uff1a
HashDbConfigPanel.dbNotIndexedMsg=\u4e0b\u8a18\u306e\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306f\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5316\u3057\u307e\u3059\u304b\uff1f\
{0}
HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=\u65e2\u77e5\u306e\u60aa\u8cea\u30d5\u30a1\u30a4\u30eb\u691c\u7d22\u306f\u5b9f\u884c\u3055\u308c\u307e\u305b\u3093\u3002
@ -191,3 +165,29 @@ OptionsCategory_Name_HashDatabase=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30
OptionsCategory_Keywords_HashDatabase=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9
HashDbManager.ingestRunningExceptionMsg=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u4e2d\uff1b\u5b8c\u4e86\u3059\u308b\u307e\u3067\u3053\u306e\u30b5\u30fc\u30d3\u30b9\u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002
HashLookupSettingsPanel.optionsLabel.text=\u30aa\u30d7\u30b7\u30e7\u30f3
HashLookupSettingsPanel.jButton3.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30dd\u30fc\u30c8
HashLookupSettingsPanel.indexPathLabelLabel.text=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u30d1\u30b9\uff1a
HashLookupSettingsPanel.createDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u4f5c\u6210
HashLookupSettingsPanel.jLabel6.text=\u7a2e\u985e\uff1a
HashLookupSettingsPanel.jLabel4.text=\u30ed\u30b1\u30fc\u30b7\u30e7\u30f3\uff1a
HashLookupSettingsPanel.jLabel2.text=\u540d\u524d\uff1a
HashLookupSettingsPanel.indexPathLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093
HashLookupSettingsPanel.ingestWarningLabel.text=\u51e6\u7406\u4e2d\u3067\u3059\u3002\u5b8c\u4e86\u3059\u308b\u307e\u3067\u4e00\u90e8\u306e\u8a2d\u5b9a\u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002
HashLookupSettingsPanel.deleteDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u524a\u9664
HashLookupSettingsPanel.importDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30dd\u30fc\u30c8
HashLookupSettingsPanel.hashDatabasesLabel.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\uff1a
HashLookupSettingsPanel.nameLabel.text=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u306e\u540d\u524d\uff1a
HashLookupSettingsPanel.informationLabel.text=\u30a4\u30f3\u30d5\u30a9\u30e1\u30fc\u30b7\u30e7\u30f3
HashLookupSettingsPanel.sendIngestMessagesCheckBox.text=\u51e6\u7406\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u9001\u308b
HashLookupSettingsPanel.hashDbLocationLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093
HashLookupSettingsPanel.hashDbNameLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093
HashLookupSettingsPanel.typeLabel.text=\u7a2e\u985e\uff1a
HashLookupSettingsPanel.locationLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\uff1a
HashLookupSettingsPanel.hashDbIndexStatusLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093
HashLookupSettingsPanel.hashDbTypeLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093
HashLookupSettingsPanel.indexButton.text=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9
HashLookupSettingsPanel.indexLabel.text=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u30b9\u30c6\u30fc\u30bf\u30b9\uff1a
HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u306a\u304f\u3066\u3082\u3001\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u8a08\u7b97
HashLookupModuleSettingsPanel.knownHashDbsLabel.text=\u65e2\u77e5\u306e\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u51e6\u7406\u306b\u5229\u7528\uff1a
HashLookupModuleSettingsPanel.knownBadHashDbsLabel.text=\u65e2\u77e5\u306e\u60aa\u8cea\u306a\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u51e6\u7406\u306b\u5229\u7528\uff1a

View File

@ -41,7 +41,7 @@ id = "HashDatabase")
//@org.openide.util.NbBundle.Messages({"OptionsCategory_Name_HashDatabase=Hash Database", "OptionsCategory_Keywords_HashDatabase=Hash Database"})
public final class HashDatabaseOptionsPanelController extends OptionsPanelController {
private HashDbConfigPanel panel;
private HashLookupSettingsPanel panel;
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private boolean changed;
private static final Logger logger = Logger.getLogger(HashDatabaseOptionsPanelController.class.getName());
@ -92,9 +92,9 @@ public final class HashDatabaseOptionsPanelController extends OptionsPanelContro
pcs.removePropertyChangeListener(l);
}
private HashDbConfigPanel getPanel() {
private HashLookupSettingsPanel getPanel() {
if (panel == null) {
panel = new HashDbConfigPanel();
panel = new HashLookupSettingsPanel();
}
return panel;
}

View File

@ -23,15 +23,10 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.PipelineContext;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.AbstractFile;
@ -45,143 +40,61 @@ import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstract.IngestModuleException;
import org.sleuthkit.autopsy.ingest.IngestModuleAdapter;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.datamodel.HashInfo;
public class HashDbIngestModule extends IngestModuleAbstractFile {
private static HashDbIngestModule instance = null;
public final static String MODULE_NAME = NbBundle.getMessage(HashDbIngestModule.class,
"HashDbIngestModule.moduleName");
public final static String MODULE_DESCRIPTION = NbBundle.getMessage(HashDbIngestModule.class,
"HashDbIngestModule.moduleDescription");
final public static String MODULE_VERSION = Version.getVersion();
public class HashDbIngestModule extends IngestModuleAdapter implements FileIngestModule {
private static final Logger logger = Logger.getLogger(HashDbIngestModule.class.getName());
private static final int MAX_COMMENT_SIZE = 500;
private HashDbSimpleConfigPanel simpleConfigPanel;
private HashDbConfigPanel advancedConfigPanel;
private IngestServices services;
private SleuthkitCase skCase;
private static int messageId = 0;
private int knownBadCount = 0;
private boolean calcHashesIsSet;
private static int messageId = 0; // RJCTODO: This is not thread safe
private final IngestServices services = IngestServices.getDefault();
private final Hash hasher = new Hash();
private final SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
private final HashDbManager hashDbManager = HashDbManager.getInstance();
private final HashLookupModuleSettings settings;
private List<HashDb> knownBadHashSets = new ArrayList<>();
private List<HashDb> knownHashSets = new ArrayList<>();
static long calctime = 0;
static long lookuptime = 0;
private final Hash hasher = new Hash();
private HashDbIngestModule() {
}
public static synchronized HashDbIngestModule getDefault() {
if (instance == null) {
instance = new HashDbIngestModule();
}
return instance;
}
@Override
public String getName() {
return MODULE_NAME;
}
@Override
public String getDescription() {
return MODULE_DESCRIPTION;
}
@Override
public String getVersion() {
return MODULE_VERSION;
}
@Override
public boolean hasSimpleConfiguration() {
return true;
}
private int knownBadCount = 0;
private long calctime = 0;
private long lookuptime = 0;
@Override
public javax.swing.JPanel getSimpleConfiguration(String context) {
if (null == simpleConfigPanel) {
simpleConfigPanel = new HashDbSimpleConfigPanel();
}
else {
simpleConfigPanel.load();
}
HashDbIngestModule(HashLookupModuleSettings settings) {
this.settings = settings;
}
return simpleConfigPanel;
}
@Override
public void saveSimpleConfiguration() {
if (simpleConfigPanel != null) {
simpleConfigPanel.store();
}
}
@Override
public boolean hasAdvancedConfiguration() {
return true;
}
@Override
public javax.swing.JPanel getAdvancedConfiguration(String context) {
if (advancedConfigPanel == null) {
advancedConfigPanel = new HashDbConfigPanel();
}
advancedConfigPanel.load();
return advancedConfigPanel;
}
@Override
public void saveAdvancedConfiguration() {
if (advancedConfigPanel != null) {
advancedConfigPanel.store();
}
if (simpleConfigPanel != null) {
simpleConfigPanel.load();
}
}
@Override
public void init(IngestModuleInit initContext) throws IngestModuleException {
services = IngestServices.getDefault();
skCase = Case.getCurrentCase().getSleuthkitCase();
HashDbManager hashDbManager = HashDbManager.getInstance();
getHashSetsUsableForIngest(hashDbManager.getKnownBadFileHashSets(), knownBadHashSets);
getHashSetsUsableForIngest(hashDbManager.getKnownFileHashSets(), knownHashSets);
calcHashesIsSet = hashDbManager.getAlwaysCalculateHashes();
@Override
public void startUp(org.sleuthkit.autopsy.ingest.IngestJobContext context) throws IngestModuleException {
getEnabledHashSets(hashDbManager.getKnownBadFileHashSets(), knownBadHashSets);
if (knownBadHashSets.isEmpty()) {
services.postMessage(IngestMessage.createWarningMessage(++messageId,
HashLookupModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.noKnownBadHashDbSetMsg"),
NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn")));
}
getEnabledHashSets(hashDbManager.getKnownFileHashSets(), knownHashSets);
if (knownHashSets.isEmpty()) {
services.postMessage(IngestMessage.createWarningMessage(++messageId,
this,
HashLookupModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.noKnownHashDbSetMsg"),
NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.knownFileSearchWillNotExecuteWarn")));
}
if (knownBadHashSets.isEmpty()) {
services.postMessage(IngestMessage.createWarningMessage(++messageId,
this,
NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.noKnownBadHashDbSetMsg"),
NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn")));
}
}
private void getHashSetsUsableForIngest(List<HashDb> hashDbs, List<HashDb> hashDbsForIngest) {
assert hashDbs != null;
assert hashDbsForIngest != null;
hashDbsForIngest.clear();
for (HashDb db : hashDbs) {
if (db.getSearchDuringIngest()) {
private void getEnabledHashSets(List<HashDb> hashSets, List<HashDb> enabledHashSets) {
assert hashSets != null;
assert enabledHashSets != null;
enabledHashSets.clear();
for (HashDb db : hashSets) {
if (settings.isHashSetEnabled(db.getHashSetName())) {
try {
if (db.hasIndex()) {
hashDbsForIngest.add(db);
enabledHashSets.add(db);
}
}
catch (TskCoreException ex) {
@ -192,23 +105,14 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
}
@Override
public boolean hasBackgroundJobsRunning() {
return false;
}
@Override
public ProcessResult process(PipelineContext<IngestModuleAbstractFile>pipelineContext, AbstractFile file) {
//skip unalloc
public ProcessResult process(AbstractFile file) {
// Skip unallocated space files.
if (file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) {
return IngestModuleAbstractFile.ProcessResult.OK;
return ProcessResult.OK;
}
return processFile(file);
}
private ProcessResult processFile(AbstractFile file) {
// bail out if we have no hashes set
if ((knownHashSets.isEmpty()) && (knownBadHashSets.isEmpty()) && (calcHashesIsSet == false)) {
if ((knownHashSets.isEmpty()) && (knownBadHashSets.isEmpty()) && (!settings.shouldCalculateHashes())) {
return ProcessResult.OK;
}
@ -223,7 +127,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
} catch (IOException ex) {
logger.log(Level.WARNING, "Error calculating hash of file " + name, ex);
services.postMessage(IngestMessage.createErrorMessage(++messageId,
HashDbIngestModule.this,
HashLookupModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.fileReadErrorMsg",
name),
@ -249,7 +153,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
} catch (TskException ex) {
logger.log(Level.WARNING, "Couldn't set known bad state for file " + name + " - see sleuthkit log for details", ex);
services.postMessage(IngestMessage.createErrorMessage(++messageId,
HashDbIngestModule.this,
HashLookupModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.hashLookupErrorMsg",
name),
@ -280,7 +184,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
} catch (TskException ex) {
logger.log(Level.WARNING, "Couldn't lookup known bad hash for file " + name + " - see sleuthkit log for details", ex);
services.postMessage(IngestMessage.createErrorMessage(++messageId,
HashDbIngestModule.this,
HashLookupModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.hashLookupErrorMsg",
name),
@ -304,14 +208,6 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
break;
} catch (TskException ex) {
logger.log(Level.WARNING, "Couldn't set known state for file " + name + " - see sleuthkit log for details", ex);
services.postMessage(IngestMessage.createErrorMessage(++messageId,
HashDbIngestModule.this,
NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.hashLookupErrorMsg",
name),
NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.settingsKnownStateErr",
name)));
ret = ProcessResult.ERROR;
}
}
@ -319,7 +215,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
} catch (TskException ex) {
logger.log(Level.WARNING, "Couldn't lookup known hash for file " + name + " - see sleuthkit log for details", ex);
services.postMessage(IngestMessage.createErrorMessage(++messageId,
HashDbIngestModule.this,
HashLookupModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.hashLookupErrorMsg",
name),
@ -333,9 +229,11 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
return ret;
}
private void postHashSetHitToBlackboard(AbstractFile abstractFile, String md5Hash, String hashSetName, String comment, boolean showInboxMessage) {
try {
String MODULE_NAME = NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.moduleName");
BlackboardArtifact badFile = abstractFile.newArtifact(ARTIFACT_TYPE.TSK_HASHSET_HIT);
//TODO Revisit usage of deprecated constructor as per TSK-583
//BlackboardAttribute att2 = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), MODULE_NAME, "Known Bad", hashSetName);
@ -376,7 +274,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
detailsSb.append("</table>");
services.postMessage(IngestMessage.createDataMessage(++messageId, this,
services.postMessage(IngestMessage.createDataMessage(++messageId, HashLookupModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.postToBB.knownBadMsg",
abstractFile.getName()),
@ -392,7 +290,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
@Override
public void complete() {
public void shutDown(boolean ingestJobCancelled) {
if ((!knownBadHashSets.isEmpty()) || (!knownHashSets.isEmpty())) {
StringBuilder detailsSb = new StringBuilder();
//details
@ -421,14 +319,10 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
detailsSb.append("</ul>");
services.postMessage(IngestMessage.createMessage(++messageId,
IngestMessage.MessageType.INFO,
this,
HashLookupModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"HashDbIngestModule.complete.hashLookupResults"),
detailsSb.toString()));
}
}
@Override
public void stop() {
}
}

View File

@ -0,0 +1,118 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.hashdatabase;
import java.util.ArrayList;
import java.util.List;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleSettingsPanel;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel;
/**
* A factory that creates file ingest modules that do hash database lookups.
*/
@ServiceProvider(service = IngestModuleFactory.class)
public class HashLookupModuleFactory extends IngestModuleFactoryAdapter {
private HashLookupModuleSettingsPanel moduleSettingsPanel = null;
@Override
public String getModuleDisplayName() {
return getModuleName();
}
static String getModuleName() {
return NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.moduleName");
}
@Override
public String getModuleDescription() {
return NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.moduleDescription");
}
@Override
public String getModuleVersionNumber() {
return Version.getVersion();
}
@Override
public IngestModuleSettings getDefaultModuleSettings() {
HashDbManager hashDbManager = HashDbManager.getInstance();
List<String> enabledHashSets = new ArrayList<>();
List<HashDbManager.HashDb> knownFileHashSets = hashDbManager.getKnownFileHashSets();
for (HashDbManager.HashDb db : knownFileHashSets) {
if (db.getSearchDuringIngest()) {
enabledHashSets.add(db.getHashSetName());
}
}
List<HashDbManager.HashDb> knownBadFileHashSets = hashDbManager.getKnownBadFileHashSets();
for (HashDbManager.HashDb db : knownBadFileHashSets) {
if (db.getSearchDuringIngest()) {
enabledHashSets.add(db.getHashSetName());
}
}
return new HashLookupModuleSettings(hashDbManager.getAlwaysCalculateHashes(), enabledHashSets);
}
@Override
public boolean hasModuleSettingsPanel() {
return true;
}
@Override
public IngestModuleSettingsPanel getModuleSettingsPanel(IngestModuleSettings settings) {
if (moduleSettingsPanel == null) {
moduleSettingsPanel = new HashLookupModuleSettingsPanel();
}
moduleSettingsPanel.load(); // RJCTODO: Fix this, use passed in settings
return moduleSettingsPanel;
}
@Override
public boolean hasGlobalSettingsPanel() {
return true;
}
@Override
public IngestModuleGlobalSetttingsPanel getGlobalSettingsPanel() {
HashLookupSettingsPanel globalSettingsPanel = new HashLookupSettingsPanel();
globalSettingsPanel.load();
return globalSettingsPanel;
}
@Override
public boolean isFileIngestModuleFactory() {
return true;
}
@Override
public FileIngestModule createFileIngestModule(IngestModuleSettings settings) {
assert settings instanceof HashLookupModuleSettings;
if (!(settings instanceof HashLookupModuleSettings)) {
throw new IllegalArgumentException("Expected settings argument to be instanceof HashLookupModuleSettings");
}
return new HashDbIngestModule((HashLookupModuleSettings) settings);
}
}

View File

@ -0,0 +1,47 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org *
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.hashdatabase;
import java.util.HashSet;
import java.util.List;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
/**
* Settings for a hash lookup file ingest module instance.
*/
final class HashLookupModuleSettings implements IngestModuleSettings {
private final HashSet<String> enabledHashSets = new HashSet<>();
private boolean shouldCalculateHashes = true;
HashLookupModuleSettings(boolean shouldCalculateHashes, List<String> enabledHashSetNames) {
this.shouldCalculateHashes = shouldCalculateHashes;
for (String hashSet : enabledHashSetNames) {
enabledHashSets.add(hashSet);
}
}
boolean shouldCalculateHashes() {
return shouldCalculateHashes;
}
boolean isHashSetEnabled(String hashSetName) {
return enabledHashSets.contains(hashSetName);
}
}

View File

@ -83,21 +83,21 @@
<Component class="javax.swing.JLabel" name="knownBadHashDbsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbSimpleConfigPanel.knownBadHashDbsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupModuleSettingsPanel.knownBadHashDbsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="knownHashDbsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbSimpleConfigPanel.knownHashDbsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupModuleSettingsPanel.knownHashDbsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="alwaysCalcHashesCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbSimpleConfigPanel.alwaysCalcHashesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 - 2013 Basis Technology Corp.
* Copyright 2011 - 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -16,11 +16,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.hashdatabase;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JOptionPane;
@ -28,47 +28,41 @@ import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
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 javax.swing.JPanel {
public class HashLookupModuleSettingsPanel extends IngestModuleSettingsPanel implements PropertyChangeListener {
private final HashDbManager hashDbManager = HashDbManager.getInstance();
private HashDatabasesTableModel knownTableModel;
private HashDatabasesTableModel knownBadTableModel;
public HashDbSimpleConfigPanel() {
HashLookupModuleSettingsPanel() {
knownTableModel = new HashDatabasesTableModel(HashDbManager.HashDb.KnownFilesType.KNOWN);
knownBadTableModel = new HashDatabasesTableModel(HashDbManager.HashDb.KnownFilesType.KNOWN_BAD);
initComponents();
customizeComponents();
}
private void customizeComponents() {
customizeHashDbsTable(jScrollPane1, knownHashTable, knownTableModel);
customizeHashDbsTable(jScrollPane2, knownBadHashTable, knownBadTableModel);
alwaysCalcHashesCheckbox.setSelected(HashDbManager.getInstance().getAlwaysCalculateHashes());
// Add a listener to the always calculate hashes checkbox component.
// The listener passes the user's selection on to the hash database manager.
alwaysCalcHashesCheckbox.addActionListener( new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
HashDbManager.getInstance().setAlwaysCalculateHashes(alwaysCalcHashesCheckbox.isSelected());
}
});
alwaysCalcHashesCheckbox.setSelected(hashDbManager.getAlwaysCalculateHashes());
load();
hashDbManager.addPropertyChangeListener(this);
}
private void customizeHashDbsTable(JScrollPane scrollPane, JTable table, HashDatabasesTableModel tableModel) {
table.setModel(tableModel);
table.setModel(tableModel);
table.setTableHeader(null);
table.setRowSelectionAllowed(false);
@ -82,36 +76,62 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
} else {
column.setPreferredWidth(((int) (width1 * 0.92)));
}
}
}
}
@Override
public void propertyChange(PropertyChangeEvent event) {
if (event.getPropertyName().equals(HashDbManager.SetEvt.DB_ADDED.name()) ||
event.getPropertyName().equals(HashDbManager.SetEvt.DB_DELETED.name())) {
load();
}
}
public void load() {
@Override
public IngestModuleSettings getSettings() {
List<String> enabledHashSets = new ArrayList<>();
List<HashDbManager.HashDb> knownFileHashSets = hashDbManager.getKnownFileHashSets();
for (HashDb db : knownFileHashSets) {
if (db.getSearchDuringIngest()) {
enabledHashSets.add(db.getHashSetName());
}
}
List<HashDbManager.HashDb> knownBadFileHashSets = hashDbManager.getKnownBadFileHashSets();
for (HashDb db : knownBadFileHashSets) {
if (db.getSearchDuringIngest()) {
enabledHashSets.add(db.getHashSetName());
}
}
return new HashLookupModuleSettings(alwaysCalcHashesCheckbox.isSelected(), enabledHashSets);
}
void load() {
knownTableModel.load();
knownBadTableModel.load();
}
public void store() {
HashDbManager.getInstance().save();
void store() {
hashDbManager.save();
}
private class HashDatabasesTableModel extends AbstractTableModel {
private final HashDbManager.HashDb.KnownFilesType hashDatabasesType;
private class HashDatabasesTableModel extends AbstractTableModel {
private final HashDbManager.HashDb.KnownFilesType hashDatabasesType;
private List<HashDb> hashDatabases;
HashDatabasesTableModel(HashDbManager.HashDb.KnownFilesType hashDatabasesType) {
this.hashDatabasesType = hashDatabasesType;
getHashDatabases();
}
private void getHashDatabases() {
if (HashDbManager.HashDb.KnownFilesType.KNOWN == hashDatabasesType) {
hashDatabases = HashDbManager.getInstance().getKnownFileHashSets();
hashDatabases = hashDbManager.getKnownFileHashSets();
} else {
hashDatabases = hashDbManager.getKnownBadFileHashSets();
}
else {
hashDatabases = HashDbManager.getInstance().getKnownBadFileHashSets();
}
}
}
private void load() {
getHashDatabases();
fireTableDataChanged();
@ -136,7 +156,7 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
return db.getHashSetName();
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return !IngestManager.getDefault().isIngestRunning() && columnIndex == 0;
@ -144,36 +164,34 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if(columnIndex == 0) {
if (columnIndex == 0) {
HashDb db = hashDatabases.get(rowIndex);
boolean dbHasIndex = false;
try {
dbHasIndex = db.hasIndex();
} catch (TskCoreException ex) {
Logger.getLogger(HashLookupModuleSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting info for " + db.getHashSetName() + " hash database", ex);
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbSimpleConfigPanel.class.getName()).log(Level.SEVERE, "Error getting info for " + db.getHashSetName() + " hash database", ex);
}
if(((Boolean) getValueAt(rowIndex, columnIndex)) || dbHasIndex) {
if (((Boolean) getValueAt(rowIndex, columnIndex)) || dbHasIndex) {
db.setSearchDuringIngest((Boolean) aValue);
}
else {
JOptionPane.showMessageDialog(HashDbSimpleConfigPanel.this,
NbBundle.getMessage(this.getClass(),
"HashDbSimpleConfigPanel.dlgMsg.mustIndexDbBeforeUse"));
} else {
JOptionPane.showMessageDialog(HashLookupModuleSettingsPanel.this,
NbBundle.getMessage(this.getClass(),
"HashDbSimpleConfigPanel.dlgMsg.mustIndexDbBeforeUse"));
}
}
}
@Override
public Class<?> getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
@ -194,11 +212,11 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
knownHashTable.setShowVerticalLines(false);
jScrollPane1.setViewportView(knownHashTable);
knownBadHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.knownBadHashDbsLabel.text")); // NOI18N
knownBadHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.knownBadHashDbsLabel.text")); // NOI18N
knownHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.knownHashDbsLabel.text")); // NOI18N
knownHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.knownHashDbsLabel.text")); // NOI18N
alwaysCalcHashesCheckbox.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.alwaysCalcHashesCheckbox.text")); // NOI18N
alwaysCalcHashesCheckbox.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text")); // NOI18N
alwaysCalcHashesCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
alwaysCalcHashesCheckboxActionPerformed(evt);
@ -256,9 +274,8 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
}// </editor-fold>//GEN-END:initComponents
private void alwaysCalcHashesCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_alwaysCalcHashesCheckboxActionPerformed
// TODO add your handling code here:
hashDbManager.setAlwaysCalculateHashes(alwaysCalcHashesCheckbox.isSelected());
}//GEN-LAST:event_alwaysCalcHashesCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox alwaysCalcHashesCheckbox;
private javax.swing.JScrollPane jScrollPane1;

View File

@ -5,21 +5,21 @@
<Component class="javax.swing.JLabel" name="jLabel2">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.jLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.jLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel4">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.jLabel4.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.jLabel4.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel6">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.jLabel6.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.jLabel6.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -29,7 +29,7 @@
<Font name="Tahoma" size="14" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.jButton3.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.jButton3.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -206,7 +206,7 @@
<Image iconType="3" name="/org/sleuthkit/autopsy/hashdatabase/warning16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.ingestWarningLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.ingestWarningLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -246,7 +246,7 @@
<Image iconType="3" name="/org/sleuthkit/autopsy/hashdatabase/delete16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.deleteDatabaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.deleteDatabaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[140, 25]"/>
@ -268,7 +268,7 @@
<Image iconType="3" name="/org/sleuthkit/autopsy/hashdatabase/import16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.importDatabaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.importDatabaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[140, 25]"/>
@ -287,70 +287,70 @@
<Component class="javax.swing.JLabel" name="hashDatabasesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.hashDatabasesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.hashDatabasesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="nameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.nameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.nameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="hashDbNameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.hashDbNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.hashDbNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="hashDbLocationLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.hashDbLocationLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.hashDbLocationLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="locationLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.locationLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.locationLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="typeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.typeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.typeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="hashDbTypeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.hashDbTypeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.hashDbTypeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="hashDbIndexStatusLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.hashDbIndexStatusLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.hashDbIndexStatusLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="indexLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.indexLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.indexLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="indexButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.indexButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.indexButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
@ -361,7 +361,7 @@
<Component class="javax.swing.JCheckBox" name="sendIngestMessagesCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.sendIngestMessagesCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.sendIngestMessagesCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
@ -371,14 +371,14 @@
<Component class="javax.swing.JLabel" name="informationLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.informationLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.informationLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="optionsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.optionsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.optionsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -392,7 +392,7 @@
<Image iconType="3" name="/org/sleuthkit/autopsy/hashdatabase/new16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.createDatabaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.createDatabaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[140, 25]"/>
@ -411,14 +411,14 @@
<Component class="javax.swing.JLabel" name="indexPathLabelLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.indexPathLabelLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.indexPathLabelLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="indexPathLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.indexPathLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashLookupSettingsPanel.indexPathLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>

View File

@ -44,25 +44,28 @@ import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb.KnownFilesType;
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 javax.swing.JPanel implements OptionsPanel {
public final class HashLookupSettingsPanel extends IngestModuleGlobalSetttingsPanel implements OptionsPanel {
private static final String NO_SELECTION_TEXT = NbBundle
.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.noSelectionText");
.getMessage(HashLookupSettingsPanel.class, "HashDbConfigPanel.noSelectionText");
private static final String ERROR_GETTING_PATH_TEXT = NbBundle
.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.errorGettingPathText");
.getMessage(HashLookupSettingsPanel.class, "HashDbConfigPanel.errorGettingPathText");
private static final String ERROR_GETTING_INDEX_STATUS_TEXT = NbBundle
.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.errorGettingIndexStatusText");
.getMessage(HashLookupSettingsPanel.class, "HashDbConfigPanel.errorGettingIndexStatusText");
private HashDbManager hashSetManager = HashDbManager.getInstance();
private HashSetTableModel hashSetTableModel = new HashSetTableModel();
public HashDbConfigPanel() {
private HashSetTableModel hashSetTableModel = new HashSetTableModel();
public HashLookupSettingsPanel() {
initComponents();
customizeComponents();
updateComponentsForNoSelection();
// Listen to the ingest modules to refresh the enabled/disabled state of
// the components in sync with file ingest.
IngestManager.addPropertyChangeListener(new PropertyChangeListener() {
@ -72,9 +75,9 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
updateComponents();
}
}
});
});
}
private void customizeComponents() {
setName(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.setName.hashSetConfig"));
this.ingestWarningLabel.setVisible(false);
@ -89,21 +92,20 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
updateComponents();
}
}
});
});
}
private void updateComponents() {
HashDb db = ((HashSetTable)hashSetTable).getSelection();
HashDb db = ((HashSetTable) hashSetTable).getSelection();
if (db != null) {
updateComponentsForSelection(db);
}
else {
} else {
updateComponentsForNoSelection();
}
}
}
private void updateComponentsForNoSelection() {
boolean ingestIsRunning = IngestManager.getDefault().isIngestRunning();
boolean ingestIsRunning = IngestManager.getDefault().isIngestRunning();
// Update descriptive labels.
hashDbNameLabel.setText(NO_SELECTION_TEXT);
@ -115,46 +117,44 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
hashDbIndexStatusLabel.setText(NO_SELECTION_TEXT);
hashDbIndexStatusLabel.setForeground(Color.black);
indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index"));
indexButton.setEnabled(false);
indexButton.setEnabled(false);
// Update ingest options.
sendIngestMessagesCheckBox.setSelected(false);
sendIngestMessagesCheckBox.setEnabled(false);
optionsLabel.setEnabled(false);
optionsSeparator.setEnabled(false);
// Update database action buttons.
createDatabaseButton.setEnabled(true);
importDatabaseButton.setEnabled(true);
deleteDatabaseButton.setEnabled(false);
// Update ingest in progress warning label.
ingestWarningLabel.setVisible(ingestIsRunning);
ingestWarningLabel.setVisible(ingestIsRunning);
}
private void updateComponentsForSelection(HashDb db) {
boolean ingestIsRunning = IngestManager.getDefault().isIngestRunning();
private void updateComponentsForSelection(HashDb db) {
boolean ingestIsRunning = IngestManager.getDefault().isIngestRunning();
// Update descriptive labels.
hashDbNameLabel.setText(db.getHashSetName());
hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName());
try {
hashDbLocationLabel.setText(shortenPath(db.getDatabasePath()));
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting database path of " + db.getHashSetName() + " hash database", ex);
} catch (TskCoreException ex) {
Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting database path of " + db.getHashSetName() + " hash database", ex);
hashDbLocationLabel.setText(ERROR_GETTING_PATH_TEXT);
}
try {
indexPathLabel.setText(shortenPath(db.getIndexPath()));
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index path of " + db.getHashSetName() + " hash database", ex);
} catch (TskCoreException ex) {
Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index path of " + db.getHashSetName() + " hash database", ex);
indexPathLabel.setText(ERROR_GETTING_PATH_TEXT);
}
// Update indexing components.
try {
if (db.isIndexing()) {
@ -164,13 +164,11 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexGen"));
hashDbIndexStatusLabel.setForeground(Color.black);
indexButton.setEnabled(false);
}
else if (db.hasIndex()) {
} else if (db.hasIndex()) {
if (db.hasIndexOnly()) {
hashDbIndexStatusLabel.setText(
NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexOnly"));
}
else {
} else {
hashDbIndexStatusLabel.setText(
NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexed"));
}
@ -179,28 +177,25 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
indexButton.setText(
NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.reIndex"));
indexButton.setEnabled(true);
}
else {
} else {
indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index"));
indexButton.setEnabled(false);
indexButton.setEnabled(false);
}
}
else {
} else {
hashDbIndexStatusLabel.setText(
NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.noIndex"));
hashDbIndexStatusLabel.setForeground(Color.red);
indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index"));
indexButton.setEnabled(true);
}
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index state of hash database", ex);
} catch (TskCoreException ex) {
Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index state of hash database", ex);
hashDbIndexStatusLabel.setText(ERROR_GETTING_INDEX_STATUS_TEXT);
hashDbIndexStatusLabel.setForeground(Color.red);
indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index"));
indexButton.setEnabled(false);
}
}
// Disable the indexing button if ingest is in progress.
if (ingestIsRunning) {
indexButton.setEnabled(false);
@ -211,36 +206,30 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
sendIngestMessagesCheckBox.setEnabled(!ingestIsRunning && db.getSearchDuringIngest() && db.getKnownFilesType().equals(KnownFilesType.KNOWN_BAD));
optionsLabel.setEnabled(!ingestIsRunning);
optionsSeparator.setEnabled(!ingestIsRunning);
// Update database action buttons.
createDatabaseButton.setEnabled(true);
importDatabaseButton.setEnabled(true);
deleteDatabaseButton.setEnabled(!ingestIsRunning);
// Update ingest in progress warning label.
ingestWarningLabel.setVisible(ingestIsRunning);
ingestWarningLabel.setVisible(ingestIsRunning);
}
private static String shortenPath(String 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));
}
return shortenedPath;
}
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());
}
@Override
public void load() {
hashSetTable.clearSelection();
hashSetTableModel.refreshModel();
private boolean isFileIngestStatusChangeEvent(PropertyChangeEvent evt) {
return evt.getPropertyName().equals(IngestManager.IngestEvent.STARTED.toString()) || evt.getPropertyName().equals(IngestManager.IngestEvent.COMPLETED.toString()) || evt.getPropertyName().equals(IngestManager.IngestEvent.STOPPED.toString());
}
@Override
public void store() {
public void saveSettings() {
//Checking for for any unindexed databases
List<HashDb> unindexed = new ArrayList<>();
for (HashDb hashSet : hashSetManager.getAllHashSets()) {
@ -248,66 +237,76 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
if (!hashSet.hasIndex()) {
unindexed.add(hashSet);
}
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex);
} catch (TskCoreException ex) {
Logger.getLogger(HashLookupSettingsPanel.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.size() == 1){
if (unindexed.size() == 1) {
showInvalidIndex(false, unindexed);
}
else if (unindexed.size() > 1){
} else if (unindexed.size() > 1) {
showInvalidIndex(true, unindexed);
}
hashSetManager.save();
hashSetManager.save();
}
@Override
public void load() {
hashSetTable.clearSelection();
hashSetTableModel.refreshModel();
}
@Override
public void store() {
saveSettings();
}
public void cancel() {
HashDbManager.getInstance().loadLastSavedConfiguration();
HashDbManager.getInstance().loadLastSavedConfiguration();
}
void removeThese(List<HashDb> toRemove) {
for (HashDb hashDb : toRemove) {
hashSetManager.removeHashDatabaseInternal(hashDb);
}
hashSetTableModel.refreshModel();
hashSetTableModel.refreshModel();
}
/**
* Displays the popup box that tells user that some of his databases are unindexed, along with solutions.
* This method is related to ModalNoButtons, to be removed at a later date.
* Displays the popup box that tells user that some of his databases are
* 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 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 message;
for(HashDb hdb : unindexed){
total+= "\n" + hdb.getHashSetName();
for (HashDb hdb : unindexed) {
total += "\n" + hdb.getHashSetName();
}
if(plural){
if (plural) {
message = NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.dbsNotIndexedMsg", total);
}
else{
} else {
message = NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.dbNotIndexedMsg", total);
}
int res = JOptionPane.showConfirmDialog(this, message,
NbBundle.getMessage(this.getClass(),
"HashDbConfigPanel.unindexedDbsMsg"),
JOptionPane.YES_NO_OPTION);
if(res == JOptionPane.YES_OPTION){
ModalNoButtons indexingDialog = new ModalNoButtons(this, new Frame(),unindexed);
NbBundle.getMessage(this.getClass(),
"HashDbConfigPanel.unindexedDbsMsg"),
JOptionPane.YES_NO_OPTION);
if (res == JOptionPane.YES_OPTION) {
ModalNoButtons indexingDialog = new ModalNoButtons(this, new Frame(), unindexed);
indexingDialog.setLocationRelativeTo(null);
indexingDialog.setVisible(true);
indexingDialog.setModal(true);
hashSetTableModel.refreshModel();
}
if(res == JOptionPane.NO_OPTION){
if (res == JOptionPane.NO_OPTION) {
JOptionPane.showMessageDialog(this, NbBundle.getMessage(this.getClass(),
"HashDbConfigPanel.allUnindexedDbsRmFromListMsg"));
"HashDbConfigPanel.allUnindexedDbsRmFromListMsg"));
removeThese(unindexed);
}
}
@ -315,30 +314,30 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
boolean valid() {
return true;
}
/**
/**
* This class implements a table for displaying configured hash sets.
*/
*/
private class HashSetTable extends JTable {
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
// Use the hash set name as the cell text.
JComponent cellRenderer = (JComponent)super.prepareRenderer(renderer, row, column);
cellRenderer.setToolTipText((String)getValueAt(row, column));
JComponent cellRenderer = (JComponent) super.prepareRenderer(renderer, row, column);
cellRenderer.setToolTipText((String) getValueAt(row, column));
// 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
// in red.
if (hashSetTableModel.indexExists(row)){
if (hashSetTableModel.indexExists(row)) {
cellRenderer.setForeground(Color.black);
}
else{
} else {
cellRenderer.setForeground(Color.red);
}
return cellRenderer;
}
public HashDb getSelection() {
return hashSetTableModel.getHashSetAt(getSelectionModel().getMinSelectionIndex());
}
@ -348,19 +347,20 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
getSelectionModel().setSelectionInterval(index, index);
}
}
public void selectRowByName(String name) {
setSelection(hashSetTableModel.getIndexByName(name));
}
}
}
/**
* This class implements the table model for the table used to display
* configured hash sets.
*/
private class HashSetTableModel extends AbstractTableModel {
*/
private class HashSetTableModel extends AbstractTableModel {
List<HashDb> hashSets = HashDbManager.getInstance().getAllHashSets();
@Override
public int getColumnCount() {
return 1;
@ -380,17 +380,16 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
public Object getValueAt(int rowIndex, int columnIndex) {
return hashSets.get(rowIndex).getHashSetName();
}
private boolean indexExists(int rowIndex){
private boolean indexExists(int rowIndex) {
try {
return hashSets.get(rowIndex).hasIndex();
}
catch (TskCoreException ex) {
Logger.getLogger(HashSetTableModel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex);
} catch (TskCoreException ex) {
Logger.getLogger(HashSetTableModel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex);
return false;
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
@ -409,32 +408,31 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
HashDb getHashSetAt(int index) {
if (!hashSets.isEmpty() && index >= 0 && index < hashSets.size()) {
return hashSets.get(index);
}
else {
return hashSets.get(index);
} else {
return null;
}
}
int getIndexByName(String name) {
for (int i = 0; i < hashSets.size(); ++i) {
if (hashSets.get(i).getHashSetName().equals(name)) {
return i;
}
}
return i;
}
}
return -1;
}
void refreshModel() {
hashSets = HashDbManager.getInstance().getAllHashSets();
refreshDisplay();
}
void refreshDisplay() {
fireTableDataChanged();
fireTableDataChanged();
}
}
/**
* 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
@ -471,20 +469,20 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
indexPathLabelLabel = new javax.swing.JLabel();
indexPathLabel = new javax.swing.JLabel();
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jLabel2.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.jLabel2.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jLabel4.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.jLabel4.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jLabel6.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.jLabel6.text")); // NOI18N
jButton3.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jButton3.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.jButton3.text")); // NOI18N
setMinimumSize(new java.awt.Dimension(700, 500));
setPreferredSize(new java.awt.Dimension(700, 500));
ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/warning16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.ingestWarningLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.ingestWarningLabel.text")); // NOI18N
hashSetTable.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
@ -504,7 +502,7 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
jScrollPane1.setViewportView(hashSetTable);
deleteDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/delete16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(deleteDatabaseButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.deleteDatabaseButton.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(deleteDatabaseButton, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.deleteDatabaseButton.text")); // NOI18N
deleteDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25));
deleteDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25));
deleteDatabaseButton.setPreferredSize(new java.awt.Dimension(140, 25));
@ -515,7 +513,7 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
});
importDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/import16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(importDatabaseButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.importDatabaseButton.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(importDatabaseButton, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.importDatabaseButton.text")); // NOI18N
importDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25));
importDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25));
importDatabaseButton.setPreferredSize(new java.awt.Dimension(140, 25));
@ -525,25 +523,25 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
}
});
org.openide.awt.Mnemonics.setLocalizedText(hashDatabasesLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDatabasesLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(hashDatabasesLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDatabasesLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.nameLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.nameLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(hashDbNameLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDbNameLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(hashDbNameLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDbNameLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(hashDbLocationLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDbLocationLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(hashDbLocationLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDbLocationLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(locationLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.locationLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(locationLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.locationLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(typeLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.typeLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(typeLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.typeLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(hashDbTypeLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDbTypeLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(hashDbTypeLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDbTypeLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(hashDbIndexStatusLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDbIndexStatusLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(hashDbIndexStatusLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDbIndexStatusLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(indexLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.indexLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(indexLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.indexLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(indexButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.indexButton.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(indexButton, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.indexButton.text")); // NOI18N
indexButton.setEnabled(false);
indexButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -551,19 +549,19 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
}
});
org.openide.awt.Mnemonics.setLocalizedText(sendIngestMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.sendIngestMessagesCheckBox.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(sendIngestMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.sendIngestMessagesCheckBox.text")); // NOI18N
sendIngestMessagesCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
sendIngestMessagesCheckBoxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(informationLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.informationLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(informationLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.informationLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.optionsLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.optionsLabel.text")); // NOI18N
createDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/new16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(createDatabaseButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.createDatabaseButton.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(createDatabaseButton, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.createDatabaseButton.text")); // NOI18N
createDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25));
createDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25));
createDatabaseButton.setPreferredSize(new java.awt.Dimension(140, 25));
@ -573,9 +571,9 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
}
});
org.openide.awt.Mnemonics.setLocalizedText(indexPathLabelLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.indexPathLabelLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(indexPathLabelLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.indexPathLabelLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(indexPathLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.indexPathLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(indexPathLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.indexPathLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
@ -692,22 +690,22 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
}// </editor-fold>//GEN-END:initComponents
private void indexButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexButtonActionPerformed
final HashDb hashDb = ((HashSetTable)hashSetTable).getSelection();
assert hashDb != null;
final HashDb hashDb = ((HashSetTable) hashSetTable).getSelection();
assert hashDb != null;
// Add a listener for the INDEXING_DONE event. This listener will update
// the UI.
hashDb.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
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)) {
updateComponents();
}
hashSetTableModel.refreshDisplay();
}
}
}
});
// Display a modal dialog box to kick off the indexing on a worker thread
@ -718,17 +716,17 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
ModalNoButtons indexDialog = new ModalNoButtons(this, new Frame(), hashDb);
indexDialog.setLocationRelativeTo(null);
indexDialog.setVisible(true);
indexDialog.setModal(true);
indexDialog.setModal(true);
}//GEN-LAST:event_indexButtonActionPerformed
private void deleteDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteDatabaseButtonActionPerformed
if (JOptionPane.showConfirmDialog(null,
NbBundle.getMessage(this.getClass(),
"HashDbConfigPanel.deleteDbActionConfirmMsg"),
NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.deleteDbActionMsg"),
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) {
HashDb hashDb = ((HashSetTable)hashSetTable).getSelection();
NbBundle.getMessage(this.getClass(),
"HashDbConfigPanel.deleteDbActionConfirmMsg"),
NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.deleteDbActionMsg"),
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) {
HashDb hashDb = ((HashSetTable) hashSetTable).getSelection();
if (hashDb != null) {
hashSetManager.removeHashDatabaseInternal(hashDb);
hashSetTableModel.refreshModel();
@ -738,16 +736,16 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
private void hashSetTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_hashSetTableKeyPressed
if (evt.getKeyCode() == KeyEvent.VK_DELETE) {
HashDb hashDb = ((HashSetTable)hashSetTable).getSelection();
HashDb hashDb = ((HashSetTable) hashSetTable).getSelection();
if (hashDb != null) {
hashSetManager.removeHashDatabaseInternal(hashDb);
hashSetTableModel.refreshModel();
}
}
}
}//GEN-LAST:event_hashSetTableKeyPressed
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) {
hashDb.setSendIngestMessages(sendIngestMessagesCheckBox.isSelected());
}
@ -757,18 +755,17 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
HashDb hashDb = new HashDbImportDatabaseDialog().getHashDatabase();
if (null != hashDb) {
hashSetTableModel.refreshModel();
((HashSetTable)hashSetTable).selectRowByName(hashDb.getHashSetName());
}
((HashSetTable) hashSetTable).selectRowByName(hashDb.getHashSetName());
}
}//GEN-LAST:event_importDatabaseButtonActionPerformed
private void createDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createDatabaseButtonActionPerformed
HashDb hashDb = new HashDbCreateDatabaseDialog().getHashDatabase();
if (null != hashDb) {
hashSetTableModel.refreshModel();
((HashSetTable)hashSetTable).selectRowByName(hashDb.getHashSetName());
((HashSetTable) hashSetTable).selectRowByName(hashDb.getHashSetName());
}
}//GEN-LAST:event_createDatabaseButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton createDatabaseButton;
private javax.swing.JButton deleteDatabaseButton;

View File

@ -42,7 +42,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen
List<HashDb> unindexed;
HashDb toIndex;
HashDbConfigPanel hdbmp;
HashLookupSettingsPanel hdbmp;
int length = 0;
int currentcount = 1;
String currentDb = "";
@ -53,7 +53,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen
* @param parent Swing parent frame.
* @param unindexed the list of unindexed databases to index.
*/
ModalNoButtons(HashDbConfigPanel hdbmp, java.awt.Frame parent, List<HashDb> unindexed) {
ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, List<HashDb> unindexed) {
super(parent, NbBundle.getMessage(ModalNoButtons.class, "ModalNoButtons.indexingDbsTitle"), true);
this.unindexed = unindexed;
this.toIndex = null;
@ -68,7 +68,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen
* @param parent Swing parent frame.
* @param unindexed The unindexed database to index.
*/
ModalNoButtons(HashDbConfigPanel hdbmp, java.awt.Frame parent, HashDb unindexed){
ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, HashDb unindexed){
super(parent, NbBundle.getMessage(ModalNoButtons.class, "ModalNoButtons.indexingDbTitle"), true);
this.unindexed = null;
this.toIndex = unindexed;

View File

@ -61,8 +61,8 @@ import org.sleuthkit.datamodel.ReadContentInputStream;
//"application/xml-dtd",
);
AbstractFileHtmlExtract() {
this.module = KeywordSearchIngestModule.getDefault();
AbstractFileHtmlExtract(KeywordSearchIngestModule module) {
this.module = module;
ingester = Server.getIngester();
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -60,8 +60,8 @@ class AbstractFileStringExtract implements AbstractFileExtract {
//STRING_CHUNK_BUF[1] = (byte) 0xBB;
//STRING_CHUNK_BUF[2] = (byte) 0xBF;
//}
public AbstractFileStringExtract() {
this.module = KeywordSearchIngestModule.getDefault();
public AbstractFileStringExtract(KeywordSearchIngestModule module) {
this.module = module;
this.ingester = Server.getIngester();
this.extractScripts.add(DEFAULT_SCRIPT);
}

View File

@ -35,7 +35,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.apache.tika.Tika;
@ -57,7 +56,7 @@ import org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException;
*/
class AbstractFileTikaTextExtract implements AbstractFileExtract {
private static final Logger logger = Logger.getLogger(IngestModuleAbstractFile.class.getName());
private static final Logger logger = Logger.getLogger(AbstractFileTikaTextExtract.class.getName());
private static final Charset OUTPUT_CHARSET = Server.DEFAULT_INDEXED_TEXT_CHARSET;
static final int MAX_EXTR_TEXT_CHARS = 512 * 1024;
private static final int SINGLE_READ_CHARS = 1024;
@ -72,8 +71,8 @@ class AbstractFileTikaTextExtract implements AbstractFileExtract {
private final ExecutorService tikaParseExecutor = Executors.newSingleThreadExecutor();
private final List<String> TIKA_SUPPORTED_TYPES = new ArrayList<>();
AbstractFileTikaTextExtract() {
this.module = KeywordSearchIngestModule.getDefault();
AbstractFileTikaTextExtract(KeywordSearchIngestModule module) {
this.module = module;
ingester = Server.getIngester();
Set<MediaType> mediaTypes = new Tika().getParser().getSupportedTypes(new ParseContext());

View File

@ -86,10 +86,10 @@ abstract class AbstractKeywordSearchPerformer extends javax.swing.JPanel impleme
@Override
public void search() {
boolean isRunning = IngestManager.getDefault().isModuleRunning(KeywordSearchIngestModule.getDefault());
boolean isIngestRunning = IngestManager.getDefault().isIngestRunning();
if (filesIndexed == 0) {
if (isRunning) {
if (isIngestRunning) {
KeywordSearchUtil.displayDialog(keywordSearchErrorDialogHeader, NbBundle.getMessage(this.getClass(),
"AbstractKeywordSearchPerformer.search.noFilesInIdxMsg",
KeywordSearchSettings.getUpdateFrequency().getTime()), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.ERROR);
@ -101,7 +101,7 @@ abstract class AbstractKeywordSearchPerformer extends javax.swing.JPanel impleme
}
//check if keyword search module ingest is running (indexing, etc)
if (isRunning) {
if (isIngestRunning) {
if (KeywordSearchUtil.displayConfirmDialog(org.openide.util.NbBundle.getMessage(this.getClass(), "AbstractKeywordSearchPerformer.search.searchIngestInProgressTitle"),
NbBundle.getMessage(this.getClass(), "AbstractKeywordSearchPerformer.search.ingestInProgressBody"), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.WARN) == false) {
return;

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -76,8 +76,6 @@ class Keyword {
return NbBundle.getMessage(this.getClass(), "Keyword.toString.text", keywordString, isLiteral, keywordType);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {

View File

@ -0,0 +1,118 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.keywordsearch;
import java.util.Date;
import java.util.List;
public class KeywordList {
private String name;
private Date created;
private Date modified;
private Boolean useForIngest;
private Boolean ingestMessages;
private List<Keyword> keywords;
private Boolean locked;
KeywordList(String name, Date created, Date modified, Boolean useForIngest, Boolean ingestMessages, List<Keyword> keywords, boolean locked) {
this.name = name;
this.created = created;
this.modified = modified;
this.useForIngest = useForIngest;
this.ingestMessages = ingestMessages;
this.keywords = keywords;
this.locked = locked;
}
KeywordList(String name, Date created, Date modified, Boolean useForIngest, Boolean ingestMessages, List<Keyword> keywords) {
this(name, created, modified, useForIngest, ingestMessages, keywords, false);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final KeywordList other = (KeywordList) obj;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 5;
return hash;
}
String getName() {
return name;
}
Date getDateCreated() {
return created;
}
Date getDateModified() {
return modified;
}
Boolean getUseForIngest() {
return useForIngest;
}
void setUseForIngest(boolean use) {
this.useForIngest = use;
}
Boolean getIngestMessages() {
return ingestMessages;
}
void setIngestMessages(boolean ingestMessages) {
this.ingestMessages = ingestMessages;
}
List<Keyword> getKeywords() {
return keywords;
}
boolean hasKeyword(Keyword keyword) {
return keywords.contains(keyword);
}
boolean hasKeyword(String keyword) {
//note, this ignores isLiteral
for (Keyword k : keywords) {
if (k.getQuery().equals(keyword)) {
return true;
}
}
return false;
}
Boolean isLocked() {
return locked;
}
}

View File

@ -0,0 +1,101 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.keywordsearch;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Keeps track, by name, of the keyword lists to be used for file ingest.
*/
// 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
// search file ingest module.
final class KeywordListsManager {
private static KeywordListsManager instance = null;
private final Logger logger = Logger.getLogger(KeywordListsManager.class.getName());
private final List<String> keywordListNames = new ArrayList<>();
private final List<Keyword> keywords = new ArrayList<>();
/**
* Gets the keyword lists manager singleton.
*/
static synchronized KeywordListsManager getInstance() {
if (null == instance) {
instance = new KeywordListsManager();
}
return instance;
}
private KeywordListsManager() {
addKeywordListsForFileIngest(null);
}
/**
* Sets the keyword lists to be used for ingest. The lists that are used
* will be the union of the lists enabled using the keyword search global
* options panel and a selection, possibly empty, of the disabled lists.
*
* @param listNames The names of disabled lists to temporarily enable
*/
synchronized void addKeywordListsForFileIngest(List<String> listNames) {
keywords.clear();
keywordListNames.clear();
StringBuilder logMessage = new StringBuilder();
KeywordSearchListsXML globalKeywordSearchOptions = KeywordSearchListsXML.getCurrent();
for (KeywordList list : globalKeywordSearchOptions.getListsL()) {
String listName = list.getName();
if ((list.getUseForIngest() == true) || (listNames != null && listNames.contains(listName))) {
keywordListNames.add(listName);
logMessage.append(listName).append(" ");
}
for (Keyword keyword : list.getKeywords()) {
if (!keywords.contains(keyword)) {
keywords.add(keyword);
}
}
}
logger.log(Level.INFO, "Keyword lists for file ingest set to: {0}", logMessage.toString());
}
/**
* Returns the keyword lists to be used for ingest, by name.
*
* @return The names of the enabled keyword lists
*/
synchronized List<String> getNamesOfKeywordListsForFileIngest() {
return new ArrayList<>(keywordListNames);
}
/**
* Indicates whether or not there are currently keywords for which to search
* during ingest.
*
* @return True if there are no keywords specified, false otherwise
*/
synchronized boolean hasNoKeywordsForSearch() {
return (keywords.isEmpty());
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 - 2013 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -16,16 +16,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.keywordsearch;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSetttingsPanel;
/**
* Container panel for keyword search advanced configuration options
* Global options panel for keyword searching.
*/
public final class KeywordSearchConfigurationPanel extends javax.swing.JPanel implements OptionsPanel {
final class KeywordSearchConfigurationPanel extends IngestModuleGlobalSetttingsPanel implements OptionsPanel {
private KeywordSearchConfigurationPanel1 listsPanel;
private KeywordSearchConfigurationPanel3 languagesPanel;
@ -35,7 +35,7 @@ public final class KeywordSearchConfigurationPanel extends javax.swing.JPanel im
initComponents();
customizeComponents();
}
private void customizeComponents() {
setName(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.title"));
listsPanel = new KeywordSearchConfigurationPanel1();
@ -71,38 +71,37 @@ public final class KeywordSearchConfigurationPanel extends javax.swing.JPanel im
);
}// </editor-fold>//GEN-END:initComponents
/**
* Load each of the tabs and reload the XML.
*/
@Override
public void load() {
// Deselect all table rows
// This calls actually clears the component.
listsPanel.load();
languagesPanel.load();
generalPanel.load();
// Reload the XML to avoid 'ghost' vars
KeywordSearchListsXML.getCurrent().reload();
}
/**
* Store each panel's settings.
*/
@Override
public void store() {
public void saveSettings() {
listsPanel.store();
languagesPanel.store();
generalPanel.store();
generalPanel.store();
}
@Override
public void store() {
saveSettings();
}
public void cancel() {
KeywordSearchListsXML.getCurrent().reload();
KeywordSearchListsXML.getCurrent().reload();
}
boolean valid() {
// TODO check whether form is consistent and complete
return true;
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTabbedPane tabbedPane;
// End of variables declaration//GEN-END:variables

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -17,18 +17,12 @@
* limitations under the License.
*/
/*
* KeywordSearchConfigurationPanel1.java
*
* Created on Feb 28, 2012, 4:12:47 PM
*/
package org.sleuthkit.autopsy.keywordsearch;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.JOptionPane;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
@ -43,9 +37,7 @@ class KeywordSearchConfigurationPanel1 extends javax.swing.JPanel implements Opt
private static final Logger logger = Logger.getLogger(KeywordSearchConfigurationPanel1.class.getName());
private static final String KEYWORD_CONFIG_NAME = org.openide.util.NbBundle.getMessage(KeywordSearchPanel.class, "ListBundleConfig");
/** Creates new form KeywordSearchConfigurationPanel1 */
KeywordSearchConfigurationPanel1() {
KeywordSearchConfigurationPanel1() {
initComponents();
customizeComponents();
setName(KEYWORD_CONFIG_NAME);
@ -80,7 +72,7 @@ class KeywordSearchConfigurationPanel1 extends javax.swing.JPanel implements Opt
public void actionPerformed(ActionEvent e) {
final String FEATURE_NAME = "Save Keyword List";
KeywordSearchListsXML writer = KeywordSearchListsXML.getCurrent();
KeywordSearchListsAbstract.KeywordSearchList currentKeywordList = editListPanel.getCurrentKeywordList();
KeywordList currentKeywordList = editListPanel.getCurrentKeywordList();
List<Keyword> keywords = currentKeywordList.getKeywords();
if (keywords.isEmpty()) {
@ -121,8 +113,6 @@ class KeywordSearchConfigurationPanel1 extends javax.swing.JPanel implements Opt
writer.addList(listName, keywords);
KeywordSearchUtil.displayDialog(FEATURE_NAME, NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.kwListSavedMsg", listName), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.INFO);
}
//currentKeywordList = writer.getList(listName);
listsManagementPanel.resync();
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012 Basis Technology Corp.
* Copyright 2012-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -22,7 +22,6 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.apache.solr.client.solrj.SolrServerException;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.keywordsearch.KeywordSearchIngestModule.UpdateFrequency;
@ -45,8 +44,7 @@ class KeywordSearchConfigurationPanel2 extends javax.swing.JPanel implements Opt
private void activateWidgets() {
skipNSRLCheckBox.setSelected(KeywordSearchSettings.getSkipKnown());
showSnippetsCB.setSelected(KeywordSearchSettings.getShowSnippets());
boolean enable = !IngestManager.getDefault().isIngestRunning()
&& !IngestManager.getDefault().isModuleRunning(KeywordSearchIngestModule.getDefault());
boolean enable = !IngestManager.getDefault().isIngestRunning();
skipNSRLCheckBox.setEnabled(enable);
setTimeSettingEnabled(enable);
@ -70,7 +68,6 @@ class KeywordSearchConfigurationPanel2 extends javax.swing.JPanel implements Opt
timeRadioButton3.setSelected(true);
break;
}
}
/**
@ -205,7 +202,6 @@ class KeywordSearchConfigurationPanel2 extends javax.swing.JPanel implements Opt
.addContainerGap(116, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel chunksLabel;
private javax.swing.JLabel chunksValLabel;
@ -248,14 +244,11 @@ class KeywordSearchConfigurationPanel2 extends javax.swing.JPanel implements Opt
private UpdateFrequency getSelectedTimeValue() {
if (timeRadioButton1.isSelected()) {
return UpdateFrequency.FAST;
}
else if (timeRadioButton2.isSelected()) {
} else if (timeRadioButton2.isSelected()) {
return UpdateFrequency.AVG;
}
else if (timeRadioButton3.isSelected()) {
} else if (timeRadioButton3.isSelected()) {
return UpdateFrequency.SLOW;
}
else if (timeRadioButton4.isSelected()) {
} else if (timeRadioButton4.isSelected()) {
return UpdateFrequency.SLOWEST;
}
return UpdateFrequency.DEFAULT;
@ -273,36 +266,28 @@ class KeywordSearchConfigurationPanel2 extends javax.swing.JPanel implements Opt
try {
filesIndexedValue.setText(Integer.toString(KeywordSearch.getServer().queryNumIndexedFiles()));
chunksValLabel.setText(Integer.toString(KeywordSearch.getServer().queryNumIndexedChunks()));
} catch (KeywordSearchModuleException ex) {
logger.log(Level.WARNING, "Could not get number of indexed files/chunks");
} catch (NoOpenCoreException ex) {
} catch (KeywordSearchModuleException | NoOpenCoreException ex) {
logger.log(Level.WARNING, "Could not get number of indexed files/chunks");
}
KeywordSearch.addNumIndexedFilesChangeListener(
new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String changed = evt.getPropertyName();
Object newValue = evt.getNewValue();
@Override
public void propertyChange(PropertyChangeEvent evt) {
String changed = evt.getPropertyName();
Object newValue = evt.getNewValue();
if (changed.equals(KeywordSearch.NUM_FILES_CHANGE_EVT)) {
int newFilesIndexed = ((Integer) newValue).intValue();
filesIndexedValue.setText(Integer.toString(newFilesIndexed));
try {
chunksValLabel.setText(Integer.toString(KeywordSearch.getServer().queryNumIndexedChunks()));
} catch (KeywordSearchModuleException ex) {
logger.log(Level.WARNING, "Could not get number of indexed chunks");
if (changed.equals(KeywordSearch.NUM_FILES_CHANGE_EVT)) {
int newFilesIndexed = ((Integer) newValue).intValue();
filesIndexedValue.setText(Integer.toString(newFilesIndexed));
try {
chunksValLabel.setText(Integer.toString(KeywordSearch.getServer().queryNumIndexedChunks()));
} catch (KeywordSearchModuleException | NoOpenCoreException ex) {
logger.log(Level.WARNING, "Could not get number of indexed chunks");
} catch (NoOpenCoreException ex) {
logger.log(Level.WARNING, "Could not get number of indexed chunks");
}
}
}
});
}
}
});
}
}

View File

@ -149,8 +149,7 @@ class KeywordSearchConfigurationPanel3 extends javax.swing.JPanel implements Opt
enableUTF8Checkbox.setSelected(utf8);
final boolean extractEnabled = utf16 || utf8;
boolean ingestNotRunning = !IngestManager.getDefault().isIngestRunning()
&& ! IngestManager.getDefault().isModuleRunning(KeywordSearchIngestModule.getDefault());
boolean ingestNotRunning = !IngestManager.getDefault().isIngestRunning() && !IngestManager.getDefault().isIngestRunning();
//enable / disable checboxes
activateScriptsCheckboxes(extractEnabled && ingestNotRunning);
enableUTF16Checkbox.setEnabled(ingestNotRunning);

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -17,7 +17,6 @@
* limitations under the License.
*/
package org.sleuthkit.autopsy.keywordsearch;
import java.awt.Component;
@ -30,7 +29,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import java.util.regex.Pattern;
@ -49,7 +47,7 @@ import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent;
import org.sleuthkit.autopsy.ingest.IngestManager.IngestEvent;
import org.sleuthkit.datamodel.BlackboardAttribute;
/**
@ -59,7 +57,7 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec
private static Logger logger = Logger.getLogger(KeywordSearchEditListPanel.class.getName());
private KeywordTableModel tableModel;
private KeywordSearchListsAbstract.KeywordSearchList currentKeywordList;
private KeywordList currentKeywordList;
private boolean ingestRunning;
@ -161,7 +159,7 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec
if (IngestManager.getDefault().isModuleRunning(KeywordSearchIngestModule.getDefault())) {
if (IngestManager.getDefault().isIngestRunning()) {
initIngest(0);
} else {
initIngest(1);
@ -173,14 +171,14 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec
public void propertyChange(PropertyChangeEvent evt) {
String changed = evt.getPropertyName();
Object oldValue = evt.getOldValue();
if (changed.equals(IngestModuleEvent.COMPLETED.toString() )
&& ((String) oldValue).equals(KeywordSearchIngestModule.MODULE_NAME)) {
if (changed.equals(IngestEvent.COMPLETED.toString() )
&& ((String) oldValue).equals(KeywordSearchModuleFactory.getModuleName())) {
initIngest(1);
} else if (changed.equals(IngestModuleEvent.STARTED.toString() )
&& ((String) oldValue).equals(KeywordSearchIngestModule.MODULE_NAME)) {
} else if (changed.equals(IngestEvent.STARTED.toString() )
&& ((String) oldValue).equals(KeywordSearchModuleFactory.getModuleName())) {
initIngest(0);
} else if (changed.equals(IngestModuleEvent.STOPPED.toString() )
&& ((String) oldValue).equals(KeywordSearchIngestModule.MODULE_NAME)) {
} else if (changed.equals(IngestEvent.STOPPED.toString() )
&& ((String) oldValue).equals(KeywordSearchModuleFactory.getModuleName())) {
initIngest(1);
}
}
@ -221,9 +219,9 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec
boolean noKeywords = !listSet ? true : currentKeywordList.getKeywords().isEmpty();
// Certain buttons will be disabled if ingest is ongoing on this list
List<String> ingestLists = new ArrayList<String>();
List<String> ingestLists = new ArrayList<>();
if (ingestOngoing) {
ingestLists = KeywordSearchIngestModule.getDefault().getKeywordLists();
ingestLists = KeywordListsManager.getInstance().getNamesOfKeywordListsForFileIngest();
}
boolean inIngest = !listSet ? false : ingestLists.contains(currentKeywordList.getName());
@ -575,7 +573,7 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec
KeywordSearchListsXML reader = KeywordSearchListsXML.getCurrent();
List<KeywordSearchListsAbstract.KeywordSearchList> toWrite = new ArrayList<KeywordSearchListsAbstract.KeywordSearchList>();
List<KeywordList> toWrite = new ArrayList<KeywordList>();
toWrite.add(reader.getList(currentKeywordList.getName()));
final KeywordSearchListsXML exporter = new KeywordSearchListsXML(fileAbs);
boolean written = exporter.saveLists(toWrite);
@ -659,11 +657,11 @@ private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt)
// Implemented by parent panel
}
KeywordSearchListsAbstract.KeywordSearchList getCurrentKeywordList() {
KeywordList getCurrentKeywordList() {
return currentKeywordList;
}
void setCurrentKeywordList(KeywordSearchListsAbstract.KeywordSearchList list) {
void setCurrentKeywordList(KeywordList list) {
currentKeywordList = list;
}

View File

@ -34,7 +34,6 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.SwingUtilities;
@ -50,13 +49,12 @@ import org.sleuthkit.autopsy.coreutils.EscapeUtil;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.StopWatch;
import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.PipelineContext;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.IngestModuleAdapter;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -76,10 +74,8 @@ import org.sleuthkit.datamodel.TskData.FileKnown;
* ingest update interval) Runs a periodic keyword / regular expression search
* on currently configured lists for ingest and writes results to blackboard
* Reports interesting events to Inbox and to viewers
*
* Registered as a module in layer.xml
*/
public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
public final class KeywordSearchIngestModule extends IngestModuleAdapter implements FileIngestModule {
enum UpdateFrequency {
@ -99,19 +95,10 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
}
};
private static final Logger logger = Logger.getLogger(KeywordSearchIngestModule.class.getName());
public static final String MODULE_NAME = NbBundle.getMessage(KeywordSearchIngestModule.class,
"KeywordSearchIngestModule.moduleName");
public static final String MODULE_DESCRIPTION = NbBundle.getMessage(KeywordSearchIngestModule.class,
"KeywordSearchIngestModule.moduleDescription");
final public static String MODULE_VERSION = Version.getVersion();
private static KeywordSearchIngestModule instance = null;
private IngestServices services;
private IngestServices services = IngestServices.getDefault();
private Ingester ingester = null;
private volatile boolean commitIndex = false; //whether to commit index next time
private volatile boolean runSearcher = false; //whether to run searcher next time
private List<Keyword> keywords; //keywords to search
private List<String> keywordLists; // lists currently being searched
private Map<String, KeywordSearchListsAbstract.KeywordSearchList> keywordToList; //keyword to list name mapping
private Timer commitTimer;
private Timer searchTimer;
private Indexer indexer;
@ -124,52 +111,126 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
private Set<Long> curDataSourceIds;
private static final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true); //use fairness policy
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 volatile boolean finalSearcherDone = true; //mark as done, until it's inited
private final String hashDBModuleName = NbBundle
.getMessage(this.getClass(), "KeywordSearchIngestModule.hashDbModuleName"); //NOTE this needs to match the HashDB module getName()
private SleuthkitCase caseHandle = null;
private static List<AbstractFileExtract> textExtractors;
private static AbstractFileStringExtract stringExtractor;
private boolean initialized = false;
private KeywordSearchIngestSimplePanel simpleConfigPanel;
private KeywordSearchConfigurationPanel advancedConfigPanel;
private Tika tikaFormatDetector;
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
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_TEXTEXTRACT, ///< File was skipped because of text extraction issues
SKIPPED_ERROR_IO ///< File was skipped because of IO issues reading it
};
private Map<Long, IngestStatus> ingestStatus;
//private constructor to ensure singleton instance
private KeywordSearchIngestModule() {
KeywordSearchIngestModule() {
}
/**
* Returns singleton instance of the module, creates one if needed
* Initializes the module for new ingest run Sets up threads, timers,
* retrieves settings, keyword lists to run on
*
* @return instance of the module
*/
public static synchronized KeywordSearchIngestModule getDefault() {
if (instance == null) {
instance = new KeywordSearchIngestModule();
@Override
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);
}
return instance;
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(PipelineContext<IngestModuleAbstractFile> pipelineContext, AbstractFile abstractFile) {
public ProcessResult process(AbstractFile abstractFile) {
if (initialized == false) //error initializing indexing/Solr
{
logger.log(Level.WARNING, "Skipping processing, module not initialized, file: " + abstractFile.getName());
logger.log(Level.WARNING, "Skipping processing, module not initialized, file: {0}", abstractFile.getName());
ingestStatus.put(abstractFile.getId(), IngestStatus.SKIPPED_ERROR_INDEXING);
return ProcessResult.OK;
}
@ -181,26 +242,19 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
} catch (TskCoreException 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)) {
//skip indexing of virtual dirs (no content, no real name) - will index children files
return ProcessResult.OK;
}
//check if we should index meta-data only when 1) it is known 2) HashDb module errored on it
if (services.getAbstractFileModuleResult(hashDBModuleName) == IngestModuleAbstractFile.ProcessResult.ERROR) {
indexer.indexFile(abstractFile, false);
//notify depending module that keyword search (would) encountered error for this file
ingestStatus.put(abstractFile.getId(), IngestStatus.SKIPPED_ERROR_IO);
return ProcessResult.ERROR;
}
else if (KeywordSearchSettings.getSkipKnown() && abstractFile.getKnown().equals(FileKnown.KNOWN)) {
if (KeywordSearchSettings.getSkipKnown() && abstractFile.getKnown().equals(FileKnown.KNOWN)) {
//index meta-data only
indexer.indexFile(abstractFile, false);
return ProcessResult.OK;
}
processedFiles = true;
processedFiles = true;
//check if it's time to commit after previous processing
checkRunCommitSearch();
@ -216,12 +270,16 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
* Cleanup resources, threads, timers
*/
@Override
public void complete() {
public void shutDown(boolean ingestJobCancelled) {
if (initialized == false) {
return;
}
//logger.log(Level.INFO, "complete()");
if (ingestJobCancelled) {
stop();
return;
}
commitTimer.stop();
//NOTE, we let the 1 before last searcher complete fully, and enqueue the last one
@ -240,7 +298,8 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
postIndexSummary();
//run one last search as there are probably some new files committed
if (keywordLists != null && !keywordLists.isEmpty() && processedFiles == true) {
List<String> keywordLists = KeywordListsManager.getInstance().getNamesOfKeywordListsForFileIngest();
if (!keywordLists.isEmpty() && processedFiles == true) {
finalSearcher = new Searcher(keywordLists, true); //final searcher run
finalSearcher.execute();
} else {
@ -252,24 +311,19 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
try {
final int numIndexedFiles = KeywordSearch.getServer().queryNumIndexedFiles();
final int numIndexedChunks = KeywordSearch.getServer().queryNumIndexedChunks();
logger.log(Level.INFO, "Indexed files count: " + numIndexedFiles);
logger.log(Level.INFO, "Indexed file chunks count: " + numIndexedChunks);
} catch (NoOpenCoreException ex) {
logger.log(Level.INFO, "Indexed files count: {0}", numIndexedFiles);
logger.log(Level.INFO, "Indexed file chunks count: {0}", numIndexedChunks);
} catch (NoOpenCoreException | KeywordSearchModuleException ex) {
logger.log(Level.WARNING, "Error executing Solr query to check number of indexed files/chunks: ", ex);
} catch (KeywordSearchModuleException se) {
logger.log(Level.WARNING, "Error executing Solr query to check number of indexed files/chunks: ", se);
}
//cleanup done in final searcher
//postSummary();
}
/**
* Handle stop event (ingest interrupted) Cleanup resources, threads, timers
*/
@Override
public void stop() {
private void stop() {
logger.log(Level.INFO, "stop()");
//stop timer
@ -286,12 +340,9 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
runSearcher = false;
finalSearcherDone = true;
//commit uncommited files, don't search again
commit();
//postSummary();
cleanup();
}
@ -314,197 +365,11 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
textExtractors = null;
stringExtractor = null;
keywords.clear();
keywordLists.clear();
keywordToList.clear();
tikaFormatDetector = null;
initialized = false;
}
@Override
public String getName() {
return MODULE_NAME;
}
@Override
public String getDescription() {
return MODULE_DESCRIPTION;
}
@Override
public String getVersion() {
return MODULE_VERSION;
}
/**
* Initializes the module for new ingest run Sets up threads, timers,
* retrieves settings, keyword lists to run on
*
*/
@Override
public void init(IngestModuleInit initContext) throws IngestModuleException {
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, instance, 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, instance, 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();
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: " + sbScripts.toString());
textExtractors = new ArrayList<AbstractFileExtract>();
//order matters, more specific extractors first
textExtractors.add(new AbstractFileHtmlExtract());
textExtractors.add(new AbstractFileTikaTextExtract());
ingestStatus = new HashMap<Long, IngestStatus>();
keywords = new ArrayList<Keyword>();
keywordLists = new ArrayList<String>();
keywordToList = new HashMap<String, KeywordSearchListsAbstract.KeywordSearchList>();
initKeywords();
if (keywords.isEmpty() || keywordLists.isEmpty()) {
services.postMessage(IngestMessage.createWarningMessage(++messageID, instance, 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<Keyword, List<Long>>();
curDataSourceIds = new HashSet<Long>();
indexer = new Indexer();
final int updateIntervalMs = KeywordSearchSettings.getUpdateFrequency().getTime() * 60 * 1000;
logger.log(Level.INFO, "Using commit interval (ms): " + updateIntervalMs);
logger.log(Level.INFO, "Using searcher interval (ms): " + updateIntervalMs);
commitTimer = new Timer(updateIntervalMs, new CommitTimerAction());
searchTimer = new Timer(updateIntervalMs, new SearchTimerAction());
initialized = true;
commitTimer.start();
searchTimer.start();
}
@Override
public boolean hasSimpleConfiguration() {
return true;
}
@Override
public boolean hasAdvancedConfiguration() {
return true;
}
@Override
public javax.swing.JPanel getSimpleConfiguration(String context) {
KeywordSearchListsXML.getCurrent().reload();
if (null == simpleConfigPanel) {
simpleConfigPanel = new KeywordSearchIngestSimplePanel();
}
else {
simpleConfigPanel.load();
}
return simpleConfigPanel;
}
@Override
public javax.swing.JPanel getAdvancedConfiguration(String context) {
if (advancedConfigPanel == null) {
advancedConfigPanel = new KeywordSearchConfigurationPanel();
}
advancedConfigPanel.load();
return advancedConfigPanel;
}
@Override
public void saveAdvancedConfiguration() {
if (advancedConfigPanel != null) {
advancedConfigPanel.store();
}
if (simpleConfigPanel != null) {
simpleConfigPanel.load();
}
}
@Override
public void saveSimpleConfiguration() {
KeywordSearchListsXML.getCurrent().save();
}
/**
* The modules maintains background threads, return true if background
* threads are running or there are pending tasks to be run in the future,
* such as the final search post-ingest completion
*
* @return
*/
@Override
public boolean hasBackgroundJobsRunning() {
if ((currentSearcher != null && searcherDone == false)
|| (finalSearcherDone == false)) {
return true;
} else {
return false;
}
}
/**
* Commits index and notifies listeners of index update
*/
@ -562,13 +427,12 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
msg.append("<tr><td>").append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.postIndexSummary.errIoLbl")).append("</td><td>").append(error_io).append("</td></tr>");
msg.append("</table>");
String indexStats = msg.toString();
logger.log(Level.INFO, "Keyword Indexing Completed: " + indexStats);
services.postMessage(IngestMessage.createMessage(++messageID, MessageType.INFO, this, NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.postIndexSummary.kwIdxResultsLbl"), indexStats));
logger.log(Level.INFO, "Keyword Indexing Completed: {0}", indexStats);
services.postMessage(IngestMessage.createMessage(++messageID, MessageType.INFO, KeywordSearchModuleFactory.getModuleName(), NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.postIndexSummary.kwIdxResultsLbl"), indexStats));
if (error_index > 0) {
MessageNotifyUtil.Notify.error(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.postIndexSummary.kwIdxErrsTitle"),
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"),
NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.postIndexSummary.idxErrReadFilesMsg"));
}
@ -582,64 +446,11 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
try {
final int numIndexedFiles = KeywordSearch.getServer().queryNumIndexedFiles();
KeywordSearch.fireNumIndexedFilesChange(null, new Integer(numIndexedFiles));
} catch (NoOpenCoreException ex) {
} catch (NoOpenCoreException | KeywordSearchModuleException ex) {
logger.log(Level.WARNING, "Error executing Solr query to check number of indexed files: ", ex);
} catch (KeywordSearchModuleException se) {
logger.log(Level.WARNING, "Error executing Solr query to check number of indexed files: ", se);
}
}
/**
* Initialize the keyword search lists and associated keywords from the XML
* loader Use the lists to ingest that are set in the permanent XML
* configuration
*/
private void initKeywords() {
addKeywordLists(null);
}
/**
* If ingest is ongoing, this will add additional keyword search lists to
* the ongoing ingest The lists to add may be temporary and not necessary
* set to be added to ingest permanently in the XML configuration. The lists
* will be reset back to original (permanent configuration state) on the
* next ingest.
*
* @param listsToAdd lists to add temporarily to the ongoing ingest
*/
void addKeywordLists(List<String> listsToAdd) {
KeywordSearchListsXML loader = KeywordSearchListsXML.getCurrent();
keywords.clear();
keywordLists.clear();
keywordToList.clear();
StringBuilder sb = new StringBuilder();
for (KeywordSearchListsAbstract.KeywordSearchList list : loader.getListsL()) {
final String listName = list.getName();
if (list.getUseForIngest() == true
|| (listsToAdd != null && listsToAdd.contains(listName))) {
keywordLists.add(listName);
sb.append(listName).append(" ");
}
for (Keyword keyword : list.getKeywords()) {
if (!keywords.contains(keyword)) {
keywords.add(keyword);
keywordToList.put(keyword.getQuery(), list);
}
}
}
logger.log(Level.INFO, "Set new effective keyword lists: " + sb.toString());
}
List<String> getKeywordLists() {
return keywordLists == null ? new ArrayList<String>() : keywordLists;
}
/**
* Check if time to commit, if so, run commit. Then run search if search
* timer is also set.
@ -655,7 +466,8 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
//in worst case, we will run search next time after commit timer goes off, or at the end of ingest
if (searcherDone && runSearcher) {
//start search if previous not running
if (keywordLists != null && !keywordLists.isEmpty()) {
List<String> keywordLists = KeywordListsManager.getInstance().getNamesOfKeywordListsForFileIngest();
if (!keywordLists.isEmpty()) {
currentSearcher = new Searcher(keywordLists);
currentSearcher.execute();//searcher will stop timer and restart timer when done
}
@ -724,8 +536,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
}
if (fileExtract == null) {
logger.log(Level.INFO, "No text extractor found for file id:"
+ aFile.getId() + ", name: " + aFile.getName() + ", detected format: " + detectedFormat);
logger.log(Level.INFO, "No text extractor found for file id:{0}, name: {1}, detected format: {2}", new Object[]{aFile.getId(), aFile.getName(), detectedFormat});
return false;
}
@ -748,7 +559,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
ingestStatus.put(aFile.getId(), IngestStatus.STRINGS_INGESTED);
return true;
} else {
logger.log(Level.WARNING, "Failed to extract strings and ingest, file '" + aFile.getName() + "' (id: " + aFile.getId() + ").");
logger.log(Level.WARNING, "Failed to extract strings and ingest, file ''{0}'' (id: {1}).", new Object[]{aFile.getName(), aFile.getId()});
ingestStatus.put(aFile.getId(), IngestStatus.SKIPPED_ERROR_TEXTEXTRACT);
return false;
}
@ -782,14 +593,14 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
* Adds the file to the index. Detects file type, calls extractors, etc.
*
* @param aFile File to analyze
* @param indexContent False if only metadata should be text_ingested. True if
* content and metadata should be index.
* @param indexContent False if only metadata should be text_ingested.
* True if content and metadata should be index.
*/
private void indexFile(AbstractFile aFile, boolean indexContent) {
//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.
if ((aType.equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) || aType.equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS))) {
extractStringsAndIndex(aFile);
@ -801,8 +612,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
try {
ingester.ingest(aFile, false); //meta-data only
ingestStatus.put(aFile.getId(), IngestStatus.METADATA_INGESTED);
}
catch (IngesterException ex) {
} catch (IngesterException ex) {
ingestStatus.put(aFile.getId(), IngestStatus.SKIPPED_ERROR_INDEXING);
logger.log(Level.WARNING, "Unable to index meta-data for file: " + aFile.getId(), ex);
}
@ -815,11 +625,9 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
try {
is = new ReadContentInputStream(aFile);
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);
}
finally {
} finally {
if (is != null) {
try {
is.close();
@ -829,9 +637,9 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
}
}
}
// @@@ Add file type signature to blackboard here
//logger.log(Level.INFO, "Detected format: " + aFile.getName() + " " + detectedFormat);
// we skip archive formats that are opened by the archive module.
@ -840,8 +648,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
try {
ingester.ingest(aFile, false); //meta-data only
ingestStatus.put(aFile.getId(), IngestStatus.METADATA_INGESTED);
}
catch (IngesterException ex) {
} catch (IngesterException ex) {
ingestStatus.put(aFile.getId(), IngestStatus.SKIPPED_ERROR_INDEXING);
logger.log(Level.WARNING, "Unable to index meta-data for file: " + aFile.getId(), ex);
}
@ -854,7 +661,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
try {
//logger.log(Level.INFO, "indexing: " + aFile.getName());
if (!extractTextAndIndex(aFile, detectedFormat)) {
logger.log(Level.WARNING, "Failed to extract text and ingest, file '" + aFile.getName() + "' (id: " + aFile.getId() + ").");
logger.log(Level.WARNING, "Failed to extract text and ingest, file ''{0}'' (id: {1}).", new Object[]{aFile.getName(), aFile.getId()});
ingestStatus.put(aFile.getId(), IngestStatus.SKIPPED_ERROR_TEXTEXTRACT);
} else {
ingestStatus.put(aFile.getId(), IngestStatus.TEXT_INGESTED);
@ -892,15 +699,15 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
*/
private List<Keyword> keywords; //keywords to search
private List<String> keywordLists; // lists currently being searched
private Map<String, KeywordSearchListsAbstract.KeywordSearchList> keywordToList; //keyword to list name mapping
private Map<String, KeywordList> keywordToList; //keyword to list name mapping
private AggregateProgressHandle progressGroup;
private final Logger logger = Logger.getLogger(Searcher.class.getName());
private boolean finalRun = false;
Searcher(List<String> keywordLists) {
this.keywordLists = new ArrayList<String>(keywordLists);
this.keywords = new ArrayList<Keyword>();
this.keywordToList = new HashMap<String, KeywordSearchListsAbstract.KeywordSearchList>();
this.keywordLists = new ArrayList<>(keywordLists);
this.keywords = new ArrayList<>();
this.keywordToList = new HashMap<>();
//keywords are populated as searcher runs
}
@ -917,15 +724,15 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
logger.log(Level.INFO, "Pending start of new searcher");
}
final String displayName = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.doInBackGround.displayName") +
(finalRun ? (" - "+ NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.doInBackGround.finalizeMsg")) : "");
progressGroup = AggregateProgressFactory.createSystemHandle(displayName + (" ("+
NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.doInBackGround.pendingMsg") +")"), null, new Cancellable() {
final String displayName = NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.doInBackGround.displayName")
+ (finalRun ? (" - " + NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.doInBackGround.finalizeMsg")) : "");
progressGroup = AggregateProgressFactory.createSystemHandle(displayName + (" ("
+ NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.doInBackGround.pendingMsg") + ")"), null, new Cancellable() {
@Override
public boolean cancel() {
logger.log(Level.INFO, "Cancelling the searcher by user.");
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);
}
@ -965,12 +772,12 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
for (Keyword keywordQuery : keywords) {
if (this.isCancelled()) {
logger.log(Level.INFO, "Cancel detected, bailing before new keyword processed: " + keywordQuery.getQuery());
logger.log(Level.INFO, "Cancel detected, bailing before new keyword processed: {0}", keywordQuery.getQuery());
return null;
}
final String queryStr = keywordQuery.getQuery();
final KeywordSearchListsAbstract.KeywordSearchList list = keywordToList.get(queryStr);
final KeywordList list = keywordToList.get(queryStr);
final String listName = list.getName();
//new subProgress will be active after the initial query
@ -985,10 +792,9 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
boolean isRegex = !keywordQuery.isLiteral();
if (isRegex) {
del = new TermComponentQuery(keywordQuery);
}
else {
} else {
del = new LuceneQuery(keywordQuery);
del.escape();
del.escape();
}
//limit search to currently ingested data sources
@ -996,7 +802,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
final KeywordQueryFilter dataSourceFilter = new KeywordQueryFilter(KeywordQueryFilter.FilterType.DATA_SOURCE, curDataSourceIds);
del.addFilter(dataSourceFilter);
Map<String, List<ContentHit>> queryResult = null;
Map<String, List<ContentHit>> queryResult;
try {
queryResult = del.performQuery();
@ -1007,7 +813,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
//likely case has closed and threads are being interrupted
return null;
} catch (CancellationException e) {
logger.log(Level.INFO, "Cancel detected, bailing during keyword query: " + keywordQuery.getQuery());
logger.log(Level.INFO, "Cancel detected, bailing during keyword query: {0}", keywordQuery.getQuery());
return null;
} catch (Exception e) {
logger.log(Level.WARNING, "Error performing query: " + keywordQuery.getQuery(), e);
@ -1023,7 +829,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
//write results to BB
//new artifacts created, to report to listeners
Collection<BlackboardArtifact> newArtifacts = new ArrayList<BlackboardArtifact>();
Collection<BlackboardArtifact> newArtifacts = new ArrayList<>();
//scale progress bar more more granular, per result sub-progress, within per keyword
int totalUnits = newResults.size();
@ -1040,10 +846,10 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
for (final Keyword hitTerm : newResults.keySet()) {
//checking for cancellation between results
if (this.isCancelled()) {
logger.log(Level.INFO, "Cancel detected, bailing before new hit processed for query: " + keywordQuery.getQuery());
logger.log(Level.INFO, "Cancel detected, bailing before new hit processed for query: {0}", keywordQuery.getQuery());
return null;
}
// update progress display
String hitDisplayStr = hitTerm.getQuery();
if (hitDisplayStr.length() > 50) {
@ -1055,9 +861,9 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
// 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));
for (final AbstractFile hitFile : contentHitsFlattened.keySet()) {
// get the snippet for the first hit in the file
String snippet = null;
String snippet;
final String snippetQuery = KeywordSearchUtil.escapeLuceneQuery(hitTerm.getQuery());
int chunkId = contentHitsFlattened.get(hitFile);
try {
@ -1074,7 +880,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
// write the blackboard artifact for this keyword in this file
KeywordWriteResult written = del.writeToBlackBoard(hitTerm.getQuery(), hitFile, snippet, listName);
if (written == null) {
logger.log(Level.WARNING, "BB artifact for keyword hit not written, file: " + hitFile + ", hit: " + hitTerm.toString());
logger.log(Level.WARNING, "BB artifact for keyword hit not written, file: {0}, hit: {1}", new Object[]{hitFile, hitTerm.toString()});
continue;
}
@ -1148,8 +954,8 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
}
}
detailsSb.append("</table>");
services.postMessage(IngestMessage.createDataMessage(++messageID, instance, 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
@ -1159,7 +965,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
//update artifact browser
if (!newArtifacts.isEmpty()) {
services.fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT, newArtifacts));
services.fireModuleDataEvent(new ModuleDataEvent(KeywordSearchModuleFactory.getModuleName(), ARTIFACT_TYPE.TSK_KEYWORD_HIT, newArtifacts));
}
} //if has results
@ -1177,7 +983,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
try {
finalizeSearcher();
stopWatch.stop();
logger.log(Level.INFO, "Searcher took to run: " + stopWatch.getElapsedTimeSecs() + " secs.");
logger.log(Level.INFO, "Searcher took to run: {0} secs.", stopWatch.getElapsedTimeSecs());
} finally {
searcherLock.unlock();
}
@ -1185,16 +991,15 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
return null;
}
@Override
protected void done() {
// call get to see if there were any errors
try {
get();
}
catch (InterruptedException | ExecutionException e) {
} catch (InterruptedException | ExecutionException e) {
logger.log(Level.SEVERE, "Error performing keyword search: " + e.getMessage());
services.postMessage(IngestMessage.createErrorMessage(++messageID, instance, "Error performing keyword search", e.getMessage()));
services.postMessage(IngestMessage.createErrorMessage(++messageID, KeywordSearchModuleFactory.getModuleName(), "Error performing keyword search", e.getMessage()));
}
// catch and ignore if we were cancelled
catch (java.util.concurrent.CancellationException ex ) { }
@ -1210,7 +1015,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
this.keywordToList.clear();
for (String name : this.keywordLists) {
KeywordSearchListsAbstract.KeywordSearchList list = loader.getList(name);
KeywordList list = loader.getList(name);
for (Keyword k : list.getKeywords()) {
this.keywords.add(k);
this.keywordToList.put(k.getQuery(), list);
@ -1261,13 +1066,13 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
//calculate new results but substracting results already obtained in this ingest
//update currentResults map with the new results
private Map<Keyword, List<ContentHit>> filterResults(Map<String, List<ContentHit>> queryResult, boolean isRegex) {
Map<Keyword, List<ContentHit>> newResults = new HashMap<Keyword, List<ContentHit>>();
Map<Keyword, List<ContentHit>> newResults = new HashMap<>();
for (String termResult : queryResult.keySet()) {
List<ContentHit> queryTermResults = queryResult.get(termResult);
//translate to list of IDs that we keep track of
List<Long> queryTermResultsIDs = new ArrayList<Long>();
List<Long> queryTermResultsIDs = new ArrayList<>();
for (ContentHit ch : queryTermResults) {
queryTermResultsIDs.add(ch.getId());
}
@ -1284,7 +1089,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
//add to new results
List<ContentHit> newResultsFs = newResults.get(termResultK);
if (newResultsFs == null) {
newResultsFs = new ArrayList<ContentHit>();
newResultsFs = new ArrayList<>();
newResults.put(termResultK, newResultsFs);
}
newResultsFs.add(res);

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 - 2013 Basis Technology Corp.
* Copyright 2011 - 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -17,7 +17,6 @@
* limitations under the License.
*/
package org.sleuthkit.autopsy.keywordsearch;
import java.util.ArrayList;
@ -28,21 +27,23 @@ import javax.swing.ListSelectionModel;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT;
import org.sleuthkit.autopsy.ingest.IngestModuleSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleSettingsPanel;
import org.sleuthkit.autopsy.ingest.NoIngestModuleSettings;
/**
* Simple ingest config panel
* Ingest job options panel for the keyword search file ingest module.
*/
public class KeywordSearchIngestSimplePanel extends javax.swing.JPanel {
public class KeywordSearchIngestSimplePanel extends IngestModuleSettingsPanel {
private final static Logger logger = Logger.getLogger(KeywordSearchIngestSimplePanel.class.getName());
public static final String PROP_OPTIONS = "Keyword Search_Options";
private KeywordTableModel tableModel;
private List<KeywordSearchListsAbstract.KeywordSearchList> lists;
private List<KeywordList> lists;
/** Creates new form KeywordSearchIngestSimplePanel */
public KeywordSearchIngestSimplePanel() {
KeywordSearchIngestSimplePanel() {
tableModel = new KeywordTableModel();
lists = new ArrayList<KeywordSearchListsAbstract.KeywordSearchList>();
lists = new ArrayList<>();
reloadLists();
initComponents();
customizeComponents();
@ -56,7 +57,7 @@ public class KeywordSearchIngestSimplePanel extends javax.swing.JPanel {
//customize column witdhs
final int width = listsScrollPane.getPreferredSize().width;
listsTable.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
TableColumn column = null;
TableColumn column;
for (int i = 0; i < listsTable.getColumnCount(); i++) {
column = listsTable.getColumnModel().getColumn(i);
if (i == 0) {
@ -70,6 +71,11 @@ public class KeywordSearchIngestSimplePanel extends javax.swing.JPanel {
reloadEncodings();
}
@Override
public IngestModuleSettings getSettings() {
return new NoIngestModuleSettings();
}
public void load() {
KeywordSearchListsXML.getCurrent().reload();
reloadLists();
@ -183,7 +189,6 @@ public class KeywordSearchIngestSimplePanel extends javax.swing.JPanel {
// End of variables declaration//GEN-END:variables
private void reloadLangs() {
//TODO multiple
List<SCRIPT> scripts = KeywordSearchSettings.getStringExtractScripts();
StringBuilder langs = new StringBuilder();
langs.append("<html>");
@ -202,7 +207,7 @@ public class KeywordSearchIngestSimplePanel extends javax.swing.JPanel {
private void reloadEncodings() {
String utf8 = KeywordSearchSettings.getStringExtractOption(AbstractFileExtract.ExtractOptions.EXTRACT_UTF8.toString());
String utf16 = KeywordSearchSettings.getStringExtractOption(AbstractFileExtract.ExtractOptions.EXTRACT_UTF16.toString());
ArrayList<String> encodingsList = new ArrayList<String>();
ArrayList<String> encodingsList = new ArrayList<>();
if(utf8==null || Boolean.parseBoolean(utf8)) {
encodingsList.add("UTF8");
}
@ -233,7 +238,7 @@ public class KeywordSearchIngestSimplePanel extends javax.swing.JPanel {
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
KeywordSearchListsAbstract.KeywordSearchList list = KeywordSearchIngestSimplePanel.this.lists.get(rowIndex);
KeywordList list = KeywordSearchIngestSimplePanel.this.lists.get(rowIndex);
if(columnIndex == 0) {
return list.getUseForIngest();
} else {
@ -249,7 +254,7 @@ public class KeywordSearchIngestSimplePanel extends javax.swing.JPanel {
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
KeywordSearchListsAbstract.KeywordSearchList list = KeywordSearchIngestSimplePanel.this.lists.get(rowIndex);
KeywordList list = KeywordSearchIngestSimplePanel.this.lists.get(rowIndex);
if(columnIndex == 0){
KeywordSearchListsXML loader = KeywordSearchListsXML.getCurrent();
loader.addList(list.getName(), list.getKeywords(), (Boolean) aValue, false);
@ -260,7 +265,6 @@ public class KeywordSearchIngestSimplePanel extends javax.swing.JPanel {
@Override
public Class<?> getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -35,38 +35,41 @@ import java.util.logging.Level;
/**
* Keyword list saving, loading, and editing abstract class.
*/
public abstract class KeywordSearchListsAbstract {
abstract class KeywordSearchListsAbstract {
protected String filePath;
Map<String, KeywordSearchList> theLists; //the keyword data
static KeywordSearchListsXML currentInstance = null;
private static final String CUR_LISTS_FILE_NAME = "keywords.xml";
private static String CUR_LISTS_FILE = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_LISTS_FILE_NAME;
Map<String, KeywordList> theLists; //the keyword data
static KeywordSearchListsXML currentInstance = null;
private static final String CUR_LISTS_FILE_NAME = "keywords.xml"; // RJCTODO: This will go to the manager
private static String CUR_LISTS_FILE = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_LISTS_FILE_NAME; // RJCTODO: This will go to the manager
protected static final Logger logger = Logger.getLogger(KeywordSearchListsAbstract.class.getName());
PropertyChangeSupport changeSupport;
protected List<String> lockedLists;
PropertyChangeSupport changeSupport; // RJCTODO: This will go to the manager, if needed, no listeners right now
protected List<String> lockedLists; // RJCTODO: This will go to the manager, if needed
public KeywordSearchListsAbstract(String filePath) {
KeywordSearchListsAbstract(String filePath) {
this.filePath = filePath;
theLists = new LinkedHashMap<String, KeywordSearchList>();
lockedLists = new ArrayList<String>();
theLists = new LinkedHashMap<>();
lockedLists = new ArrayList<>();
changeSupport = new PropertyChangeSupport(this);
}
// RJCTODO: There are no listeners
// RJCTODO: For manager
/**
* Property change event support
* In events: For all of these enums, the old value should be null, and
* the new value should be the keyword list name string.
* Property change event support In events: For all of these enums, the old
* value should be null, and the new value should be the keyword list name
* string.
*/
public enum ListsEvt {
enum ListsEvt {
LIST_ADDED, LIST_DELETED, LIST_UPDATED
};
// RJCTODO: For manager
/**
* get instance for managing the current keyword list of the application
*/
public static KeywordSearchListsXML getCurrent() {
static KeywordSearchListsXML getCurrent() {
if (currentInstance == null) {
currentInstance = new KeywordSearchListsXML(CUR_LISTS_FILE);
currentInstance.reload();
@ -74,29 +77,30 @@ public abstract class KeywordSearchListsAbstract {
return currentInstance;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
changeSupport.addPropertyChangeListener(listener);
}
// RJCTODO: For manager
// RJCTODO: There are no listeners
// public void addPropertyChangeListener(PropertyChangeListener listener) {
// changeSupport.addPropertyChangeListener(listener);
// }
private void prepopulateLists() {
if (! theLists.isEmpty()) {
if (!theLists.isEmpty()) {
return;
}
//phone number
List<Keyword> phones = new ArrayList<Keyword>();
List<Keyword> phones = new ArrayList<>();
phones.add(new Keyword("[(]{0,1}\\d\\d\\d[)]{0,1}[\\.-]\\d\\d\\d[\\.-]\\d\\d\\d\\d", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER));
//phones.add(new Keyword("\\d{8,10}", false));
//IP address
List<Keyword> ips = new ArrayList<Keyword>();
List<Keyword> ips = new ArrayList<>();
ips.add(new Keyword("(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IP_ADDRESS));
//email
List<Keyword> emails = new ArrayList<Keyword>();
emails.add(new Keyword("(?=.{8})[a-z0-9%+_-]+(?:\\.[a-z0-9%+_-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z]{2,4}(?<!\\.txt|\\.exe|\\.dll|\\.jpg|\\.xml)",
false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL));
List<Keyword> emails = new ArrayList<>();
emails.add(new Keyword("(?=.{8})[a-z0-9%+_-]+(?:\\.[a-z0-9%+_-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z]{2,4}(?<!\\.txt|\\.exe|\\.dll|\\.jpg|\\.xml)",
false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL));
//emails.add(new Keyword("[A-Z0-9._%-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}",
// false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL));
//URL
List<Keyword> urls = new ArrayList<Keyword>();
List<Keyword> urls = new ArrayList<>();
//urls.add(new Keyword("http://|https://|^www\\.", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL));
urls.add(new Keyword("((((ht|f)tp(s?))\\://)|www\\.)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,5})(\\:[0-9]+)*(/($|[a-zA-Z0-9\\.\\,\\;\\?\\'\\\\+&amp;%\\$#\\=~_\\-]+))*", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL));
@ -104,24 +108,26 @@ public abstract class KeywordSearchListsAbstract {
//disable messages for harcoded/locked lists
String name;
name = "Phone Numbers";
lockedLists.add(name);
addList(name, phones, false, false, true);
name = "IP Addresses";
lockedLists.add(name);
addList(name, ips, false, false, true);
name = "Email Addresses";
lockedLists.add(name);
addList(name, emails, true, false, true);
name = "URLs";
lockedLists.add(name);
addList(name, urls, false, false, true);
}
// RJCTODO: Manager, reader mixed
// RJCTODO: This is only called by config type stuff to affect the global list
/**
* load the file or create new
*/
@ -131,10 +137,10 @@ public abstract class KeywordSearchListsAbstract {
//theLists.clear();
//populate only the first time
prepopulateLists();
//reset all the lists other than locked lists (we don't save them to XML)
//we want to preserve state of locked lists
List<String> toClear = new ArrayList<String>();
List<String> toClear = new ArrayList<>();
for (String list : theLists.keySet()) {
if (theLists.get(list).isLocked() == false) {
toClear.add(list);
@ -142,34 +148,35 @@ public abstract class KeywordSearchListsAbstract {
}
for (String clearList : toClear) {
theLists.remove(clearList);
}
if (!this.listFileExists()) {
}
if (!listFileExists()) {
//create new if it doesn't exist
save();
created = true;
}
//load, if fails to laod create new
//load, if fails to load create new
if (!load() && !created) {
//create new if failed to load
save();
}
}
public List<KeywordSearchList> getListsL() {
List<KeywordSearchList> ret = new ArrayList<KeywordSearchList>();
for (KeywordSearchList list : theLists.values()) {
// RJCTODO: Need a manager and reader version of getting lists
public List<KeywordList> getListsL() {
List<KeywordList> ret = new ArrayList<>();
for (KeywordList list : theLists.values()) {
ret.add(list);
}
return ret;
}
public List<KeywordSearchList> getListsL(boolean locked) {
List<KeywordSearchList> ret = new ArrayList<KeywordSearchList>();
for (KeywordSearchList list : theLists.values()) {
// RJCTODO: Need a manager of getting lists
// RJCTODO: There is one client, KeywordSearchEditListPanel, fetching unlocked lists
public List<KeywordList> getListsL(boolean locked) {
List<KeywordList> ret = new ArrayList<>();
for (KeywordList list : theLists.values()) {
if (list.isLocked().equals(locked)) {
ret.add(list);
}
@ -177,15 +184,17 @@ public abstract class KeywordSearchListsAbstract {
return ret;
}
// RJCTODO: Used by KeywordSearchListsManagementPanel; for manager, since global list affected
/**
* Get list names of all loaded keyword list names
*
* @return List of keyword list names
*/
public List<String> getListNames() {
return new ArrayList<String>(theLists.keySet());
return new ArrayList<>(theLists.keySet());
}
// RJCTODO: Used by KeywordSearchListsManagementPanel; for manager, since global list affected
/**
* Get list names of all locked or unlocked loaded keyword list names
*
@ -193,9 +202,9 @@ public abstract class KeywordSearchListsAbstract {
* @return List of keyword list names
*/
public List<String> getListNames(boolean locked) {
ArrayList<String> lists = new ArrayList<String>();
ArrayList<String> lists = new ArrayList<>();
for (String listName : theLists.keySet()) {
KeywordSearchList list = theLists.get(listName);
KeywordList list = theLists.get(listName);
if (locked == list.isLocked()) {
lists.add(listName);
}
@ -210,26 +219,9 @@ public abstract class KeywordSearchListsAbstract {
* @param keyword
* @return found list or null
*/
public KeywordSearchList getListWithKeyword(Keyword keyword) {
KeywordSearchList found = null;
for (KeywordSearchList list : theLists.values()) {
if (list.hasKeyword(keyword)) {
found = list;
break;
}
}
return found;
}
/**
* return first list that contains the keyword
*
* @param keyword
* @return found list or null
*/
public KeywordSearchList getListWithKeyword(String keyword) {
KeywordSearchList found = null;
for (KeywordSearchList list : theLists.values()) {
public KeywordList getListWithKeyword(String keyword) {
KeywordList found = null;
for (KeywordList list : theLists.values()) {
if (list.hasKeyword(keyword)) {
found = list;
break;
@ -256,7 +248,7 @@ public abstract class KeywordSearchListsAbstract {
public int getNumberLists(boolean locked) {
int numLists = 0;
for (String listName : theLists.keySet()) {
KeywordSearchList list = theLists.get(listName);
KeywordList list = theLists.get(listName);
if (locked == list.isLocked()) {
++numLists;
}
@ -270,7 +262,7 @@ public abstract class KeywordSearchListsAbstract {
* @param name id of the list
* @return keyword list representation
*/
public KeywordSearchList getList(String name) {
public KeywordList getList(String name) {
return theLists.get(name);
}
@ -295,38 +287,36 @@ public abstract class KeywordSearchListsAbstract {
*/
boolean addList(String name, List<Keyword> newList, boolean useForIngest, boolean ingestMessages, boolean locked) {
boolean replaced = false;
KeywordSearchList curList = getList(name);
KeywordList curList = getList(name);
final Date now = new Date();
if (curList == null) {
theLists.put(name, new KeywordSearchList(name, now, now, useForIngest, ingestMessages, newList, locked));
theLists.put(name, new KeywordList(name, now, now, useForIngest, ingestMessages, newList, locked));
// if (!locked) {
// save();
// }
try {
changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, name);
}
catch (Exception e) {
changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, name);
} catch (Exception e) {
logger.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e);
MessageNotifyUtil.Notify.show("Module Error", "A module caused an error listening to KeywordSearchListsAbstract updates. See log to determine which module. Some data could be incomplete.", MessageNotifyUtil.MessageType.ERROR);
}
} else {
theLists.put(name, new KeywordSearchList(name, curList.getDateCreated(), now, useForIngest, ingestMessages, newList, locked));
theLists.put(name, new KeywordList(name, curList.getDateCreated(), now, useForIngest, ingestMessages, newList, locked));
// if (!locked) {
// save();
// }
replaced = true;
try {
changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, name);
}
catch (Exception e) {
} catch (Exception e) {
logger.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e);
MessageNotifyUtil.Notify.show("Module Error", "A module caused an error listening to KeywordSearchListsAbstract updates. See log to determine which module. Some data could be incomplete.", MessageNotifyUtil.MessageType.ERROR);
}
}
return replaced;
}
@ -341,7 +331,7 @@ public abstract class KeywordSearchListsAbstract {
return addList(name, newList, true, isLocked);
}
boolean addList(KeywordSearchList list) {
boolean addList(KeywordList list) {
return addList(list.getName(), list.getKeywords(), list.getUseForIngest(), list.getIngestMessages(), list.isLocked());
}
@ -351,12 +341,12 @@ public abstract class KeywordSearchListsAbstract {
* @param lists
* @return
*/
boolean saveLists(List<KeywordSearchList> lists) {
boolean saveLists(List<KeywordList> lists) {
int oldSize = this.getNumberLists();
List<KeywordSearchList> overwritten = new ArrayList<KeywordSearchList>();
List<KeywordSearchList> newLists = new ArrayList<KeywordSearchList>();
for (KeywordSearchList list : lists) {
List<KeywordList> overwritten = new ArrayList<KeywordList>();
List<KeywordList> newLists = new ArrayList<KeywordList>();
for (KeywordList list : lists) {
if (this.listExists(list.getName())) {
overwritten.add(list);
} else {
@ -366,20 +356,18 @@ public abstract class KeywordSearchListsAbstract {
}
boolean saved = save(true);
if (saved) {
for (KeywordSearchList list : newLists) {
for (KeywordList list : newLists) {
try {
changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, list.getName());
}
catch (Exception e) {
} catch (Exception e) {
logger.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e);
MessageNotifyUtil.Notify.show("Module Error", "A module caused an error listening to KeywordSearchListsAbstract updates. See log to determine which module. Some data could be incomplete.", MessageNotifyUtil.MessageType.ERROR);
}
}
for (KeywordSearchList over : overwritten) {
for (KeywordList over : overwritten) {
try {
changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, over.getName());
}
catch (Exception e) {
} catch (Exception e) {
logger.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e);
MessageNotifyUtil.Notify.show("Module Error", "A module caused an error listening to KeywordSearchListsAbstract updates. See log to determine which module. Some data could be incomplete.", MessageNotifyUtil.MessageType.ERROR);
}
@ -395,12 +383,10 @@ public abstract class KeywordSearchListsAbstract {
* @param lists
* @return
*/
boolean writeLists(List<KeywordSearchList> lists) {
int oldSize = this.getNumberLists();
List<KeywordSearchList> overwritten = new ArrayList<KeywordSearchList>();
List<KeywordSearchList> newLists = new ArrayList<KeywordSearchList>();
for (KeywordSearchList list : lists) {
boolean writeLists(List<KeywordList> lists) {
List<KeywordList> overwritten = new ArrayList<>();
List<KeywordList> newLists = new ArrayList<>();
for (KeywordList list : lists) {
if (this.listExists(list.getName())) {
overwritten.add(list);
} else {
@ -408,24 +394,22 @@ public abstract class KeywordSearchListsAbstract {
}
theLists.put(list.getName(), list);
}
//boolean saved = save();
for (KeywordSearchList list : newLists) {
for (KeywordList list : newLists) {
try {
changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, list.getName());
}
catch (Exception e) {
changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, list.getName());
} catch (Exception e) {
logger.log(Level.SEVERE, "KeywordSearchListsAbstractr listener threw exception", e);
MessageNotifyUtil.Notify.show("Module Error", "A module caused an error listening to KeywordSearchListsAbstract updates. See log to determine which module. Some data could be incomplete.", MessageNotifyUtil.MessageType.ERROR);
}
}
for (KeywordSearchList over : overwritten) {
for (KeywordList over : overwritten) {
try {
changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, over.getName());
}
catch (Exception e) {
} catch (Exception e) {
logger.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e);
MessageNotifyUtil.Notify.show("Module Error", "A module caused an error listening to KeywordSearchListsAbstract updates. See log to determine which module. Some data could be incomplete.", MessageNotifyUtil.MessageType.ERROR);
}
@ -434,38 +418,37 @@ public abstract class KeywordSearchListsAbstract {
return true;
}
// RJCTODO: For manager
/**
* delete list if exists and save new list
* delete list if exists and save new list // RJCTODO: What new list? Nothing is saved (liar!)
*
* @param name of list to delete
* @return true if deleted
*/
boolean deleteList(String name) {
boolean deleted = false;
KeywordSearchList delList = getList(name);
KeywordList delList = getList(name);
if (delList != null && !delList.isLocked()) {
theLists.remove(name);
//deleted = save();
}
try {
changeSupport.firePropertyChange(ListsEvt.LIST_DELETED.toString(), null, name); // RJCTODO: Always fired (liar!)
} catch (Exception e) {
logger.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e);
MessageNotifyUtil.Notify.show("Module Error", "A module caused an error listening to KeywordSearchListsAbstract updates. See log to determine which module. Some data could be incomplete.", MessageNotifyUtil.MessageType.ERROR);
}
try {
changeSupport.firePropertyChange(ListsEvt.LIST_DELETED.toString(), null, name);
}
catch (Exception e) {
logger.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e);
MessageNotifyUtil.Notify.show("Module Error", "A module caused an error listening to KeywordSearchListsAbstract updates. See log to determine which module. Some data could be incomplete.", MessageNotifyUtil.MessageType.ERROR);
}
return true;
return true; // RJCTODO: LOL, reports that it always succeeds (liar!)
}
/**
* writes out current list replacing the last lists file
*/
public abstract boolean save();
/**
* writes out current list replacing the last lists file
*
* @param isExport true is this save operation is an export and not a 'Save
* As'
*/
@ -480,107 +463,8 @@ public abstract class KeywordSearchListsAbstract {
File f = new File(filePath);
return f.exists() && f.canRead() && f.canWrite();
}
public void setUseForIngest(String key, boolean flag)
{
public void setUseForIngest(String key, boolean flag) {
theLists.get(key).setUseForIngest(flag);
}
/**
* a representation of a single keyword list created or loaded
*/
public class KeywordSearchList {
private String name;
private Date created;
private Date modified;
private Boolean useForIngest;
private Boolean ingestMessages;
private List<Keyword> keywords;
private Boolean locked;
KeywordSearchList(String name, Date created, Date modified, Boolean useForIngest, Boolean ingestMessages, List<Keyword> keywords, boolean locked) {
this.name = name;
this.created = created;
this.modified = modified;
this.useForIngest = useForIngest;
this.ingestMessages = ingestMessages;
this.keywords = keywords;
this.locked = locked;
}
KeywordSearchList(String name, Date created, Date modified, Boolean useForIngest, Boolean ingestMessages, List<Keyword> keywords) {
this(name, created, modified, useForIngest, ingestMessages, keywords, false);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final KeywordSearchList other = (KeywordSearchList) obj;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 5;
return hash;
}
public String getName() {
return name;
}
public Date getDateCreated() {
return created;
}
public Date getDateModified() {
return modified;
}
public Boolean getUseForIngest() {
return useForIngest;
}
void setUseForIngest(boolean use) {
this.useForIngest = use;
}
public Boolean getIngestMessages() {
return ingestMessages;
}
void setIngestMessages(boolean ingestMessages) {
this.ingestMessages = ingestMessages;
}
public List<Keyword> getKeywords() {
return keywords;
}
boolean hasKeyword(Keyword keyword) {
return keywords.contains(keyword);
}
public boolean hasKeyword(String keyword) {
//note, this ignores isLiteral
for (Keyword k : keywords) {
if (k.getQuery().equals(keyword)) {
return true;
}
}
return false;
}
public Boolean isLocked() {
return locked;
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -64,7 +64,7 @@ class KeywordSearchListsEncase extends KeywordSearchListsAbstract{
name = parentPath + "/" + entry.name;
}
List<Keyword> children = new ArrayList<Keyword>();
List<Keyword> children = new ArrayList<>();
for(EncaseFileEntry child : entry.children) {
switch(child.type) {
case Folder:
@ -88,7 +88,7 @@ class KeywordSearchListsEncase extends KeywordSearchListsAbstract{
}
// Don't create lists if there are no keywords
if (!children.isEmpty()) {
KeywordSearchList newList = new KeywordSearchList(name, new Date(), new Date(),
KeywordList newList = new KeywordList(name, new Date(), new Date(),
true, true, children);
theLists.put(name, newList);
}
@ -133,7 +133,7 @@ class KeywordSearchListsEncase extends KeywordSearchListsAbstract{
BufferedReader readBuffer = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "utf-16"));
String structLine;
String metaLine;
entriesUnsorted = new ArrayList<EncaseFileEntry>();
entriesUnsorted = new ArrayList<>();
for(int line = 1; line < 6; line++) {
readBuffer.readLine();
}
@ -144,7 +144,7 @@ class KeywordSearchListsEncase extends KeywordSearchListsAbstract{
String childCount = structArr[1];
String name = metaArr[1];
String value = metaArr[2];
ArrayList<EncaseFlag> flags = new ArrayList<EncaseFlag>();
ArrayList<EncaseFlag> flags = new ArrayList<>();
for(int i = 0; i < 17; i++) {
if(metaArr.length < i+4) {
continue;
@ -215,7 +215,7 @@ class KeywordSearchListsEncase extends KeywordSearchListsAbstract{
this.name = name;
this.value = value;
this.childCount = childCount;
this.children = new ArrayList<EncaseFileEntry>();
this.children = new ArrayList<>();
this.hasParent = hasParent;
this.parent = parent;
this.type = type;

Some files were not shown because too many files have changed in this diff Show More