diff --git a/HashDatabase/nbproject/project.xml b/HashDatabase/nbproject/project.xml
index 9cfb151e4c..40499aa189 100644
--- a/HashDatabase/nbproject/project.xml
+++ b/HashDatabase/nbproject/project.xml
@@ -95,5 +95,9 @@
org.sleuthkit.autopsy.hashdatabase
+
+ openide
+ org
+
-
\ No newline at end of file
+
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java
index bef2c3e889..9326fd61cd 100755
--- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java
+++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java
@@ -24,7 +24,6 @@ import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import javax.swing.AbstractAction;
-import javax.swing.Action;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
@@ -35,124 +34,128 @@ import org.sleuthkit.autopsy.ingest.IngestConfigurator;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException;
+import static org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
/**
- * Instances of this Action allow users to content to a hash database.
+ * Instances of this Action allow users to content to a hash database.
*/
-public class AddContentToHashDbAction extends AbstractAction implements Presenter.Popup {
- // This class is a singleton to support multi-selection of nodes, since
- // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
- // node in the array returns a reference to the same action object from Node.getActions(boolean).
+final class AddContentToHashDbAction extends AbstractAction implements Presenter.Popup {
private static AddContentToHashDbAction instance;
- private static String SINGLE_SELECTION_NAME = "Add file to hash database";
- private static String MULTIPLE_SELECTION_NAME = "Add files to hash database";
- private String menuText;
-
+
+ /**
+ * AddContentToHashDbAction is a singleton to support multi-selection of nodes, since
+ * org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action from a node
+ * if every node in the nodes array returns a reference to the same action object from
+ * Node.getActions(boolean).
+ */
public static synchronized AddContentToHashDbAction getInstance() {
if (null == instance) {
instance = new AddContentToHashDbAction();
- }
-
- instance.setEnabled(true);
- instance.putValue(Action.NAME, SINGLE_SELECTION_NAME);
- instance.menuText = SINGLE_SELECTION_NAME;
-
- // Disable the action if file ingest is in progress.
- IngestConfigurator ingestConfigurator = Lookup.getDefault().lookup(IngestConfigurator.class);
- if (null != ingestConfigurator && ingestConfigurator.isIngestRunning()) {
- instance.setEnabled(false);
- }
-
- // Set the name of the action based on the selected content and disable the action if there is
- // selected content without an MD5 hash.
- Collection extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
- if (selectedFiles.size() > 1) {
- instance.putValue(Action.NAME, MULTIPLE_SELECTION_NAME);
- instance.menuText = MULTIPLE_SELECTION_NAME;
- }
- if (selectedFiles.isEmpty()) {
- instance.setEnabled(false);
- }
- else {
- for (AbstractFile file : selectedFiles) {
- if (null == file.getMd5Hash()) {
- instance.setEnabled(false);
- break;
- }
- }
- }
-
+ }
return instance;
}
private AddContentToHashDbAction() {
- super(SINGLE_SELECTION_NAME);
}
@Override
public JMenuItem getPopupPresenter() {
- return new AddContentToHashDbMenu(menuText);
+ return new AddContentToHashDbMenu();
}
@Override
public void actionPerformed(ActionEvent event) {
}
- private class AddContentToHashDbMenu extends JMenu {
- AddContentToHashDbMenu(String menuText) {
- super(menuText);
+ // Instances of this class are used to implement the a pop up menu for this
+ // action.
+ private final class AddContentToHashDbMenu extends JMenu {
+ private final static String SINGLE_SELECTION_NAME = "Add file to hash database";
+ private final static String MULTIPLE_SELECTION_NAME = "Add files to hash database";
+
+ AddContentToHashDbMenu() {
+ 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()) {
+ setEnabled(false);
+ return;
+ }
+ // Get any AbstractFile objects from the lookup of the currently focused top component.
+ final Collection extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
+ if (selectedFiles.isEmpty()) {
+ setEnabled(false);
+ return;
+ }
+ else if (selectedFiles.size() > 1) {
+ setText(MULTIPLE_SELECTION_NAME);
+ }
+
+ // Disable the menu if hashes have not been calculated.
+ for (AbstractFile file : selectedFiles) {
+ if (null == file.getMd5Hash()) {
+ setEnabled(false);
+ return;
+ }
+ }
+
// Get the current set of updateable hash databases and add each
- // one as a menu item.
- List hashDatabases = HashDbManager.getInstance().getUpdateableHashSets();
+ // one to the menu as a separate menu item. Selecting a hash database
+ // adds the selected files to the selected database.
+ final List hashDatabases = HashDbManager.getInstance().getUpdateableHashSets();
if (!hashDatabases.isEmpty()) {
for (final HashDb database : hashDatabases) {
JMenuItem databaseItem = add(database.getHashSetName());
databaseItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- addContentToHashSet(database);
+ addFilesToHashSet(selectedFiles, database);
}
});
}
}
else {
- JMenuItem empty = new JMenuItem("No hash databases");
+ JMenuItem empty = new JMenuItem("No hash databases configured");
empty.setEnabled(false);
add(empty);
}
- // Add a "New Hash Set..." menu item.
+ // Add a "New Hash Set..." menu item. Selecting this item invokes a
+ // a hash database creation dialog and adds the selected files to the
+ // the new database.
addSeparator();
- JMenuItem newHashSetItem = new JMenuItem("New Hash Set...");
+ JMenuItem newHashSetItem = new JMenuItem("Create database...");
newHashSetItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- HashDb hashDb = new HashDbCreateDatabaseDialog().doDialog();
+ HashDb hashDb = new HashDbCreateDatabaseDialog().getHashDatabase();
if (null != hashDb) {
- HashDbManager hashSetManager = HashDbManager.getInstance();
- hashSetManager.addHashSet(hashDb);
- hashSetManager.save();
- addContentToHashSet(hashDb);
+ HashDbManager.getInstance().save();
+ addFilesToHashSet(selectedFiles, hashDb);
}
}
});
add(newHashSetItem);
}
- private void addContentToHashSet(HashDb hashSet) {
- Collection extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
- for (AbstractFile file : selectedFiles) {
+ private void addFilesToHashSet(final Collection extends AbstractFile> files, HashDb hashSet) {
+ for (AbstractFile file : files) {
String md5Hash = file.getMd5Hash();
if (null != md5Hash) {
try {
- hashSet.add(file);
+ hashSet.addHashes(file);
}
catch (TskCoreException ex) {
Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error adding to hash database", ex);
- JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + " to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE);
+ JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + " to the hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE);
}
- }
+ }
+ else {
+ JOptionPane.showMessageDialog(null, "Unable to add the " + (files.size() > 1 ? "files" : "file") + " to the hash database. Hashes have not been calculated. Please configure and run an appropriate ingest module.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE);
+ break;
+ }
}
}
}
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties
index 891a9e4358..7e2fa92971 100644
--- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties
+++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties
@@ -22,26 +22,15 @@ HashDbSearchPanel.errorField.text=Error: Not all files have been hashed.
HashDbSearchPanel.saveBox.text=Remember Hashes
HashDbSearchPanel.cancelButton.text=Cancel
OpenIDE-Module-Short-Description=Hash Database Ingest Module and hash db tools
-HashDbImportDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest
-HashDbImportDatabaseDialog.useForIngestCheckbox.text=Enable for ingest
HashDbImportDatabaseDialog.jLabel1.text=Hash Set Name:
-HashDbImportDatabaseDialog.databaseNameTextField.text=
HashDbImportDatabaseDialog.databasePathTextField.text=
-HashDbImportDatabaseDialog.browseButton.text=Browse
HashDbImportDatabaseDialog.knownBadRadioButton.text=Known Bad
HashDbImportDatabaseDialog.jLabel2.text=Type of database:
HashDbImportDatabaseDialog.okButton.text=OK
HashDbImportDatabaseDialog.cancelButton.text=Cancel
-HashDbCreateDatabaseDialog.jLabel2.text=Type of database:
+HashDbCreateDatabaseDialog.jLabel2.text=Type:
HashDbCreateDatabaseDialog.knownBadRadioButton.text=Known Bad
-HashDbCreateDatabaseDialog.browseButton.text=Browse
-HashDbCreateDatabaseDialog.databasePathTextField.text=
HashDbCreateDatabaseDialog.cancelButton.text=Cancel
-HashDbCreateDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest
-HashDbCreateDatabaseDialog.okButton.text=OK
-HashDbCreateDatabaseDialog.useForIngestCheckbox.text=Enable for ingest
-HashDbCreateDatabaseDialog.jLabel1.text=Hash Set Name:
-HashDbCreateDatabaseDialog.databaseNameTextField.text=
HashDbConfigPanel.nameLabel.text=Hash Set Name:
HashDbConfigPanel.hashDbNameLabel.text=No database selected
HashDbConfigPanel.hashDatabasesLabel.text=Hash Databases:
@@ -58,11 +47,7 @@ HashDbConfigPanel.hashDbIndexStatusLabel.text=No database selected
HashDbConfigPanel.hashDbTypeLabel.text=No database selected
HashDbConfigPanel.indexButton.text=Index
HashDbConfigPanel.indexLabel.text=Index Status:
-HashDbConfigPanel.showInboxMessagesCheckBox.text=Enable sending messages to inbox during ingest
-HashDbConfigPanel.useForIngestCheckbox.text=Enable for ingest
HashDbConfigPanel.informationLabel.text=Information
-HashDbSimpleConfigPanel.calcHashesButton.text=Calculate hashes even if no hash database is selected
-HashDbConfigPanel.newDatabaseButton.text=New Database
HashDbConfigPanel.importDatabaseButton.text=Import Database
HashDbConfigPanel.deleteDatabaseButton.text=Delete Database
HashDbConfigPanel.indexPathLabelLabel.text=Index Path:
@@ -75,4 +60,22 @@ ModalNoButtons.CANCEL_BUTTON.text=Cancel
HashDbSimpleConfigPanel.knownBadHashDbsLabel.text=Enable known bad databases for ingest:
HashDbSimpleConfigPanel.knownHashDbsLabel.text=Enable known hash databases for ingest:
HashDbImportDatabaseDialog.knownRadioButton.text=Known (NSRL or other)
-HashDbCreateDatabaseDialog.knownRadioButton.text=Known (NSRL or other)
+HashDbCreateDatabaseDialog.knownRadioButton.text=Known
+HashDbCreateDatabaseDialog.jLabel1.text=Database Path:
+HashDbCreateDatabaseDialog.saveAsButton.text=Save As...
+HashDbCreateDatabaseDialog.hashSetNameTextField.text=
+HashDbImportDatabaseDialog.jLabel3.text=Database Path:
+HashDbCreateDatabaseDialog.searchDuringIngestCheckbox.text=Search during ingest
+HashDbCreateDatabaseDialog.searchDuringIngestCheckbox.toolTipText=
+HashDbCreateDatabaseDialog.sendIngestMessagesCheckbox.text=Send ingest messages
+HashDbImportDatabaseDialog.searchDuringIngestCheckbox.text=Search during ingest
+HashDbImportDatabaseDialog.sendIngestMessagesCheckbox.text=Send ingest messages
+HashDbImportDatabaseDialog.hashSetNameTextField.text=
+HashDbConfigPanel.createDatabaseButton.text=Create Database
+HashDbImportDatabaseDialog.openButton.text=Open...
+HashDbSimpleConfigPanel.alwaysCalcHashesCheckbox.text=Calculate hashes even if no hash database is selected
+HashDbCreateDatabaseDialog.jLabel3.text=Hash Set Name:
+HashDbCreateDatabaseDialog.okButton.text=OK
+HashDbCreateDatabaseDialog.databasePathTextField.text=
+HashDbConfigPanel.searchDuringIngestCheckbox.text=Search during ingest
+HashDbConfigPanel.sendIngestMessagesCheckBox.text=Send ingest messages
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java
deleted file mode 100644
index ec6e84435f..0000000000
--- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Autopsy Forensic Browser
- *
- * Copyright 2011 - 2013 Basis Technology Corp.
- * Contact: carrier sleuthkit 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.beans.PropertyChangeListener;
-import java.beans.PropertyChangeSupport;
-import java.util.logging.Level;
-import javax.swing.JOptionPane;
-import javax.swing.SwingWorker;
-import org.netbeans.api.progress.ProgressHandle;
-import org.netbeans.api.progress.ProgressHandleFactory;
-import org.sleuthkit.autopsy.coreutils.Logger;
-import org.sleuthkit.datamodel.AbstractFile;
-import org.sleuthkit.datamodel.Content;
-import org.sleuthkit.datamodel.HashInfo;
-import org.sleuthkit.datamodel.SleuthkitJNI;
-import org.sleuthkit.datamodel.TskCoreException;
-import org.sleuthkit.datamodel.TskData;
-
-/**
- * Instances of this class represent hash databases used to classify files as
- * known or know bad.
- */
-public class HashDb {
- /**
- * Property change events published by hash database objects.
- */
- public enum Event {
- INDEXING_DONE
- }
-
- /**
- * The classification to apply to files whose hashes are stored in the
- * hash database.
- */
- public enum KnownFilesType{
- KNOWN("Known"),
- KNOWN_BAD("Known Bad");
-
- private String displayName;
-
- private KnownFilesType(String displayName) {
- this.displayName = displayName;
- }
-
- public String getDisplayName() {
- return this.displayName;
- }
- }
-
- private int handle;
- private KnownFilesType knownFilesType;
- private String databasePath;
- private String indexPath;
- private String hashSetName;
- private boolean useForIngest;
- private boolean sendHitMessages;
- private boolean indexing;
- private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
-
- /**
- * Opens an existing hash database.
- * @param hashSetName Name used to represent the hash database in user interface components.
- * @param selectedFilePath Full path to either a hash database file or a hash database index file.
- * @param useForIngest A flag indicating whether or not the hash database should be used during ingest.
- * @param sendHitMessages A flag indicating whether hash set hit messages should be sent to the application in box.
- * @param knownFilesType The classification to apply to files whose hashes are stored in the hash database.
- * @return A HashDb object representation of the new hash database.
- * @throws TskCoreException
- */
- public static HashDb openHashDatabase(String hashSetName, String selectedFilePath, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) throws TskCoreException {
- int handle = SleuthkitJNI.openHashDatabase(selectedFilePath);
- return new HashDb(handle, SleuthkitJNI.getHashDatabasePath(handle), SleuthkitJNI.getHashDatabaseIndexPath(handle), hashSetName, useForIngest, sendHitMessages, knownFilesType);
- }
-
- /**
- * Creates a new hash database.
- * @param hashSetName Hash set name used to represent the hash database in user interface components.
- * @param databasePath Full path to the database file to be created. The file name component of the path must have a ".kdb" extension.
- * @param useForIngest A flag indicating whether or not the data base should be used during the file ingest process.
- * @param showInboxMessages A flag indicating whether messages indicating lookup hits should be sent to the application in box.
- * @param hashSetType The type of hash set to associate with the database.
- * @return A HashDb object representation of the opened hash database.
- * @throws TskCoreException
- */
- public static HashDb createHashDatabase(String hashSetName, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType knownFilesType) throws TskCoreException {
- int handle = SleuthkitJNI.createHashDatabase(databasePath);
- return new HashDb(handle, SleuthkitJNI.getHashDatabasePath(handle), SleuthkitJNI.getHashDatabaseIndexPath(handle), hashSetName, useForIngest, showInboxMessages, knownFilesType);
- }
-
- private HashDb(int handle, String databasePath, String indexPath, String name, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) {
- this.databasePath = databasePath;
- this.indexPath = indexPath;
- this.hashSetName = name;
- this.useForIngest = useForIngest;
- this.sendHitMessages = sendHitMessages;
- this.knownFilesType = knownFilesType;
- this.handle = handle;
- this.indexing = false;
- }
-
- /**
- * Adds a listener for the events defined in HashDb.Event.
- */
- public void addPropertyChangeListener(PropertyChangeListener pcl) {
- propertyChangeSupport.addPropertyChangeListener(pcl);
- }
-
- /**
- * Removes a listener for the events defined in HashDb.Event.
- */
- public void removePropertyChangeListener(PropertyChangeListener pcl) {
- propertyChangeSupport.removePropertyChangeListener(pcl);
- }
-
- public String getHashSetName() {
- return hashSetName;
- }
-
- public String getDatabasePath() {
- return databasePath;
- }
-
- public String getIndexPath() {
- return indexPath;
- }
-
- public KnownFilesType getKnownFilesType() {
- return knownFilesType;
- }
-
- public boolean getUseForIngest() {
- return useForIngest;
- }
-
- void setUseForIngest(boolean useForIngest) {
- this.useForIngest = useForIngest;
- }
-
- public boolean getShowInboxMessages() {
- return sendHitMessages;
- }
-
- void setShowInboxMessages(boolean showInboxMessages) {
- this.sendHitMessages = showInboxMessages;
- }
-
- public boolean hasLookupIndex() throws TskCoreException {
- return SleuthkitJNI.hashDatabaseHasLookupIndex(handle);
- }
-
- public boolean canBeReindexed() throws TskCoreException {
- return SleuthkitJNI.hashDatabaseCanBeReindexed(handle);
- }
-
- public boolean hasIndexOnly() throws TskCoreException {
- return SleuthkitJNI.hashDatabaseHasLegacyLookupIndexOnly(handle);
- }
-
- /**
- * Indicates whether the hash database accepts updates.
- * @return True if the database accepts updates, false otherwise.
- */
- public boolean isUpdateable() throws TskCoreException {
- return SleuthkitJNI.isUpdateableHashDatabase(this.handle);
- }
-
- /**
- * Adds hashes of content (if calculated) to the hash database.
- * @param content The content for which the calculated hashes, if any, are to be added to the hash database.
- * @throws TskCoreException
- */
- public void add(Content content) throws TskCoreException {
- add(content, null);
- }
-
- /**
- * Adds hashes of content (if calculated) to the hash database.
- * @param content The content for which the calculated hashes, if any, are to be added to the hash database.
- * @param comment A comment to associate with the hashes, e.g., the name of the case in which the content was encountered.
- * @throws TskCoreException
- */
- public void add(Content content, String comment) throws TskCoreException {
- // TODO: This only works for AbstractFiles at present. Change when Content
- // can be queried for hashes.
- assert content instanceof AbstractFile;
- if (content instanceof AbstractFile) {
- AbstractFile file = (AbstractFile)content;
- // TODO: Add support for SHA-1 and SHA-256 hashes.
- if (null != file.getMd5Hash()) {
- SleuthkitJNI.addToHashDatabase(file.getName(), file.getMd5Hash(), null, null, comment, handle);
- }
- }
- }
-
- public boolean lookUp(Content content) throws TskCoreException {
- boolean result = false;
- // TODO: This only works for AbstractFiles at present. Change when Content can be queried for hashes.
- assert content instanceof AbstractFile;
- if (content instanceof AbstractFile) {
- AbstractFile file = (AbstractFile)content;
- // TODO: Add support for SHA-1 and SHA-256 hashes.
- if (null != file.getMd5Hash()) {
- result = SleuthkitJNI.lookupInHashDatabase(file.getMd5Hash(), handle);
- }
- }
- return result;
- }
-
- public HashInfo lookUpVerbose(Content content) throws TskCoreException {
- HashInfo result = null;
- // TODO: This only works for AbstractFiles at present. Change when Content can be queried for hashes.
- assert content instanceof AbstractFile;
- if (content instanceof AbstractFile) {
- AbstractFile file = (AbstractFile)content;
- // TODO: Add support for SHA-1 and SHA-256 hashes.
- if (null != file.getMd5Hash()) {
- result = SleuthkitJNI.lookupInHashDatabaseVerbose(file.getMd5Hash(), handle);
- }
- }
- return result;
- }
-
- boolean isIndexing() {
- return indexing;
- }
-
- // Tries to index the database (overwrites any existing index) using a
- // SwingWorker.
- void createIndex(boolean deleteIndexFile) {
- CreateIndex creator = new CreateIndex(deleteIndexFile);
- creator.execute();
- }
-
- private class CreateIndex extends SwingWorker {
- private ProgressHandle progress;
- private boolean deleteIndexFile;
-
- CreateIndex(boolean deleteIndexFile) {
- this.deleteIndexFile = deleteIndexFile;
- };
-
- @Override
- protected Object doInBackground() {
- indexing = true;
- progress = ProgressHandleFactory.createHandle("Indexing " + hashSetName);
- progress.start();
- progress.switchToIndeterminate();
- try {
- SleuthkitJNI.createLookupIndexForHashDatabase(handle, deleteIndexFile);
- indexPath = SleuthkitJNI.getHashDatabaseIndexPath(handle);
- }
- catch (TskCoreException ex) {
- Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error indexing hash database", ex);
- JOptionPane.showMessageDialog(null, "Error indexing hash database for " + getHashSetName() + ".", "Hash Database Index Error", JOptionPane.ERROR_MESSAGE);
- }
- return null;
- }
-
- @Override
- protected void done() {
- indexing = false;
- progress.finish();
- propertyChangeSupport.firePropertyChange(Event.INDEXING_DONE.toString(), null, hashSetName);
- }
- }
-
- public void close() throws TskCoreException {
- SleuthkitJNI.closeHashDatabase(handle);
- }
-}
\ No newline at end of file
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form
index 2cef194731..a56c3f2b57 100644
--- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form
+++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form
@@ -60,7 +60,6 @@
-
@@ -74,13 +73,6 @@
-
-
-
-
-
-
-
@@ -97,6 +89,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -106,12 +113,20 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
@@ -165,9 +180,9 @@
-
+
-
+
@@ -177,7 +192,7 @@
-
+
@@ -345,24 +360,24 @@
-
+
-
+
-
+
-
+
-
+
-
+
@@ -383,13 +398,13 @@
-
+
-
+
@@ -402,7 +417,7 @@
-
+
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java
index 34f9bca200..5f365f61d9 100644
--- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java
+++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java
@@ -40,13 +40,16 @@ import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
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.hashdatabase.HashDbManager.HashDb.KnownFilesType;
/**
* Instances of this class provide a comprehensive UI for managing the hash sets configuration.
*/
public final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel {
private static final String NO_SELECTION_TEXT = "No database selected";
- private static final String ERROR_GETTING_INDEX_STATUS = "Error occurred getting status";
+ private static final String ERROR_GETTING_PATH_TEXT = "Error occurred getting path";
+ private static final String ERROR_GETTING_INDEX_STATUS_TEXT = "Error occurred getting status";
private static final String LEGACY_INDEX_FILE_EXTENSION = "-md5.idx";
private HashDbManager hashSetManager = HashDbManager.getInstance();
private HashSetTableModel hashSetTableModel = new HashSetTableModel();
@@ -55,8 +58,19 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
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() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (isFileIngestStatusChangeEvent(evt)) {
+ updateComponents();
+ }
+ }
+ });
}
-
+
private void customizeComponents() {
setName("Hash Set Configuration");
this.ingestWarningLabel.setVisible(false);
@@ -100,16 +114,16 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
indexButton.setEnabled(false);
// Update ingest options.
- useForIngestCheckbox.setSelected(false);
- useForIngestCheckbox.setEnabled(false);
- showInboxMessagesCheckBox.setSelected(false);
- showInboxMessagesCheckBox.setEnabled(false);
+ searchDuringIngestCheckbox.setSelected(false);
+ searchDuringIngestCheckbox.setEnabled(false);
+ sendIngestMessagesCheckBox.setSelected(false);
+ sendIngestMessagesCheckBox.setEnabled(false);
optionsLabel.setEnabled(false);
optionsSeparator.setEnabled(false);
// Update database action buttons.
- newDatabaseButton.setEnabled(!ingestIsRunning);
- importDatabaseButton.setEnabled(!ingestIsRunning);
+ createDatabaseButton.setEnabled(true);
+ importDatabaseButton.setEnabled(true);
deleteDatabaseButton.setEnabled(false);
// Update ingest in progress warning label.
@@ -122,8 +136,22 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
// Update descriptive labels.
hashDbNameLabel.setText(db.getHashSetName());
hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName());
- hashDbLocationLabel.setText(shortenPath(db.getDatabasePath()));
- indexPathLabel.setText(shortenPath(db.getIndexPath()));
+
+ 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);
+ 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);
+ indexPathLabel.setText(ERROR_GETTING_PATH_TEXT);
+ }
// Update indexing components.
try {
@@ -144,7 +172,7 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
hashDbIndexStatusLabel.setText("Indexed");
}
hashDbIndexStatusLabel.setForeground(Color.black);
- if (db.canBeReindexed()) {
+ if (db.canBeReIndexed()) {
indexButton.setText("Re-Index");
indexButton.setEnabled(true);
}
@@ -162,29 +190,29 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index state of hash database", ex);
- hashDbIndexStatusLabel.setText(ERROR_GETTING_INDEX_STATUS);
+ hashDbIndexStatusLabel.setText(ERROR_GETTING_INDEX_STATUS_TEXT);
hashDbIndexStatusLabel.setForeground(Color.red);
indexButton.setText("Index");
indexButton.setEnabled(false);
}
- // Diable the indexing button if ingest is in progress.
+ // Disable the indexing button if ingest is in progress.
if (ingestIsRunning) {
indexButton.setEnabled(false);
}
// Update ingest option components.
- useForIngestCheckbox.setSelected(db.getUseForIngest());
- useForIngestCheckbox.setEnabled(!ingestIsRunning);
- showInboxMessagesCheckBox.setSelected(db.getShowInboxMessages());
- showInboxMessagesCheckBox.setEnabled(!ingestIsRunning && db.getUseForIngest() && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD));
- optionsLabel.setEnabled(!ingestIsRunning && db.getUseForIngest() && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD));
- optionsSeparator.setEnabled(!ingestIsRunning && db.getUseForIngest() && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD));
+ searchDuringIngestCheckbox.setSelected(db.getSearchDuringIngest());
+ searchDuringIngestCheckbox.setEnabled(!ingestIsRunning);
+ sendIngestMessagesCheckBox.setSelected(db.getSendIngestMessages());
+ 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);
- importDatabaseButton.setEnabled(!ingestIsRunning);
- importDatabaseButton.setEnabled(!ingestIsRunning);
// Update ingest in progress warning label.
ingestWarningLabel.setVisible(ingestIsRunning);
@@ -198,6 +226,10 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
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();
@@ -230,18 +262,9 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
hashSetManager.save();
}
- public void discard() {
- HashDbManager.getInstance().loadLastSavedConfiguration();
- }
-
- /**
- * Removes a list of HashDbs from the dialog panel that do not have a companion -md5.idx file.
- * Occurs when user clicks "No" to the dialog popup box.
- * @param toRemove a list of HashDbs that are unindexed
- */
void removeThese(List toRemove) {
for (HashDb hashDb : toRemove) {
- hashSetManager.removeHashSet(hashDb);
+ hashSetManager.removeHashDatabase(hashDb);
}
hashSetTableModel.refreshModel();
}
@@ -279,7 +302,6 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
}
boolean valid() {
- // TODO check whether form is consistent and complete
return true;
}
@@ -428,13 +450,13 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
hashDbIndexStatusLabel = new javax.swing.JLabel();
indexLabel = new javax.swing.JLabel();
indexButton = new javax.swing.JButton();
- useForIngestCheckbox = new javax.swing.JCheckBox();
- showInboxMessagesCheckBox = new javax.swing.JCheckBox();
+ searchDuringIngestCheckbox = new javax.swing.JCheckBox();
+ sendIngestMessagesCheckBox = new javax.swing.JCheckBox();
informationLabel = new javax.swing.JLabel();
optionsLabel = new javax.swing.JLabel();
informationSeparator = new javax.swing.JSeparator();
optionsSeparator = new javax.swing.JSeparator();
- newDatabaseButton = new javax.swing.JButton();
+ createDatabaseButton = new javax.swing.JButton();
indexPathLabelLabel = new javax.swing.JLabel();
indexPathLabel = new javax.swing.JLabel();
@@ -518,17 +540,17 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
}
});
- org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.useForIngestCheckbox.text")); // NOI18N
- useForIngestCheckbox.addActionListener(new java.awt.event.ActionListener() {
+ org.openide.awt.Mnemonics.setLocalizedText(searchDuringIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.searchDuringIngestCheckbox.text")); // NOI18N
+ searchDuringIngestCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
- useForIngestCheckboxActionPerformed(evt);
+ searchDuringIngestCheckboxActionPerformed(evt);
}
});
- org.openide.awt.Mnemonics.setLocalizedText(showInboxMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.showInboxMessagesCheckBox.text")); // NOI18N
- showInboxMessagesCheckBox.addActionListener(new java.awt.event.ActionListener() {
+ org.openide.awt.Mnemonics.setLocalizedText(sendIngestMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.sendIngestMessagesCheckBox.text")); // NOI18N
+ sendIngestMessagesCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
- showInboxMessagesCheckBoxActionPerformed(evt);
+ sendIngestMessagesCheckBoxActionPerformed(evt);
}
});
@@ -536,14 +558,14 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.optionsLabel.text")); // NOI18N
- newDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/new16.png"))); // NOI18N
- org.openide.awt.Mnemonics.setLocalizedText(newDatabaseButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.newDatabaseButton.text")); // NOI18N
- newDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25));
- newDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25));
- newDatabaseButton.setPreferredSize(new java.awt.Dimension(140, 25));
- newDatabaseButton.addActionListener(new java.awt.event.ActionListener() {
+ 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
+ createDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25));
+ createDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25));
+ createDatabaseButton.setPreferredSize(new java.awt.Dimension(140, 25));
+ createDatabaseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
- newDatabaseButtonActionPerformed(evt);
+ createDatabaseButtonActionPerformed(evt);
}
});
@@ -558,7 +580,6 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(hashDatabasesLabel)
.addGroup(layout.createSequentialGroup()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 275, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
@@ -571,12 +592,6 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(layout.createSequentialGroup()
- .addComponent(nameLabel)
- .addGap(53, 53, 53)
- .addComponent(hashDbNameLabel))
- .addComponent(useForIngestCheckbox)
- .addComponent(showInboxMessagesCheckBox)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(locationLabel)
@@ -589,16 +604,32 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
.addComponent(hashDbTypeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 241, Short.MAX_VALUE)
.addComponent(hashDbLocationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(indexPathLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(hashDbIndexStatusLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
+ .addComponent(hashDbIndexStatusLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+ .addGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(nameLabel)
+ .addGap(53, 53, 53)
+ .addComponent(hashDbNameLabel))
+ .addComponent(searchDuringIngestCheckbox)
+ .addGroup(layout.createSequentialGroup()
+ .addGap(21, 21, 21)
+ .addComponent(sendIngestMessagesCheckBox)))
+ .addGap(0, 0, Short.MAX_VALUE))))
.addGroup(layout.createSequentialGroup()
.addComponent(optionsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(optionsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 324, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addGroup(layout.createSequentialGroup()
- .addComponent(newDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(importDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(hashDatabasesLabel)
+ .addGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
+ .addComponent(deleteDatabaseButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
+ .addComponent(createDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 137, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(importDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)))
+ .addGap(0, 0, Short.MAX_VALUE)))
.addGap(24, 24, 24))
);
layout.setVerticalGroup(
@@ -641,9 +672,9 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
.addComponent(optionsLabel)
.addComponent(optionsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 6, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
- .addComponent(useForIngestCheckbox)
+ .addComponent(searchDuringIngestCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
- .addComponent(showInboxMessagesCheckBox)
+ .addComponent(sendIngestMessagesCheckBox)
.addGap(18, 18, 18)
.addComponent(ingestWarningLabel)
.addGap(0, 0, Short.MAX_VALUE))
@@ -651,7 +682,7 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(importDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(newDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addComponent(createDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
@@ -689,10 +720,10 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
}//GEN-LAST:event_indexButtonActionPerformed
private void deleteDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteDatabaseButtonActionPerformed
- if (JOptionPane.showConfirmDialog(null, "This will remove the hash database entry globally (for all Cases). Do you want to proceed? ", "Deleting a Hash Database Entry", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) {
+ if (JOptionPane.showConfirmDialog(null, "This will remove the hash database for all cases. Do you want to proceed? ", "Delete Hash Database from Configuration", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) {
HashDb hashDb = ((HashSetTable)hashSetTable).getSelection();
if (hashDb != null) {
- hashSetManager.removeHashSet(hashDb);
+ hashSetManager.removeHashDatabase(hashDb);
hashSetTableModel.refreshModel();
}
}
@@ -702,46 +733,48 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
if (evt.getKeyCode() == KeyEvent.VK_DELETE) {
HashDb hashDb = ((HashSetTable)hashSetTable).getSelection();
if (hashDb != null) {
- hashSetManager.removeHashSet(hashDb);
+ hashSetManager.removeHashDatabase(hashDb);
hashSetTableModel.refreshModel();
}
}
}//GEN-LAST:event_hashSetTableKeyPressed
- private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed
+ private void searchDuringIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchDuringIngestCheckboxActionPerformed
HashDb hashDb = ((HashSetTable)hashSetTable).getSelection();
if (hashDb != null) {
- hashDb.setUseForIngest(useForIngestCheckbox.isSelected());
- showInboxMessagesCheckBox.setEnabled(useForIngestCheckbox.isSelected());
+ hashDb.setSearchDuringIngest(searchDuringIngestCheckbox.isSelected());
+ if (!searchDuringIngestCheckbox.isSelected()) {
+ sendIngestMessagesCheckBox.setSelected(false);
+ }
+ hashDb.setSendIngestMessages(sendIngestMessagesCheckBox.isSelected());
}
- }//GEN-LAST:event_useForIngestCheckboxActionPerformed
+ }//GEN-LAST:event_searchDuringIngestCheckboxActionPerformed
- private void showInboxMessagesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showInboxMessagesCheckBoxActionPerformed
+ private void sendIngestMessagesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sendIngestMessagesCheckBoxActionPerformed
HashDb hashDb = ((HashSetTable)hashSetTable).getSelection();
if (hashDb != null) {
- hashDb.setShowInboxMessages(showInboxMessagesCheckBox.isSelected());
+ hashDb.setSendIngestMessages(sendIngestMessagesCheckBox.isSelected());
}
- }//GEN-LAST:event_showInboxMessagesCheckBoxActionPerformed
+ }//GEN-LAST:event_sendIngestMessagesCheckBoxActionPerformed
private void importDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importDatabaseButtonActionPerformed
- HashDb hashDb = new HashDbImportDatabaseDialog().doDialog();
- if (hashDb != null) {
- hashSetManager.addHashSet(hashDb);
+ HashDb hashDb = new HashDbImportDatabaseDialog().getHashDatabase();
+ if (null != hashDb) {
hashSetTableModel.refreshModel();
((HashSetTable)hashSetTable).selectRowByName(hashDb.getHashSetName());
}
}//GEN-LAST:event_importDatabaseButtonActionPerformed
- private void newDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newDatabaseButtonActionPerformed
- HashDb hashDb = new HashDbCreateDatabaseDialog().doDialog();
+ private void createDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createDatabaseButtonActionPerformed
+ HashDb hashDb = new HashDbCreateDatabaseDialog().getHashDatabase();
if (null != hashDb) {
- hashSetManager.addHashSet(hashDb);
hashSetTableModel.refreshModel();
((HashSetTable)hashSetTable).selectRowByName(hashDb.getHashSetName());
}
- }//GEN-LAST:event_newDatabaseButtonActionPerformed
+ }//GEN-LAST:event_createDatabaseButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JButton createDatabaseButton;
private javax.swing.JButton deleteDatabaseButton;
private javax.swing.JLabel hashDatabasesLabel;
private javax.swing.JLabel hashDbIndexStatusLabel;
@@ -764,11 +797,10 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JLabel locationLabel;
private javax.swing.JLabel nameLabel;
- private javax.swing.JButton newDatabaseButton;
private javax.swing.JLabel optionsLabel;
private javax.swing.JSeparator optionsSeparator;
- private javax.swing.JCheckBox showInboxMessagesCheckBox;
+ private javax.swing.JCheckBox searchDuringIngestCheckbox;
+ private javax.swing.JCheckBox sendIngestMessagesCheckBox;
private javax.swing.JLabel typeLabel;
- private javax.swing.JCheckBox useForIngestCheckbox;
// End of variables declaration//GEN-END:variables
}
\ No newline at end of file
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form
index 56cbcf2e03..047c483d48 100644
--- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form
+++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form
@@ -32,43 +32,48 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -77,45 +82,46 @@
+
+
+
+
+
-
-
-
-
+
-
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
@@ -128,23 +134,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -179,10 +168,10 @@
-
+
-
+
@@ -193,24 +182,52 @@
-
+
-
+
+
+
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java
index cadbced05d..842f1d5e06 100644
--- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java
+++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java
@@ -27,31 +27,60 @@ import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
-import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.JFrame;
import org.apache.commons.io.FilenameUtils;
-import org.sleuthkit.autopsy.hashdatabase.HashDb.KnownFilesType;
import org.sleuthkit.datamodel.TskCoreException;
+import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
+import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb.KnownFilesType;
+import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDatabaseFileAlreadyExistsException;
+import org.sleuthkit.autopsy.hashdatabase.HashDbManager.DuplicateHashSetNameException;
+import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDatabaseAlreadyAddedException;
+import org.sleuthkit.autopsy.hashdatabase.HashDbManager.IllegalHashDatabaseFileNameExtensionException;
-final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
- private JFileChooser fileChooser;
+/**
+ * Instances of this class allow a user to create a new hash database and
+ * add it to the set of hash databases used to classify files as unknown, known
+ * or known bad.
+ */
+final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
+
+ private static final String DEFAULT_FILE_NAME = "hashset";
+ private JFileChooser fileChooser = null;
private HashDb newHashDb = null;
+ /**
+ * Displays a dialog that allows a user to create a new hash database and
+ * add it to the set of hash databases used to classify files as unknown, known
+ * or known bad.
+ */
HashDbCreateDatabaseDialog() {
- super(new javax.swing.JFrame(), "Create Hash Database", true);
- setResizable(false);
+ super(new JFrame(), "Create Hash Database", true);
+ initFileChooser();
+ initComponents();
+ display();
+ }
+
+ /**
+ * Get the hash database created by the user, if any.
+ * @return A HashDb object or null.
+ */
+ HashDb getHashDatabase() {
+ return newHashDb;
+ }
+
+ private void initFileChooser() {
fileChooser = new JFileChooser() {
@Override
public void approveSelection() {
File selectedFile = getSelectedFile();
- if (!FilenameUtils.getExtension(selectedFile.getName()).equalsIgnoreCase("kdb")) {
- if (JOptionPane.showConfirmDialog(this, "The file must have a .kdb extension.", "File Name Error", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) {
+ if (!FilenameUtils.getExtension(selectedFile.getName()).equalsIgnoreCase(HashDbManager.getHashDatabaseFileExtension())) {
+ if (JOptionPane.showConfirmDialog(this, "The hash database file must have a ." + HashDbManager.getHashDatabaseFileExtension() + " extension.", "File Name Error", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) {
cancelSelection();
}
return;
}
if (selectedFile.exists()) {
- int r = JOptionPane.showConfirmDialog(this, "A file with this name already exists. Please enter a new filename.", "Existing File", JOptionPane.OK_CANCEL_OPTION);
- if (r == JOptionPane.CANCEL_OPTION) {
+ if (JOptionPane.showConfirmDialog(this, "A file with this name already exists. Please choose a new file name.", "File Already Exists Error", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) {
cancelSelection();
}
return;
@@ -59,30 +88,17 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
super.approveSelection();
}
};
- initComponents();
- customizeComponents();
- }
-
- void customizeComponents() {
- fileChooser.setDragEnabled(false);
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
- String[] EXTENSION = new String[] { "txt", "kdb", "idx", "hash", "Hash", "hsh"};
- FileNameExtensionFilter filter = new FileNameExtensionFilter("Hash Database File", EXTENSION);
- fileChooser.setFileFilter(filter);
- fileChooser.setMultiSelectionEnabled(false);
+ fileChooser.setDragEnabled(false);
+ fileChooser.setMultiSelectionEnabled(false);
}
- HashDb doDialog() {
- newHashDb = null;
-
- // Center and display the dialog.
+ private void display() {
Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2);
- this.setVisible(true);
-
- return newHashDb;
+ setVisible(true);
}
-
+
/**
* 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
@@ -93,24 +109,25 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
private void initComponents() {
buttonGroup1 = new javax.swing.ButtonGroup();
- okButton = new javax.swing.JButton();
+ saveAsButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
- databasePathTextField = new javax.swing.JTextField();
- browseButton = new javax.swing.JButton();
knownRadioButton = new javax.swing.JRadioButton();
knownBadRadioButton = new javax.swing.JRadioButton();
jLabel1 = new javax.swing.JLabel();
- databaseNameTextField = new javax.swing.JTextField();
+ hashSetNameTextField = new javax.swing.JTextField();
jLabel2 = new javax.swing.JLabel();
- useForIngestCheckbox = new javax.swing.JCheckBox();
- sendInboxMessagesCheckbox = new javax.swing.JCheckBox();
+ searchDuringIngestCheckbox = new javax.swing.JCheckBox();
+ sendIngestMessagesCheckbox = new javax.swing.JCheckBox();
+ jLabel3 = new javax.swing.JLabel();
+ databasePathTextField = new javax.swing.JTextField();
+ okButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
- org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.okButton.text")); // NOI18N
- okButton.addActionListener(new java.awt.event.ActionListener() {
+ org.openide.awt.Mnemonics.setLocalizedText(saveAsButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.saveAsButton.text")); // NOI18N
+ saveAsButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
- okButtonActionPerformed(evt);
+ saveAsButtonActionPerformed(evt);
}
});
@@ -121,15 +138,6 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
}
});
- databasePathTextField.setText(org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.databasePathTextField.text")); // NOI18N
-
- org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.browseButton.text")); // NOI18N
- browseButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- browseButtonActionPerformed(evt);
- }
- });
-
buttonGroup1.add(knownRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(knownRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.knownRadioButton.text")); // NOI18N
knownRadioButton.addActionListener(new java.awt.event.ActionListener() {
@@ -149,20 +157,33 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.jLabel1.text")); // NOI18N
- databaseNameTextField.setText(org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.databaseNameTextField.text")); // NOI18N
+ hashSetNameTextField.setText(org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.hashSetNameTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.jLabel2.text")); // NOI18N
- useForIngestCheckbox.setSelected(true);
- org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.useForIngestCheckbox.text")); // NOI18N
- useForIngestCheckbox.addActionListener(new java.awt.event.ActionListener() {
+ searchDuringIngestCheckbox.setSelected(true);
+ org.openide.awt.Mnemonics.setLocalizedText(searchDuringIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.searchDuringIngestCheckbox.text")); // NOI18N
+ searchDuringIngestCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.searchDuringIngestCheckbox.toolTipText")); // NOI18N
+ searchDuringIngestCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
- useForIngestCheckboxActionPerformed(evt);
+ searchDuringIngestCheckboxActionPerformed(evt);
}
});
- sendInboxMessagesCheckbox.setSelected(true);
- org.openide.awt.Mnemonics.setLocalizedText(sendInboxMessagesCheckbox, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.sendInboxMessagesCheckbox.text")); // NOI18N
+ sendIngestMessagesCheckbox.setSelected(true);
+ org.openide.awt.Mnemonics.setLocalizedText(sendIngestMessagesCheckbox, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.sendIngestMessagesCheckbox.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.jLabel3.text")); // NOI18N
+
+ databasePathTextField.setEditable(false);
+ databasePathTextField.setText(org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.databasePathTextField.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.okButton.text")); // NOI18N
+ okButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ okButtonActionPerformed(evt);
+ }
+ });
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
@@ -174,142 +195,175 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
+ .addGap(21, 21, 21)
+ .addComponent(sendIngestMessagesCheckbox))
+ .addComponent(searchDuringIngestCheckbox))
+ .addGap(0, 0, Short.MAX_VALUE))
+ .addGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(okButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton))
+ .addComponent(jLabel2)
.addGroup(layout.createSequentialGroup()
- .addComponent(databasePathTextField)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(browseButton))
+ .addGap(20, 20, 20)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(knownRadioButton)
+ .addComponent(knownBadRadioButton)))
.addGroup(layout.createSequentialGroup()
- .addComponent(jLabel1)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(databaseNameTextField))
- .addGroup(layout.createSequentialGroup()
- .addComponent(jLabel2)
- .addGap(0, 0, Short.MAX_VALUE)))
- .addContainerGap())
- .addGroup(layout.createSequentialGroup()
- .addGap(10, 10, 10)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(knownBadRadioButton)
- .addComponent(knownRadioButton))
- .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
- .addGroup(layout.createSequentialGroup()
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(useForIngestCheckbox)
- .addComponent(sendInboxMessagesCheckbox))
- .addGap(0, 135, Short.MAX_VALUE))))
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(jLabel1)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(databasePathTextField))
+ .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
+ .addComponent(jLabel3)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 272, javax.swing.GroupLayout.PREFERRED_SIZE)))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(saveAsButton)))
+ .addContainerGap())))
);
+
+ layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, okButton});
+
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
- .addContainerGap()
+ .addGap(2, 2, 2)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel3)
+ .addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(databasePathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(browseButton))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(jLabel1)
- .addComponent(databaseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(saveAsButton)
+ .addComponent(jLabel1))
+ .addGap(7, 7, 7)
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(knownRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(knownBadRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
- .addComponent(useForIngestCheckbox)
+ .addComponent(searchDuringIngestCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(sendInboxMessagesCheckbox)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(sendIngestMessagesCheckbox)
+ .addGap(3, 3, 3)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(okButton)
- .addComponent(cancelButton))
- .addContainerGap())
+ .addComponent(cancelButton)
+ .addComponent(okButton))
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// //GEN-END:initComponents
- private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
- try {
- fileChooser.setSelectedFile(new File("hash.kdb"));
- if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
- File databaseFile = fileChooser.getSelectedFile();
- databasePathTextField.setText(databaseFile.getCanonicalPath());
- databaseNameTextField.setText(FilenameUtils.removeExtension(databaseFile.getName()));
- if (databaseNameTextField.getText().toLowerCase().contains("nsrl")) {
- knownRadioButton.setSelected(true);
- knownRadioButtonActionPerformed(null);
- }
- }
- }
- catch (IOException ex) {
- Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, "Couldn't get selected file path.", ex);
- }
- }//GEN-LAST:event_browseButtonActionPerformed
-
private void knownRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownRadioButtonActionPerformed
- sendInboxMessagesCheckbox.setSelected(false);
- sendInboxMessagesCheckbox.setEnabled(false);
+ searchDuringIngestCheckbox.setSelected(true);
+ sendIngestMessagesCheckbox.setSelected(false);
+ sendIngestMessagesCheckbox.setEnabled(false);
}//GEN-LAST:event_knownRadioButtonActionPerformed
private void knownBadRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownBadRadioButtonActionPerformed
- sendInboxMessagesCheckbox.setSelected(true);
- sendInboxMessagesCheckbox.setEnabled(true);
+ searchDuringIngestCheckbox.setSelected(true);
+ sendIngestMessagesCheckbox.setSelected(true);
+ sendIngestMessagesCheckbox.setEnabled(true);
}//GEN-LAST:event_knownBadRadioButtonActionPerformed
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
- this.dispose();
+ dispose();
}//GEN-LAST:event_cancelButtonActionPerformed
- private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
- if(databasePathTextField.getText().isEmpty()) {
- JOptionPane.showMessageDialog(this, "Database path cannot be empty");
- return;
- }
- if(databaseNameTextField.getText().isEmpty()) {
- JOptionPane.showMessageDialog(this, "Database name cannot be empty");
- return;
+ private void saveAsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveAsButtonActionPerformed
+ try {
+ StringBuilder path = new StringBuilder();
+ if (!hashSetNameTextField.getText().isEmpty()) {
+ path.append(hashSetNameTextField.getText());
+ }
+ else {
+ path.append(DEFAULT_FILE_NAME);
+ }
+ path.append(".").append(HashDbManager.getHashDatabaseFileExtension());
+ fileChooser.setSelectedFile(new File(path.toString()));
+ if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
+ File databaseFile = fileChooser.getSelectedFile();
+ databasePathTextField.setText(databaseFile.getCanonicalPath());
+ }
}
+ catch (IOException ex) {
+ Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, "Couldn't get selected file path.", ex);
+ }
+ }//GEN-LAST:event_saveAsButtonActionPerformed
+ private void searchDuringIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchDuringIngestCheckboxActionPerformed
+ sendIngestMessagesCheckbox.setEnabled(searchDuringIngestCheckbox.isSelected());
+ if (!searchDuringIngestCheckbox.isSelected()) {
+ sendIngestMessagesCheckbox.setSelected(false);
+ }
+ }//GEN-LAST:event_searchDuringIngestCheckboxActionPerformed
+
+ private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
+ // Note that the error handlers in this method call return without disposing of the
+ // dialog to allow the user to try again, if desired.
+
+ if (hashSetNameTextField.getText().isEmpty()) {
+ JOptionPane.showMessageDialog(this, "A hash set name must be entered.", "Create Hash Database Error", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+
+ if (databasePathTextField.getText().isEmpty()) {
+ JOptionPane.showMessageDialog(this, "A database path must be entered.", "Create Hash Database Error", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+
KnownFilesType type;
- if(knownRadioButton.isSelected()) {
+ if (knownRadioButton.isSelected()) {
type = KnownFilesType.KNOWN;
- } else {
+ }
+ else {
type = KnownFilesType.KNOWN_BAD;
}
-
+
+ String errorMessage = "Hash database creation error";
try
{
- newHashDb = HashDb.createHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type);
+ newHashDb = HashDbManager.getInstance().addNewHashDatabase(hashSetNameTextField.getText(), fileChooser.getSelectedFile().getCanonicalPath(), searchDuringIngestCheckbox.isSelected(), sendIngestMessagesCheckbox.isSelected(), type);
}
+ catch (IOException ex) {
+ Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex);
+ JOptionPane.showMessageDialog(this, "Cannot create a hash database file at the selected location.", "Create Hash Database Error", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ catch (HashDatabaseFileAlreadyExistsException | DuplicateHashSetNameException | HashDatabaseAlreadyAddedException | IllegalHashDatabaseFileNameExtensionException ex) {
+ Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex);
+ JOptionPane.showMessageDialog(this, ex.getMessage(), "Create Hash Database Error", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
catch (TskCoreException ex) {
- Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.SEVERE, "Hash database creation error", ex);
- JOptionPane.showMessageDialog(this, "Failed to create hash database.");
+ Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.SEVERE, errorMessage, ex);
+ JOptionPane.showMessageDialog(this, "Failed to create the hash database.", "Create Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
}
-
- this.dispose();
+
+ dispose();
}//GEN-LAST:event_okButtonActionPerformed
- private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed
- }//GEN-LAST:event_useForIngestCheckboxActionPerformed
-
// Variables declaration - do not modify//GEN-BEGIN:variables
- private javax.swing.JButton browseButton;
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JButton cancelButton;
- private javax.swing.JTextField databaseNameTextField;
private javax.swing.JTextField databasePathTextField;
+ private javax.swing.JTextField hashSetNameTextField;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
+ private javax.swing.JLabel jLabel3;
private javax.swing.JRadioButton knownBadRadioButton;
private javax.swing.JRadioButton knownRadioButton;
private javax.swing.JButton okButton;
- private javax.swing.JCheckBox sendInboxMessagesCheckbox;
- private javax.swing.JCheckBox useForIngestCheckbox;
+ private javax.swing.JButton saveAsButton;
+ private javax.swing.JCheckBox searchDuringIngestCheckbox;
+ private javax.swing.JCheckBox sendIngestMessagesCheckbox;
// End of variables declaration//GEN-END:variables
}
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.form
index 5cb8ef9c34..627f4090ba 100644
--- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.form
+++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.form
@@ -30,47 +30,50 @@
-
+
-
-
-
-
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -79,30 +82,38 @@
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
@@ -130,19 +141,20 @@
+
-
+
-
+
-
+
@@ -179,10 +191,10 @@
-
+
-
+
@@ -193,22 +205,29 @@
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java
index d4cea65dbb..33516bad99 100644
--- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java
+++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java
@@ -27,44 +27,69 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;
-import org.sleuthkit.autopsy.hashdatabase.HashDb.KnownFilesType;
+import javax.swing.JFrame;
import org.sleuthkit.datamodel.TskCoreException;
import org.apache.commons.io.FilenameUtils;
+import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb.KnownFilesType;
+import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
+import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDatabaseDoesNotExistException;
+import org.sleuthkit.autopsy.hashdatabase.HashDbManager.DuplicateHashSetNameException;
+import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDatabaseAlreadyAddedException;
/**
- * Instances of this class allow a user to select a hash database for import.
+ * Instances of this class allow a user to select an existing hash database and
+ * add it to the set of hash databases used to classify files as unknown, known,
+ * or known bad.
*/
final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
- private JFileChooser fileChooser = new JFileChooser();
- private HashDb selectedHashDb;
-
- HashDbImportDatabaseDialog() {
- super(new javax.swing.JFrame(), "Import Hash Database", true);
- setResizable(false);
- initComponents();
- customizeComponents();
- }
- void customizeComponents() {
+ private JFileChooser fileChooser = new JFileChooser();
+ private String selectedFilePath = "";
+ private HashDb selectedHashDb = null;
+
+ /**
+ * Displays a dialog that allows a user to select an existing hash database
+ * and add it to the set of hash databases used to classify files as unknown,
+ * known, or known bad.
+ */
+ HashDbImportDatabaseDialog() {
+ super(new JFrame(), "Import Hash Database", true);
+ initFileChooser();
+ initComponents();
+ display();
+ }
+
+ /**
+ * Get the hash database imported by the user, if any.
+ * @return A HashDb object or null.
+ */
+ HashDb getHashDatabase() {
+ return selectedHashDb;
+ }
+
+ private void initFileChooser() {
fileChooser.setDragEnabled(false);
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
String[] EXTENSION = new String[] { "txt", "kdb", "idx", "hash", "Hash", "hsh"};
FileNameExtensionFilter filter = new FileNameExtensionFilter("Hash Database File", EXTENSION);
fileChooser.setFileFilter(filter);
- fileChooser.setMultiSelectionEnabled(false);
- }
-
- HashDb doDialog() {
- selectedHashDb = null;
-
- // Center and display the dialog.
- Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
- setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2);
- this.setVisible(true);
-
- return selectedHashDb;
+ fileChooser.setMultiSelectionEnabled(false);
}
+ private void display() {
+ Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
+ setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2);
+ setVisible(true);
+ }
+
+ private static String shortenPath(String path) {
+ String shortenedPath = path;
+ 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;
+ }
+
/**
* 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
@@ -78,14 +103,15 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
okButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
databasePathTextField = new javax.swing.JTextField();
- browseButton = new javax.swing.JButton();
+ openButton = new javax.swing.JButton();
knownRadioButton = new javax.swing.JRadioButton();
knownBadRadioButton = new javax.swing.JRadioButton();
jLabel1 = new javax.swing.JLabel();
- databaseNameTextField = new javax.swing.JTextField();
+ hashSetNameTextField = new javax.swing.JTextField();
jLabel2 = new javax.swing.JLabel();
- useForIngestCheckbox = new javax.swing.JCheckBox();
- sendInboxMessagesCheckbox = new javax.swing.JCheckBox();
+ searchDuringIngestCheckbox = new javax.swing.JCheckBox();
+ sendIngestMessagesCheckbox = new javax.swing.JCheckBox();
+ jLabel3 = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
@@ -103,12 +129,13 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
}
});
+ databasePathTextField.setEditable(false);
databasePathTextField.setText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.databasePathTextField.text")); // NOI18N
- org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.browseButton.text")); // NOI18N
- browseButton.addActionListener(new java.awt.event.ActionListener() {
+ org.openide.awt.Mnemonics.setLocalizedText(openButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.openButton.text")); // NOI18N
+ openButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
- browseButtonActionPerformed(evt);
+ openButtonActionPerformed(evt);
}
});
@@ -131,20 +158,22 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.jLabel1.text")); // NOI18N
- databaseNameTextField.setText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.databaseNameTextField.text")); // NOI18N
+ hashSetNameTextField.setText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.hashSetNameTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.jLabel2.text")); // NOI18N
- useForIngestCheckbox.setSelected(true);
- org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.useForIngestCheckbox.text")); // NOI18N
- useForIngestCheckbox.addActionListener(new java.awt.event.ActionListener() {
+ searchDuringIngestCheckbox.setSelected(true);
+ org.openide.awt.Mnemonics.setLocalizedText(searchDuringIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.searchDuringIngestCheckbox.text")); // NOI18N
+ searchDuringIngestCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
- useForIngestCheckboxActionPerformed(evt);
+ searchDuringIngestCheckboxActionPerformed(evt);
}
});
- sendInboxMessagesCheckbox.setSelected(true);
- org.openide.awt.Mnemonics.setLocalizedText(sendInboxMessagesCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.sendInboxMessagesCheckbox.text")); // NOI18N
+ sendIngestMessagesCheckbox.setSelected(true);
+ org.openide.awt.Mnemonics.setLocalizedText(sendIngestMessagesCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.sendIngestMessagesCheckbox.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.jLabel3.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
@@ -156,90 +185,104 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
- .addGap(0, 0, Short.MAX_VALUE)
- .addComponent(okButton)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(cancelButton))
- .addGroup(layout.createSequentialGroup()
- .addComponent(databasePathTextField)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(browseButton))
+ .addGap(21, 21, 21)
+ .addComponent(sendIngestMessagesCheckbox))
+ .addComponent(searchDuringIngestCheckbox))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(okButton)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(cancelButton))
+ .addGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jLabel2)
.addGroup(layout.createSequentialGroup()
+ .addGap(19, 19, 19)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(knownRadioButton)
+ .addComponent(knownBadRadioButton))))
+ .addGap(0, 307, Short.MAX_VALUE))
+ .addGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+ .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(databaseNameTextField))
- .addGroup(layout.createSequentialGroup()
- .addComponent(jLabel2)
- .addGap(0, 0, Short.MAX_VALUE)))
- .addContainerGap())
- .addGroup(layout.createSequentialGroup()
- .addGap(10, 10, 10)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(knownBadRadioButton)
- .addComponent(knownRadioButton))
- .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
- .addGroup(layout.createSequentialGroup()
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(useForIngestCheckbox)
- .addComponent(sendInboxMessagesCheckbox))
- .addGap(0, 135, Short.MAX_VALUE))))
+ .addComponent(hashSetNameTextField))
+ .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
+ .addComponent(jLabel3)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(databasePathTextField)))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(openButton)))
+ .addContainerGap())
);
+
+ layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, okButton});
+
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(openButton)
.addComponent(databasePathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(browseButton))
+ .addComponent(jLabel3))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
- .addComponent(databaseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(jLabel2)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(knownRadioButton)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(knownBadRadioButton)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
- .addComponent(useForIngestCheckbox)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(sendInboxMessagesCheckbox)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(okButton)
- .addComponent(cancelButton))
- .addContainerGap())
+ .addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 119, Short.MAX_VALUE)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(okButton)
+ .addComponent(cancelButton))
+ .addContainerGap())
+ .addGroup(layout.createSequentialGroup()
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(jLabel2)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(knownRadioButton)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(knownBadRadioButton)
+ .addGap(13, 13, 13)
+ .addComponent(searchDuringIngestCheckbox)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(sendIngestMessagesCheckbox)
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
);
pack();
}// //GEN-END:initComponents
- private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
+ private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
File databaseFile = fileChooser.getSelectedFile();
try {
- databasePathTextField.setText(databaseFile.getCanonicalPath());
- databaseNameTextField.setText(FilenameUtils.removeExtension(databaseFile.getName()));
- if (databaseNameTextField.getText().toLowerCase().contains("nsrl")) {
+ selectedFilePath = databaseFile.getCanonicalPath();
+ databasePathTextField.setText(shortenPath(selectedFilePath));
+ hashSetNameTextField.setText(FilenameUtils.removeExtension(databaseFile.getName()));
+ if (hashSetNameTextField.getText().toLowerCase().contains("nsrl")) {
knownRadioButton.setSelected(true);
knownRadioButtonActionPerformed(null);
}
}
catch (IOException ex) {
Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Failed to get path of selected database", ex);
+ JOptionPane.showMessageDialog(this, "Failed to get the path of the selected database.");
}
}
- }//GEN-LAST:event_browseButtonActionPerformed
+ }//GEN-LAST:event_openButtonActionPerformed
private void knownRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownRadioButtonActionPerformed
- sendInboxMessagesCheckbox.setSelected(false);
- sendInboxMessagesCheckbox.setEnabled(false);
+ searchDuringIngestCheckbox.setSelected(true);
+ sendIngestMessagesCheckbox.setSelected(false);
+ sendIngestMessagesCheckbox.setEnabled(false);
}//GEN-LAST:event_knownRadioButtonActionPerformed
private void knownBadRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownBadRadioButtonActionPerformed
- sendInboxMessagesCheckbox.setSelected(true);
- sendInboxMessagesCheckbox.setEnabled(true);
+ searchDuringIngestCheckbox.setSelected(true);
+ sendIngestMessagesCheckbox.setSelected(true);
+ sendIngestMessagesCheckbox.setEnabled(true);
}//GEN-LAST:event_knownBadRadioButtonActionPerformed
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
@@ -247,32 +290,24 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
}//GEN-LAST:event_cancelButtonActionPerformed
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
- if(databasePathTextField.getText().isEmpty()) {
- JOptionPane.showMessageDialog(this, "Hash database file path cannot be empty.");
+ // Note that the error handlers in this method call return without disposing of the
+ // dialog to allow the user to try again, if desired.
+
+ if(hashSetNameTextField.getText().isEmpty()) {
+ JOptionPane.showMessageDialog(this, "A hash set name must be entered.", "Import Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
}
- if(databaseNameTextField.getText().isEmpty()) {
- JOptionPane.showMessageDialog(this, "Hash set name cannot be empty.");
+ if(selectedFilePath.isEmpty()) {
+ JOptionPane.showMessageDialog(this, "A hash database file path must be selected.", "Import Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
- }
-
- File file = new File(databasePathTextField.getText());
+ }
+ File file = new File(selectedFilePath);
if (!file.exists()) {
- JOptionPane.showMessageDialog(this, "Selected hash database does not exist.");
+ JOptionPane.showMessageDialog(this, "The selected hash database does not exist.", "Import Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
}
-
- String filePath;
- try {
- filePath = file.getCanonicalPath();
- }
- catch (IOException ex) {
- Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Failed to get path of selected database", ex);
- JOptionPane.showMessageDialog(this, "Failed to get path of selected database.");
- return;
- }
-
+
KnownFilesType type;
if (knownRadioButton.isSelected()) {
type = KnownFilesType.KNOWN;
@@ -281,33 +316,44 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
type = KnownFilesType.KNOWN_BAD;
}
+ String errorMessage = "Failed to open hash database at " + selectedFilePath + ".";
try {
- selectedHashDb = HashDb.openHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type);
+ selectedHashDb = HashDbManager.getInstance().addExistingHashDatabase(hashSetNameTextField.getText(), selectedFilePath, searchDuringIngestCheckbox.isSelected(), sendIngestMessagesCheckbox.isSelected(), type);
}
- catch (TskCoreException ex) {
- Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Failed to open hash database at " + filePath, ex);
- JOptionPane.showMessageDialog(this, "Failed to import selected database.\nPlease verify that the selected file is a hash database.");
+ catch (HashDatabaseDoesNotExistException | DuplicateHashSetNameException | HashDatabaseAlreadyAddedException ex) {
+ Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex);
+ JOptionPane.showMessageDialog(this, ex.getMessage(), "Import Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
- }
+ }
+ catch (TskCoreException ex) {
+ Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.SEVERE, errorMessage, ex);
+ JOptionPane.showMessageDialog(this, errorMessage, "Import Hash Database Error", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
- this.dispose();
+ dispose();
}//GEN-LAST:event_okButtonActionPerformed
- private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed
- }//GEN-LAST:event_useForIngestCheckboxActionPerformed
+ private void searchDuringIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchDuringIngestCheckboxActionPerformed
+ sendIngestMessagesCheckbox.setEnabled(searchDuringIngestCheckbox.isSelected());
+ if (!searchDuringIngestCheckbox.isSelected()) {
+ sendIngestMessagesCheckbox.setSelected(false);
+ }
+ }//GEN-LAST:event_searchDuringIngestCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
- private javax.swing.JButton browseButton;
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JButton cancelButton;
- private javax.swing.JTextField databaseNameTextField;
private javax.swing.JTextField databasePathTextField;
+ private javax.swing.JTextField hashSetNameTextField;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
+ private javax.swing.JLabel jLabel3;
private javax.swing.JRadioButton knownBadRadioButton;
private javax.swing.JRadioButton knownRadioButton;
private javax.swing.JButton okButton;
- private javax.swing.JCheckBox sendInboxMessagesCheckbox;
- private javax.swing.JCheckBox useForIngestCheckbox;
+ private javax.swing.JButton openButton;
+ private javax.swing.JCheckBox searchDuringIngestCheckbox;
+ private javax.swing.JCheckBox sendIngestMessagesCheckbox;
// End of variables declaration//GEN-END:variables
}
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java
index c3e2340a51..8e0967daf9 100644
--- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java
+++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java
@@ -42,6 +42,7 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskException;
+import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
public class HashDbIngestModule extends IngestModuleAbstractFile {
private static HashDbIngestModule instance = null;
@@ -138,9 +139,9 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
skCase = Case.getCurrentCase().getSleuthkitCase();
HashDbManager hashDbManager = HashDbManager.getInstance();
- getHashSetsUsableForIngest(hashDbManager.getKnownBadHashSets(), knownBadHashSets);
- getHashSetsUsableForIngest(hashDbManager.getKnownHashSets(), knownHashSets);
- calcHashesIsSet = hashDbManager.shouldAlwaysCalculateHashes();
+ getHashSetsUsableForIngest(hashDbManager.getKnownBadFileHashSets(), knownBadHashSets);
+ getHashSetsUsableForIngest(hashDbManager.getKnownFileHashSets(), knownHashSets);
+ calcHashesIsSet = hashDbManager.getAlwaysCalculateHashes();
if (knownHashSets.isEmpty()) {
services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No known hash database set", "Known file search will not be executed."));
@@ -155,14 +156,14 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
assert hashDbsForIngest != null;
hashDbsForIngest.clear();
for (HashDb db : hashDbs) {
- if (db.getUseForIngest()) {
+ if (db.getSearchDuringIngest()) {
try {
if (db.hasLookupIndex()) {
hashDbsForIngest.add(db);
}
}
catch (TskCoreException ex) {
- logger.log(Level.WARNING, "Error get index status for hash database at " +db.getDatabasePath(), ex);
+ logger.log(Level.WARNING, "Error getting index status for " + db.getHashSetName() +" hash database", ex);
}
}
}
@@ -206,14 +207,24 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
}
// look up in known bad first
- TskData.FileKnown status = TskData.FileKnown.UNKNOWN;
boolean foundBad = false;
ProcessResult ret = ProcessResult.OK;
for (HashDb db : knownBadHashSets) {
try {
long lookupstart = System.currentTimeMillis();
- if (db.lookUp(file)) {
- status = TskData.FileKnown.BAD;
+ if (db.hasMd5HashOf(file)) {
+ foundBad = true;
+ knownBadCount += 1;
+ try {
+ skCase.setKnown(file, TskData.FileKnown.BAD);
+ } 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, "Hash Lookup Error: " + name,
+ "Error encountered while setting known bad state for " + name + "."));
+ ret = ProcessResult.ERROR;
+ }
+ String hashSetName = db.getHashSetName();
+ postHashSetHitToBlackboard(file, md5Hash, hashSetName, db.getSendIngestMessages());
}
lookuptime += (System.currentTimeMillis() - lookupstart);
} catch (TskException ex) {
@@ -222,21 +233,6 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
"Error encountered while looking up known bad hash value for " + name + "."));
ret = ProcessResult.ERROR;
}
-
- if (status.equals(TskData.FileKnown.BAD)) {
- foundBad = true;
- knownBadCount += 1;
- try {
- skCase.setKnown(file, TskData.FileKnown.BAD);
- } 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, "Hash Lookup Error: " + name,
- "Error encountered while setting known bad state for " + name + "."));
- ret = ProcessResult.ERROR;
- }
- String hashSetName = db.getHashSetName();
- processBadFile(file, md5Hash, hashSetName, db.getShowInboxMessages());
- }
}
// If the file is not in the known bad sets, search for it in the known sets.
@@ -246,8 +242,16 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
for (HashDb db : knownHashSets) {
try {
long lookupstart = System.currentTimeMillis();
- if (db.lookUp(file)) {
- status = TskData.FileKnown.KNOWN;
+ if (db.hasMd5HashOf(file)) {
+ try {
+ skCase.setKnown(file, TskData.FileKnown.KNOWN);
+ 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, "Hash Lookup Error: " + name,
+ "Error encountered while setting known state for " + name + "."));
+ ret = ProcessResult.ERROR;
+ }
}
lookuptime += (System.currentTimeMillis() - lookupstart);
} catch (TskException ex) {
@@ -256,25 +260,13 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
"Error encountered while looking up known hash value for " + name + "."));
ret = ProcessResult.ERROR;
}
-
- if (status.equals(TskData.FileKnown.KNOWN)) {
- try {
- skCase.setKnown(file, TskData.FileKnown.KNOWN);
- 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, "Hash Lookup Error: " + name,
- "Error encountered while setting known state for " + name + "."));
- ret = ProcessResult.ERROR;
- }
- }
}
}
return ret;
}
- private void processBadFile(AbstractFile abstractFile, String md5Hash, String hashSetName, boolean showInboxMessage) {
+ private void postHashSetHitToBlackboard(AbstractFile abstractFile, String md5Hash, String hashSetName, boolean showInboxMessage) {
try {
BlackboardArtifact badFile = abstractFile.newArtifact(ARTIFACT_TYPE.TSK_HASHSET_HIT);
//TODO Revisit usage of deprecated constructor as per TSK-583
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java
old mode 100644
new mode 100755
index 687903e96b..f5abf778e4
--- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java
+++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java
@@ -16,53 +16,69 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.sleuthkit.autopsy.hashdatabase;
+import java.beans.PropertyChangeEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
-import java.util.logging.Level;
+import java.util.Set;
import javax.swing.JFileChooser;
-import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
-import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.XMLUtil;
-import org.sleuthkit.autopsy.hashdatabase.HashDb.KnownFilesType;
-import org.sleuthkit.datamodel.TskCoreException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.logging.Level;
+import javax.swing.JOptionPane;
+import javax.swing.SwingWorker;
+import org.apache.commons.io.FilenameUtils;
+import org.netbeans.api.progress.ProgressHandle;
+import org.netbeans.api.progress.ProgressHandleFactory;
+import org.sleuthkit.autopsy.coreutils.Logger;
+import org.sleuthkit.datamodel.AbstractFile;
+import org.sleuthkit.datamodel.Content;
+import org.sleuthkit.datamodel.HashInfo;
+import org.sleuthkit.datamodel.SleuthkitJNI;
+import org.sleuthkit.datamodel.TskCoreException;
/**
- * This class is a singleton that manages the set of hash databases
- * used to classify files as known or known bad.
+ * This class implements a singleton that manages the set of hash databases
+ * used to classify files as unknown, known or known bad.
*/
-public class HashDbManager {
- private static final String ROOT_EL = "hash_sets";
- private static final String SET_EL = "hash_set";
- private static final String SET_NAME_ATTR = "name";
- private static final String SET_TYPE_ATTR = "type";
- private static final String SET_USE_FOR_INGEST_ATTR = "use_for_ingest";
- private static final String SET_SHOW_INBOX_MESSAGES = "show_inbox_messages";
- private static final String PATH_EL = "hash_set_path";
- private static final String CUR_HASHSETS_FILE_NAME = "hashsets.xml";
- private static final String XSDFILE = "HashsetsSchema.xsd";
+public class HashDbManager implements PropertyChangeListener {
+
+ private static final String ROOT_ELEMENT = "hash_sets";
+ private static final String SET_ELEMENT = "hash_set";
+ private static final String SET_NAME_ATTRIBUTE = "name";
+ private static final String SET_TYPE_ATTRIBUTE = "type";
+ private static final String SEARCH_DURING_INGEST_ATTRIBUTE = "use_for_ingest";
+ private static final String SEND_INGEST_MESSAGES_ATTRIBUTE = "show_inbox_messages";
+ private static final String PATH_ELEMENT = "hash_set_path";
+ private static final String CONFIG_FILE_NAME = "hashsets.xml";
+ private static final String XSD_FILE_NAME = "HashsetsSchema.xsd";
private static final String ENCODING = "UTF-8";
- private static final String SET_CALC = "hash_calculate";
- private static final String SET_VALUE = "value";
- private static final Logger logger = Logger.getLogger(HashDbManager.class.getName());
- private static HashDbManager instance;
- private String xmlFilePath = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME;
+ private static final String ALWAYS_CALCULATE_HASHES_ELEMENT = "hash_calculate";
+ private static final String VALUE_ATTRIBUTE = "value";
+ private static final String HASH_DATABASE_FILE_EXTENSON = "kdb";
+ private static final String LEGACY_INDEX_FILE_EXTENSION = "-md5.idx";
+ private static HashDbManager instance = null;
+ private final String configFilePath = PlatformUtil.getUserConfigDirectory() + File.separator + CONFIG_FILE_NAME;
private List knownHashSets = new ArrayList<>();
private List knownBadHashSets = new ArrayList<>();
- private boolean alwaysCalculateHashes;
-
+ private Set hashSetNames = new HashSet<>();
+ private Set hashSetPaths = new HashSet<>();
+ private boolean alwaysCalculateHashes = false;
+
/**
* Gets the singleton instance of this class.
*/
@@ -78,73 +94,238 @@ public class HashDbManager {
readHashSetsConfigurationFromDisk();
}
}
-
+
/**
- * Adds a hash database to the configuration. Does not check for duplication
- * of hash set names and does not save the configuration - the configuration
- * is only saved on demand to support cancellation of configuration panels.
+ * Gets the extension, without the dot separator, that the SleuthKit requires
+ * for the hash database files that combine a database and an index and can
+ * therefore be updated.
*/
- public void addHashSet(HashDb hashDb) {
+ static String getHashDatabaseFileExtension() {
+ return HASH_DATABASE_FILE_EXTENSON;
+ }
+
+ class DuplicateHashSetNameException extends Exception {
+ private DuplicateHashSetNameException(String hashSetName) {
+ super("The hash set name '"+ hashSetName +"' has already been used for another hash database.");
+ }
+ }
+
+ class HashDatabaseDoesNotExistException extends Exception {
+ private HashDatabaseDoesNotExistException(String path) {
+ super("No hash database found at\n" + path);
+ }
+ }
+
+ class HashDatabaseFileAlreadyExistsException extends Exception {
+ private HashDatabaseFileAlreadyExistsException(String path) {
+ super("A file already exists at\n" + path);
+ }
+ }
+
+ class HashDatabaseAlreadyAddedException extends Exception {
+ private HashDatabaseAlreadyAddedException(String path) {
+ super("The hash database at\n" + path + "\nhas already been created or imported.");
+ }
+ }
+
+ class IllegalHashDatabaseFileNameExtensionException extends Exception {
+ private IllegalHashDatabaseFileNameExtensionException() {
+ super("The hash database file name must have a ." + getHashDatabaseFileExtension() + " extension.");
+ }
+ }
+
+ /**
+ * Adds an existing hash database to the set of hash databases used to classify files as known or known bad.
+ * Does not save the configuration - the configuration is only saved on demand to support cancellation of
+ * configuration panels.
+ * @param hashSetName Name used to represent the hash database in user interface components.
+ * @param path Full path to either a hash database file or a hash database index file.
+ * @param searchDuringIngest A flag indicating whether or not the hash database should be searched during ingest.
+ * @param sendIngestMessages A flag indicating whether hash set hit messages should be sent as ingest messages.
+ * @param knownFilesType The classification to apply to files whose hashes are found in the hash database.
+ * @return A HashDb representing the hash database.
+ * @throws HashDatabaseDoesNotExistException, DuplicateHashSetNameException, HashDatabaseAlreadyAddedException, TskCoreException
+ */
+ synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDatabaseDoesNotExistException, DuplicateHashSetNameException, HashDatabaseAlreadyAddedException, TskCoreException {
+ if (!new File(path).exists()) {
+ throw new HashDatabaseDoesNotExistException(path);
+ }
+
+ if (hashSetPaths.contains(path)) {
+ throw new HashDatabaseAlreadyAddedException(path);
+ }
+
+ if (hashSetNames.contains(hashSetName)) {
+ throw new DuplicateHashSetNameException(hashSetName);
+ }
+
+ return addHashDatabase(SleuthkitJNI.openHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
+ }
+
+ /**
+ * Adds a new hash database to the set of hash databases used to classify files as known or known bad.
+ * Does not save the configuration - the configuration is only saved on demand to support cancellation of
+ * configuration panels.
+ * @param hashSetName Hash set name used to represent the hash database in user interface components.
+ * @param path Full path to the database file to be created.
+ * @param searchDuringIngest A flag indicating whether or not the hash database should be searched during ingest.
+ * @param sendIngestMessages A flag indicating whether hash set hit messages should be sent as ingest messages.
+ * @param knownFilesType The classification to apply to files whose hashes are found in the hash database.
+ * @return A HashDb representing the hash database.
+ * @throws TskCoreException
+ */
+ synchronized HashDb addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDatabaseFileAlreadyExistsException, IllegalHashDatabaseFileNameExtensionException, DuplicateHashSetNameException, HashDatabaseAlreadyAddedException, TskCoreException {
+ File file = new File(path);
+ if (file.exists()) {
+ throw new HashDatabaseFileAlreadyExistsException(path);
+ }
+ if (!FilenameUtils.getExtension(file.getName()).equalsIgnoreCase(HASH_DATABASE_FILE_EXTENSON)) {
+ throw new IllegalHashDatabaseFileNameExtensionException();
+ }
+
+ if (hashSetPaths.contains(path)) {
+ throw new HashDatabaseAlreadyAddedException(path);
+ }
+
+ if (hashSetNames.contains(hashSetName)) {
+ throw new DuplicateHashSetNameException(hashSetName);
+ }
+
+ return addHashDatabase(SleuthkitJNI.createHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
+ }
+
+ private HashDb addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws TskCoreException {
+ // Wrap an object around the handle.
+ HashDb hashDb = new HashDb(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
+
+ // Get the indentity data before updating the collections since the
+ // accessor methods may throw.
+ String databasePath = hashDb.getDatabasePath();
+ String indexPath = hashDb.getIndexPath();
+
+ // Update the collections used to ensure that hash set names are unique
+ // and the same database is not added to the configuration more than once.
+ hashSetNames.add(hashDb.getHashSetName());
+ if (!databasePath.equals("None")) {
+ hashSetPaths.add(databasePath);
+ }
+ if (!indexPath.equals("None")) {
+ hashSetPaths.add(indexPath);
+ }
+
+ // Add the hash database to the appropriate collection for its type.
if (hashDb.getKnownFilesType() == HashDb.KnownFilesType.KNOWN) {
knownHashSets.add(hashDb);
}
else {
knownBadHashSets.add(hashDb);
- }
+ }
+
+ return hashDb;
+ }
+
+ synchronized void indexHashDatabase(HashDb hashDb, boolean deleteIndexFile) {
+ hashDb.addPropertyChangeListener(this);
+ HashDbIndexer creator = new HashDbIndexer(hashDb, deleteIndexFile);
+ creator.execute();
}
+ @Override
+ public void propertyChange(PropertyChangeEvent event) {
+ if (event.getPropertyName().equals(HashDb.Event.INDEXING_DONE.name())) {
+ HashDb hashDb = (HashDb)event.getNewValue();
+ if (null != hashDb) {
+ try {
+ String indexPath = hashDb.getIndexPath();
+ if (!indexPath.equals("None")) {
+ hashSetPaths.add(indexPath);
+ }
+ }
+ catch (TskCoreException ex) {
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDb.getHashSetName() + " hash database after indexing", ex);
+ }
+ }
+ }
+ }
+
/**
- * Removes a hash database from the configuration. Does not save the
- * configuration - the configuration is only saved on demand to support
- * cancellation of configuration panels.
+ * Removes a hash database from the set of hash databases used to classify
+ * files as known or known bad. Does not save the configuration - the
+ * configuration is only saved on demand to support cancellation of
+ * configuration panels.
+ * @throws TskCoreException
*/
- public void removeHashSet(HashDb hashDb) {
- try {
- hashDb.close();
- }
- catch (TskCoreException ex) {
- logger.log(Level.SEVERE, "Error closing hash database at " + hashDb.getDatabasePath(), ex);
- }
+ synchronized void removeHashDatabase(HashDb hashDb) {
+ // Remove the database from whichever hash set list it occupies,
+ // and remove its hash set name from the hash set used to ensure unique
+ // hash set names are used, before undertaking These operations will succeed and constitute
+ // a mostly effective removal, even if the subsequent operations fail.
knownHashSets.remove(hashDb);
knownBadHashSets.remove(hashDb);
+ hashSetNames.remove(hashDb.getHashSetName());
+
+ // Now undertake the operations that could throw.
+ try {
+ hashSetPaths.remove(hashDb.getIndexPath());
+ }
+ catch (TskCoreException ex) {
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDb.getHashSetName() + " hash database when removing the database", ex);
+ }
+ try {
+ if (!hashDb.hasIndexOnly()) {
+ hashSetPaths.remove(hashDb.getDatabasePath());
+ }
+ }
+ catch (TskCoreException ex) {
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting database path of " + hashDb.getHashSetName() + " hash database when removing the database", ex);
+ }
+ try {
+ hashDb.close();
+ }
+ catch (TskCoreException ex) {
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + hashDb.getHashSetName() + " hash database when removing the database", ex);
+ }
}
/**
- * Gets all of the configured hash sets.
- * @return A list, possibly empty, of HashDb objects representing the hash
- * sets.
+ * Gets all of the hash databases used to classify files as known or known bad.
+ * @return A list, possibly empty, of hash databases.
*/
- public List getAllHashSets() {
+ public synchronized List getAllHashSets() {
List hashDbs = new ArrayList<>();
hashDbs.addAll(knownHashSets);
hashDbs.addAll(knownBadHashSets);
- return Collections.unmodifiableList(hashDbs);
+ return hashDbs;
}
/**
- * Gets the configured known files hash sets.
- * @return A list, possibly empty, of HashDb objects.
+ * Gets all of the hash databases used to classify files as known.
+ * @return A list, possibly empty, of hash databases.
*/
- public List getKnownHashSets() {
- return Collections.unmodifiableList(knownHashSets);
+ public synchronized List getKnownFileHashSets() {
+ List hashDbs = new ArrayList<>();
+ hashDbs.addAll(knownHashSets);
+ return hashDbs;
}
/**
- * Gets the configured known bad files hash sets.
- * @return A list, possibly empty, of HashDb objects.
+ * Gets all of the hash databases used to classify files as known bad.
+ * @return A list, possibly empty, of hash databases.
*/
- public List getKnownBadHashSets() {
- return Collections.unmodifiableList(knownBadHashSets);
+ public synchronized List getKnownBadFileHashSets() {
+ List hashDbs = new ArrayList<>();
+ hashDbs.addAll(knownBadHashSets);
+ return hashDbs;
}
-
- /**
- * Gets all of the configured hash sets that accept updates.
- * @return A list, possibly empty, of HashDb objects.
+
+ /**
+ * Gets all of the hash databases that accept updates.
+ * @return A list, possibly empty, of hash databases.
*/
- public List getUpdateableHashSets() {
+ public synchronized List getUpdateableHashSets() {
List updateableDbs = getUpdateableHashSets(knownHashSets);
updateableDbs.addAll(getUpdateableHashSets(knownBadHashSets));
- return Collections.unmodifiableList(updateableDbs);
+ return updateableDbs;
}
private List getUpdateableHashSets(List hashDbs) {
@@ -156,25 +337,25 @@ public class HashDbManager {
}
}
catch (TskCoreException ex) {
- logger.log(Level.SEVERE, "Error checking updateable status of hash database at " + db.getDatabasePath(), ex);
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error checking updateable status of " + db.getHashSetName() + " hash database", ex);
}
}
return updateableDbs;
- }
+ }
/**
* Sets the value for the flag that indicates whether hashes should be calculated
* for content even if no hash databases are configured.
*/
- public void alwaysCalculateHashes(boolean alwaysCalculateHashes) {
+ synchronized void setAlwaysCalculateHashes(boolean alwaysCalculateHashes) {
this.alwaysCalculateHashes = alwaysCalculateHashes;
}
/**
- * Accesses the flag that indicates whether hashes should be calculated
+ * Gets the flag that indicates whether hashes should be calculated
* for content even if no hash databases are configured.
*/
- public boolean shouldAlwaysCalculateHashes() {
+ synchronized boolean getAlwaysCalculateHashes() {
return alwaysCalculateHashes;
}
@@ -183,7 +364,7 @@ public class HashDbManager {
* saved on demand to support cancellation of configuration panels.
* @return True on success, false otherwise.
*/
- public boolean save() {
+ public synchronized boolean save() {
return writeHashSetConfigurationToDisk();
}
@@ -191,67 +372,59 @@ public class HashDbManager {
* Restores the last saved hash sets configuration. This supports
* cancellation of configuration panels.
*/
- public void loadLastSavedConfiguration() {
+ public synchronized void loadLastSavedConfiguration() {
closeHashDatabases(knownHashSets);
closeHashDatabases(knownBadHashSets);
+ hashSetNames.clear();
+ hashSetPaths.clear();
if (hashSetsConfigurationFileExists()) {
readHashSetsConfigurationFromDisk();
}
}
- private void closeHashDatabases(List hashDbs) {
- String dbPath = "";
- try {
- for (HashDb db : hashDbs) {
- dbPath = db.getDatabasePath();
- db.close();
+ private void closeHashDatabases(List hashDatabases) {
+ for (HashDb database : hashDatabases) {
+ try {
+ database.close();
+ }
+ catch (TskCoreException ex) {
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + database.getHashSetName() + " hash database", ex);
}
}
- catch (TskCoreException ex) {
- logger.log(Level.SEVERE, "Error closing hash database at " + dbPath, ex);
- }
- hashDbs.clear();
+ hashDatabases.clear();
}
- private boolean hashSetsConfigurationFileExists() {
- File f = new File(xmlFilePath);
- return f.exists() && f.canRead() && f.canWrite();
- }
-
private boolean writeHashSetConfigurationToDisk() {
boolean success = false;
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
Document doc = docBuilder.newDocument();
- Element rootEl = doc.createElement(ROOT_EL);
+ Element rootEl = doc.createElement(ROOT_ELEMENT);
doc.appendChild(rootEl);
writeHashDbsToDisk(doc, rootEl, knownHashSets);
writeHashDbsToDisk(doc, rootEl, knownBadHashSets);
String calcValue = Boolean.toString(alwaysCalculateHashes);
- Element setCalc = doc.createElement(SET_CALC);
- setCalc.setAttribute(SET_VALUE, calcValue);
+ Element setCalc = doc.createElement(ALWAYS_CALCULATE_HASHES_ELEMENT);
+ setCalc.setAttribute(VALUE_ATTRIBUTE, calcValue);
rootEl.appendChild(setCalc);
- success = XMLUtil.saveDoc(HashDbManager.class, xmlFilePath, ENCODING, doc);
+ success = XMLUtil.saveDoc(HashDbManager.class, configFilePath, ENCODING, doc);
}
- catch (ParserConfigurationException e) {
- logger.log(Level.SEVERE, "Error saving hash databases", e);
+ catch (ParserConfigurationException ex) {
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error saving hash databases", ex);
}
return success;
}
private static void writeHashDbsToDisk(Document doc, Element rootEl, List hashDbs) {
for (HashDb db : hashDbs) {
- Element setEl = doc.createElement(SET_EL);
- setEl.setAttribute(SET_NAME_ATTR, db.getHashSetName());
- setEl.setAttribute(SET_TYPE_ATTR, db.getKnownFilesType().toString());
- setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, Boolean.toString(db.getUseForIngest()));
- setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, Boolean.toString(db.getShowInboxMessages()));
- String path = null;
+ // Get the path for the hash database before writing anything, in
+ // case an exception is thrown.
+ String path;
try {
if (db.hasIndexOnly()) {
path = db.getIndexPath();
@@ -259,102 +432,176 @@ public class HashDbManager {
else {
path = db.getDatabasePath();
}
- Element pathEl = doc.createElement(PATH_EL);
- pathEl.setTextContent(path);
- setEl.appendChild(pathEl);
- rootEl.appendChild(setEl);
}
catch (TskCoreException ex) {
- logger.log(Level.SEVERE, "Error getting path of hash database " + db.getHashSetName() + ", unable to save configuration", ex);
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting path of hash database " + db.getHashSetName() + ", discarding from hash database configuration", ex);
+ continue;
}
+
+ Element setElement = doc.createElement(SET_ELEMENT);
+ setElement.setAttribute(SET_NAME_ATTRIBUTE, db.getHashSetName());
+ setElement.setAttribute(SET_TYPE_ATTRIBUTE, db.getKnownFilesType().toString());
+ setElement.setAttribute(SEARCH_DURING_INGEST_ATTRIBUTE, Boolean.toString(db.getSearchDuringIngest()));
+ setElement.setAttribute(SEND_INGEST_MESSAGES_ATTRIBUTE, Boolean.toString(db.getSendIngestMessages()));
+ Element pathElement = doc.createElement(PATH_ELEMENT);
+ pathElement.setTextContent(path);
+ setElement.appendChild(pathElement);
+ rootEl.appendChild(setElement);
}
}
- // TODO: The return value from this function is never checked. Failure is not indicated to the user. Is this desired?
+ private boolean hashSetsConfigurationFileExists() {
+ File f = new File(configFilePath);
+ return f.exists() && f.canRead() && f.canWrite();
+ }
+
private boolean readHashSetsConfigurationFromDisk() {
- final Document doc = XMLUtil.loadDoc(HashDbManager.class, xmlFilePath, XSDFILE);
+ // Open the XML document that implements the configuration file.
+ final Document doc = XMLUtil.loadDoc(HashDbManager.class, configFilePath, XSD_FILE_NAME);
if (doc == null) {
return false;
}
+ // Get the root element.
Element root = doc.getDocumentElement();
if (root == null) {
- logger.log(Level.SEVERE, "Error loading hash sets: invalid file format.");
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading hash sets: invalid file format.");
return false;
}
- NodeList setsNList = root.getElementsByTagName(SET_EL);
+ // Get the hash set elements.
+ NodeList setsNList = root.getElementsByTagName(SET_ELEMENT);
int numSets = setsNList.getLength();
if(numSets == 0) {
- logger.log(Level.WARNING, "No element hash_set exists.");
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, "No element hash_set exists.");
}
+ // Create HashDb objects for each hash set element. Skip to the next hash database if the definition of
+ // a particular hash database is not well-formed.
+ String attributeErrorMessage = " attribute was not set for hash_set at index {0}, cannot make instance of HashDb class";
+ String elementErrorMessage = " element was not set for hash_set at index {0}, cannot make instance of HashDb class";
for (int i = 0; i < numSets; ++i) {
Element setEl = (Element) setsNList.item(i);
- final String name = setEl.getAttribute(SET_NAME_ATTR);
- final String type = setEl.getAttribute(SET_TYPE_ATTR);
- final String useForIngest = setEl.getAttribute(SET_USE_FOR_INGEST_ATTR);
- final String showInboxMessages = setEl.getAttribute(SET_SHOW_INBOX_MESSAGES);
- Boolean useForIngestBool = Boolean.parseBoolean(useForIngest);
- Boolean showInboxMessagesBool = Boolean.parseBoolean(showInboxMessages);
-
- String path = null;
- NodeList pathsNList = setEl.getElementsByTagName(PATH_EL);
- if (pathsNList.getLength() > 0) {
- // Shouldn't be more than 1
- Element pathEl = (Element) pathsNList.item(0);
- path = pathEl.getTextContent();
- File database = new File(path);
- if(!database.exists() && JOptionPane.showConfirmDialog(null, "Database " + name + " could not be found at location\n" + path + "\nWould you like to search for the file?", "Missing Database", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
- path = searchForFile();
+
+ String hashSetName = setEl.getAttribute(SET_NAME_ATTRIBUTE);
+ if (hashSetName.isEmpty()) {
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, SET_NAME_ATTRIBUTE + attributeErrorMessage, i);
+ continue;
+ }
+
+ // Handle configurations saved before duplicate hash set names were not permitted.
+ if (hashSetNames.contains(hashSetName)) {
+ int suffix = 0;
+ String newHashSetName;
+ do {
+ ++suffix;
+ newHashSetName = hashSetName + suffix;
}
+ while (hashSetNames.contains(newHashSetName));
+ JOptionPane.showMessageDialog(null, "Duplicate hash set name " + hashSetName + " found.\nReplacing with " + newHashSetName + ".", "Open Hash Database Error", JOptionPane.ERROR_MESSAGE);
+ hashSetName = newHashSetName;
+ }
+
+ String knownFilesType = setEl.getAttribute(SET_TYPE_ATTRIBUTE);
+ if(knownFilesType.isEmpty()) {
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, SET_TYPE_ATTRIBUTE + attributeErrorMessage, i);
+ continue;
}
- if(name.isEmpty()) {
- logger.log(Level.WARNING, "Name was not set for hash_set at index {0}.", i);
- }
+ // Handle legacy known files types.
+ if (knownFilesType.equals("NSRL")) {
+ knownFilesType = HashDb.KnownFilesType.KNOWN.toString();
+ }
- if(type.isEmpty()) {
- logger.log(Level.SEVERE, "Type was not set for hash_set at index {0}, cannot make instance of HashDb class.", i);
- return false;
+ final String searchDuringIngest = setEl.getAttribute(SEARCH_DURING_INGEST_ATTRIBUTE);
+ if (searchDuringIngest.isEmpty()) {
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, SEARCH_DURING_INGEST_ATTRIBUTE + attributeErrorMessage, i);
+ continue;
}
-
- if(useForIngest.isEmpty()) {
- logger.log(Level.WARNING, "UseForIngest was not set for hash_set at index {0}.", i);
+ Boolean seearchDuringIngestFlag = Boolean.parseBoolean(searchDuringIngest);
+
+ final String sendIngestMessages = setEl.getAttribute(SEND_INGEST_MESSAGES_ATTRIBUTE);
+ if (searchDuringIngest.isEmpty()) {
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, SEND_INGEST_MESSAGES_ATTRIBUTE + attributeErrorMessage, i);
+ continue;
}
-
- if(showInboxMessages.isEmpty()) {
- logger.log(Level.WARNING, "ShowInboxMessages was not set for hash_set at index {0}.", i);
+ Boolean sendIngestMessagesFlag = Boolean.parseBoolean(sendIngestMessages);
+
+ String dbPath;
+ NodeList pathsNList = setEl.getElementsByTagName(PATH_ELEMENT);
+ if (pathsNList.getLength() > 0) {
+ Element pathEl = (Element) pathsNList.item(0); // Shouldn't be more than one.
+ dbPath = pathEl.getTextContent();
+ if (dbPath.isEmpty()) {
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, PATH_ELEMENT + elementErrorMessage, i);
+ continue;
+ }
}
-
- if(path == null) {
- logger.log(Level.WARNING, "No path for hash_set at index {0}, cannot make instance of HashDb class.", i);
+ else {
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, PATH_ELEMENT + elementErrorMessage, i);
+ continue;
+ }
+ dbPath = getValidFilePath(hashSetName, dbPath);
+
+ if (null != dbPath) {
+ try {
+ addExistingHashDatabase(hashSetName, dbPath, seearchDuringIngestFlag, sendIngestMessagesFlag, HashDb.KnownFilesType.valueOf(knownFilesType));
+ }
+ catch (HashDatabaseDoesNotExistException | DuplicateHashSetNameException | HashDatabaseAlreadyAddedException | TskCoreException ex) {
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash database", ex);
+ JOptionPane.showMessageDialog(null, "Unable to open " + dbPath + " hash database.", "Open Hash Database Error", JOptionPane.ERROR_MESSAGE);
+ }
}
else {
- try {
- addHashSet(HashDb.openHashDatabase(name, path, useForIngestBool, showInboxMessagesBool, KnownFilesType.valueOf(type)));
- }
- catch (TskCoreException ex) {
- Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash database", ex);
- JOptionPane.showMessageDialog(null, "Unable to open " + path + " hash database.", "Open Hash Database Error", JOptionPane.ERROR_MESSAGE);
- }
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, "No valid path for hash_set at index {0}, cannot make instance of HashDb class", i);
}
}
- NodeList calcList = root.getElementsByTagName(SET_CALC);
+ // Get the element that stores the always calculate hashes flag.
+ NodeList calcList = root.getElementsByTagName(ALWAYS_CALCULATE_HASHES_ELEMENT);
if (calcList.getLength() > 0) {
- Element calcEl = (Element) calcList.item(0); // Shouldn't be more than 1
- final String value = calcEl.getAttribute(SET_VALUE);
+ Element calcEl = (Element) calcList.item(0); // Shouldn't be more than one.
+ final String value = calcEl.getAttribute(VALUE_ATTRIBUTE);
alwaysCalculateHashes = Boolean.parseBoolean(value);
}
else {
- logger.log(Level.WARNING, "No element hash_calculate exists.");
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, " element ");
+ alwaysCalculateHashes = false;
}
return true;
}
+
+ private String getValidFilePath(String hashSetName, String configuredPath) {
+ // Check the configured path.
+ File database = new File(configuredPath);
+ if (database.exists()) {
+ return configuredPath;
+ }
+
+ // Try a path that could be in an older version of the configuration file.
+ String legacyPath = configuredPath + LEGACY_INDEX_FILE_EXTENSION;
+ database = new File(legacyPath);
+ if (database.exists()) {
+ return legacyPath;
+ }
+
+ // Give the user an opportunity to find the desired file.
+ String newPath = null;
+ if (JOptionPane.showConfirmDialog(null, "Database " + hashSetName + " could not be found at location\n" + configuredPath + "\nWould you like to search for the file?", "Missing Database", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
+ newPath = searchForFile();
+ if (null != newPath && !newPath.isEmpty()) {
+ database = new File(newPath);
+ if (!database.exists()) {
+ newPath = null;
+ }
+ }
+ }
+ return newPath;
+ }
private String searchForFile() {
+ String filePath = null;
JFileChooser fc = new JFileChooser();
fc.setDragEnabled(false);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
@@ -362,18 +609,223 @@ public class HashDbManager {
FileNameExtensionFilter filter = new FileNameExtensionFilter("Hash Database File", EXTENSION);
fc.setFileFilter(filter);
fc.setMultiSelectionEnabled(false);
-
- String filePath = null;
if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
File f = fc.getSelectedFile();
try {
filePath = f.getCanonicalPath();
}
catch (IOException ex) {
- logger.log(Level.WARNING, "Couldn't get selected file path", ex);
+ Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, "Couldn't get selected file path", ex);
}
- }
-
+ }
return filePath;
}
+
+ /**
+ * Instances of this class represent hash databases used to classify files as known or know bad.
+ */
+ public static class HashDb {
+
+ /**
+ * Indicates how files with hashes stored in a particular hash database
+ * object should be classified.
+ */
+ public enum KnownFilesType{
+ KNOWN("Known"),
+ KNOWN_BAD("Known Bad");
+
+ private String displayName;
+
+ private KnownFilesType(String displayName) {
+ this.displayName = displayName;
+ }
+
+ public String getDisplayName() {
+ return this.displayName;
+ }
+ }
+
+ /**
+ * Property change events published by hash database objects.
+ */
+ public enum Event {
+ INDEXING_DONE
+ }
+
+ private int handle;
+ private String hashSetName;
+ private boolean searchDuringIngest;
+ private boolean sendIngestMessages;
+ private KnownFilesType knownFilesType;
+ private boolean indexing;
+ private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
+
+ private HashDb(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) {
+ this.handle = handle;
+ this.hashSetName = hashSetName;
+ this.searchDuringIngest = useForIngest;
+ this.sendIngestMessages = sendHitMessages;
+ this.knownFilesType = knownFilesType;
+ this.indexing = false;
+ }
+
+ /**
+ * Adds a listener for the events defined in HashDb.Event.
+ */
+ public void addPropertyChangeListener(PropertyChangeListener pcl) {
+ propertyChangeSupport.addPropertyChangeListener(pcl);
+ }
+
+ /**
+ * Removes a listener for the events defined in HashDb.Event.
+ */
+ public void removePropertyChangeListener(PropertyChangeListener pcl) {
+ propertyChangeSupport.removePropertyChangeListener(pcl);
+ }
+
+ public String getHashSetName() {
+ return hashSetName;
+ }
+
+ public String getDatabasePath() throws TskCoreException {
+ return SleuthkitJNI.getHashDatabasePath(handle);
+ }
+
+ public String getIndexPath() throws TskCoreException {
+ return SleuthkitJNI.getHashDatabaseIndexPath(handle);
+ }
+
+ public KnownFilesType getKnownFilesType() {
+ return knownFilesType;
+ }
+
+ public boolean getSearchDuringIngest() {
+ return searchDuringIngest;
+ }
+
+ void setSearchDuringIngest(boolean useForIngest) {
+ this.searchDuringIngest = useForIngest;
+ }
+
+ public boolean getSendIngestMessages() {
+ return sendIngestMessages;
+ }
+
+ void setSendIngestMessages(boolean showInboxMessages) {
+ this.sendIngestMessages = showInboxMessages;
+ }
+
+ /**
+ * Indicates whether the hash database accepts updates.
+ * @return True if the database accepts updates, false otherwise.
+ */
+ public boolean isUpdateable() throws TskCoreException {
+ return SleuthkitJNI.isUpdateableHashDatabase(this.handle);
+ }
+
+ /**
+ * Adds hashes of content (if calculated) to the hash database.
+ * @param content The content for which the calculated hashes, if any, are to be added to the hash database.
+ * @throws TskCoreException
+ */
+ public void addHashes(Content content) throws TskCoreException {
+ addHashes(content, null);
+ }
+
+ /**
+ * Adds hashes of content (if calculated) to the hash database.
+ * @param content The content for which the calculated hashes, if any, are to be added to the hash database.
+ * @param comment A comment to associate with the hashes, e.g., the name of the case in which the content was encountered.
+ * @throws TskCoreException
+ */
+ public void addHashes(Content content, String comment) throws TskCoreException {
+ // TODO: This only works for AbstractFiles and MD5 hashes at present.
+ assert content instanceof AbstractFile;
+ if (content instanceof AbstractFile) {
+ AbstractFile file = (AbstractFile)content;
+ if (null != file.getMd5Hash()) {
+ SleuthkitJNI.addToHashDatabase(null, file.getMd5Hash(), null, null, comment, handle);
+ }
+ }
+ }
+
+ public boolean hasMd5HashOf(Content content) throws TskCoreException {
+ boolean result = false;
+ assert content instanceof AbstractFile;
+ if (content instanceof AbstractFile) {
+ AbstractFile file = (AbstractFile)content;
+ if (null != file.getMd5Hash()) {
+ result = SleuthkitJNI.lookupInHashDatabase(file.getMd5Hash(), handle);
+ }
+ }
+ return result;
+ }
+
+ public HashInfo lookUp(Content content) throws TskCoreException {
+ HashInfo result = null;
+ // TODO: This only works for AbstractFiles and MD5 hashes at present.
+ assert content instanceof AbstractFile;
+ if (content instanceof AbstractFile) {
+ AbstractFile file = (AbstractFile)content;
+ if (null != file.getMd5Hash()) {
+ result = SleuthkitJNI.lookupInHashDatabaseVerbose(file.getMd5Hash(), handle);
+ }
+ }
+ return result;
+ }
+
+ boolean hasLookupIndex() throws TskCoreException {
+ return SleuthkitJNI.hashDatabaseHasLookupIndex(handle);
+ }
+
+ boolean hasIndexOnly() throws TskCoreException {
+ return SleuthkitJNI.hashDatabaseHasLegacyLookupIndexOnly(handle);
+ }
+
+ boolean canBeReIndexed() throws TskCoreException {
+ return SleuthkitJNI.hashDatabaseCanBeReindexed(handle);
+ }
+
+ boolean isIndexing() {
+ return indexing;
+ }
+
+ private void close() throws TskCoreException {
+ SleuthkitJNI.closeHashDatabase(handle);
+ }
+ }
+
+ private class HashDbIndexer extends SwingWorker {
+ private ProgressHandle progress = null;
+ private HashDb hashDb = null;
+ private boolean deleteIndexFile = false;
+
+ HashDbIndexer(HashDb hashDb, boolean deleteIndexFile) {
+ this.hashDb = hashDb;
+ this.deleteIndexFile = deleteIndexFile;
+ };
+
+ @Override
+ protected Object doInBackground() {
+ hashDb.indexing = true;
+ progress = ProgressHandleFactory.createHandle("Indexing " + hashDb.hashSetName);
+ progress.start();
+ progress.switchToIndeterminate();
+ try {
+ SleuthkitJNI.createLookupIndexForHashDatabase(hashDb.handle, deleteIndexFile);
+ }
+ catch (TskCoreException ex) {
+ Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error indexing hash database", ex);
+ JOptionPane.showMessageDialog(null, "Error indexing " + hashDb.getHashSetName() + " hash database.", "Hash Database Indexing Error", JOptionPane.ERROR_MESSAGE);
+ }
+ return null;
+ }
+
+ @Override
+ protected void done() {
+ hashDb.indexing = false;
+ progress.finish();
+ hashDb.propertyChangeSupport.firePropertyChange(HashDb.Event.INDEXING_DONE.toString(), null, hashDb);
+ }
+ }
}
\ No newline at end of file
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.form
index f25f5bdc32..75a4788a57 100644
--- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.form
+++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.form
@@ -28,7 +28,7 @@
-
+
@@ -46,7 +46,7 @@
-
+
@@ -92,10 +92,10 @@
-
+
-
+
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java
index bd8388fc62..02cce28f49 100644
--- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java
+++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java
@@ -30,6 +30,7 @@ import javax.swing.table.TableColumn;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.TskCoreException;
+import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
/**
* Instances of this class provide a simplified UI for managing the hash sets configuration.
@@ -39,8 +40,8 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
private HashDbsTableModel knownBadTableModel;
public HashDbSimpleConfigPanel() {
- knownTableModel = new HashDbsTableModel(HashDbManager.getInstance().getKnownHashSets());
- knownBadTableModel = new HashDbsTableModel(HashDbManager.getInstance().getKnownBadHashSets());
+ knownTableModel = new HashDbsTableModel(HashDbManager.getInstance().getKnownFileHashSets());
+ knownBadTableModel = new HashDbsTableModel(HashDbManager.getInstance().getKnownBadFileHashSets());
initComponents();
customizeComponents();
}
@@ -51,10 +52,10 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
// Add a listener to the always calculate hashes checkbox component.
// The listener passes the user's selection on to the hash database manager.
- calcHashesButton.addActionListener( new ActionListener() {
+ alwaysCalcHashesCheckbox.addActionListener( new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- HashDbManager.getInstance().alwaysCalculateHashes(calcHashesButton.isSelected());
+ HashDbManager.getInstance().setAlwaysCalculateHashes(alwaysCalcHashesCheckbox.isSelected());
}
});
@@ -82,33 +83,33 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
public void refreshComponents() {
knownTableModel.refresh();
knownBadTableModel.refresh();
- refreshAlwaysCalcHashesComponents();
+ refreshAlwaysCalcHashesCheckbox();
}
- private void refreshAlwaysCalcHashesComponents() {
+ private void refreshAlwaysCalcHashesCheckbox() {
boolean noHashDbsConfiguredForIngest = true;
for (HashDb hashDb : HashDbManager.getInstance().getAllHashSets()) {
try {
- if (hashDb.getUseForIngest()== true && hashDb.hasLookupIndex()) {
+ if (hashDb.getSearchDuringIngest()== true && hashDb.hasLookupIndex()) {
noHashDbsConfiguredForIngest = false;
break;
}
}
catch (TskCoreException ex) {
- Logger.getLogger(HashDbSimpleConfigPanel.class.getName()).log(Level.SEVERE, "Error getting info for hash database at " + hashDb.getDatabasePath(), ex);
+ Logger.getLogger(HashDbSimpleConfigPanel.class.getName()).log(Level.SEVERE, "Error getting info for " + hashDb.getHashSetName() + " hash database", ex);
}
}
// If there are no hash databases configured for use during file ingest,
// default to always calculating hashes of the files.
if (noHashDbsConfiguredForIngest) {
- calcHashesButton.setEnabled(true);
- calcHashesButton.setSelected(true);
- HashDbManager.getInstance().alwaysCalculateHashes(true);
+ alwaysCalcHashesCheckbox.setEnabled(true);
+ alwaysCalcHashesCheckbox.setSelected(true);
+ HashDbManager.getInstance().setAlwaysCalculateHashes(true);
} else {
- calcHashesButton.setEnabled(false);
- calcHashesButton.setSelected(false);
- HashDbManager.getInstance().alwaysCalculateHashes(false);
+ alwaysCalcHashesCheckbox.setEnabled(false);
+ alwaysCalcHashesCheckbox.setSelected(false);
+ HashDbManager.getInstance().setAlwaysCalculateHashes(false);
}
}
@@ -137,7 +138,7 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
public Object getValueAt(int rowIndex, int columnIndex) {
HashDb db = hashDbs.get(rowIndex);
if (columnIndex == 0) {
- return db.getUseForIngest();
+ return db.getSearchDuringIngest();
} else {
return db.getHashSetName();
}
@@ -157,10 +158,10 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
dbHasIndex = db.hasLookupIndex();
}
catch (TskCoreException ex) {
- Logger.getLogger(HashDbSimpleConfigPanel.class.getName()).log(Level.SEVERE, "Error getting info for hash database at " + db.getDatabasePath(), ex);
+ Logger.getLogger(HashDbSimpleConfigPanel.class.getName()).log(Level.SEVERE, "Error getting info for " + db.getHashSetName() + " hash database", ex);
}
if(((Boolean) getValueAt(rowIndex, columnIndex)) || dbHasIndex) {
- db.setUseForIngest((Boolean) aValue);
+ db.setSearchDuringIngest((Boolean) aValue);
}
else {
JOptionPane.showMessageDialog(HashDbSimpleConfigPanel.this, "Hash databases must be indexed before they can be used for ingest");
@@ -187,7 +188,7 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
knownHashTable = new javax.swing.JTable();
knownBadHashDbsLabel = new javax.swing.JLabel();
knownHashDbsLabel = new javax.swing.JLabel();
- calcHashesButton = new javax.swing.JCheckBox();
+ alwaysCalcHashesCheckbox = new javax.swing.JCheckBox();
jScrollPane2 = new javax.swing.JScrollPane();
knownBadHashTable = new javax.swing.JTable();
@@ -202,7 +203,7 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
knownHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.knownHashDbsLabel.text")); // NOI18N
- calcHashesButton.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.calcHashesButton.text")); // NOI18N
+ alwaysCalcHashesCheckbox.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.alwaysCalcHashesCheckbox.text")); // NOI18N
jScrollPane2.setBorder(javax.swing.BorderFactory.createEtchedBorder());
@@ -233,7 +234,7 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
.addComponent(knownBadHashDbsLabel))
.addGap(0, 0, Short.MAX_VALUE))
.addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
- .addComponent(calcHashesButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addComponent(alwaysCalcHashesCheckbox, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
@@ -248,13 +249,13 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 55, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(calcHashesButton)
+ .addComponent(alwaysCalcHashesCheckbox)
.addContainerGap())
);
}// //GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
- private javax.swing.JCheckBox calcHashesButton;
+ private javax.swing.JCheckBox alwaysCalcHashesCheckbox;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JLabel knownBadHashDbsLabel;
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java
index 432a4011f2..9f1e10c7ba 100644
--- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java
+++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java
@@ -28,6 +28,7 @@ import java.util.logging.Level;
import javax.swing.JOptionPane;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TskCoreException;
+import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
/**
* This class exists as a stop-gap measure to force users to have an indexed database.
@@ -210,7 +211,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen
this.CURRENTLYON_LABEL.setText("Currently indexing 1 database");
if (!this.toIndex.isIndexing()) {
this.toIndex.addPropertyChangeListener(this);
- this.toIndex.createIndex(okToDeleteOldIndexFile(toIndex));
+ HashDbManager.getInstance().indexHashDatabase(toIndex, okToDeleteOldIndexFile(toIndex));
}
}
@@ -226,7 +227,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen
this.CURRENTLYON_LABEL.setText("Currently indexing 1 of " + length);
if (!db.isIndexing()) {
db.addPropertyChangeListener(this);
- db.createIndex(okToDeleteOldIndexFile(db));
+ HashDbManager.getInstance().indexHashDatabase(db, okToDeleteOldIndexFile(db));
}
}
}
@@ -251,8 +252,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen
this.dispose();
} else {
currentcount++;
- this.CURRENTLYON_LABEL.setText("Currently indexing " + currentcount + " of " + length);
-
+ this.CURRENTLYON_LABEL.setText("Currently indexing " + currentcount + " of " + length);
}
}
}