From 4f4b8e057d25459281552daded2aacd88d074a7e Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Wed, 9 Oct 2013 14:35:52 -0400 Subject: [PATCH 01/30] Add support for loading KDB (SQLite) hash index files. --- .../autopsy/hashdatabase/HashDb.java | 22 +++++++++++++++---- .../hashdatabase/HashDbAddDatabaseDialog.java | 7 +++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index 9a08234eab..6f623157a6 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -57,7 +57,8 @@ public class HashDb implements Comparable { } // Suffix added to the end of a database name to get its index file - private static final String INDEX_SUFFIX = "-md5.idx"; + private static final String INDEX_SUFFIX = ".kdb"; + private static final String INDEX_SUFFIX_OLD = "-md5.idx"; private String name; private List databasePaths; // TODO: Length limited to one for now... @@ -230,7 +231,7 @@ public class HashDb implements Comparable { * @return true if index */ static boolean isIndexPath(String path) { - return path.endsWith(INDEX_SUFFIX); + return (path.endsWith(INDEX_SUFFIX) || path.endsWith(INDEX_SUFFIX_OLD)); } /** @@ -239,11 +240,15 @@ public class HashDb implements Comparable { * @return */ static String toDatabasePath(String indexPath) { - return indexPath.substring(0, indexPath.lastIndexOf(INDEX_SUFFIX)); + if (indexPath.endsWith(INDEX_SUFFIX_OLD)) { + return indexPath.substring(0, indexPath.lastIndexOf(INDEX_SUFFIX_OLD)); + } else { + return indexPath.substring(0, indexPath.lastIndexOf(INDEX_SUFFIX)); + } } /** - * Derives image path from an database path by appending the suffix. + * Derives index path from an database path by appending the suffix. * @param databasePath * @return */ @@ -251,6 +256,15 @@ public class HashDb implements Comparable { return databasePath.concat(INDEX_SUFFIX); } + /** + * Derives old-format index path from an database path by appending the suffix. + * @param databasePath + * @return + */ + static String toOldIndexPath(String databasePath) { + return databasePath.concat(INDEX_SUFFIX_OLD); + } + /** * Calls Sleuth Kit method via JNI to determine whether there is an * index for the given path diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java index cb635520fe..56e5427355 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java @@ -55,7 +55,7 @@ final class HashDbAddDatabaseDialog extends javax.swing.JDialog { void customizeComponents() { fc.setDragEnabled(false); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); - String[] EXTENSION = new String[] { "txt", "idx", "hash", "Hash", "hsh"}; + String[] EXTENSION = new String[] { "txt", "kdb", "idx", "hash", "Hash", "hsh"}; FileNameExtensionFilter filter = new FileNameExtensionFilter( "Hash Database File", EXTENSION); fc.setFileFilter(filter); @@ -285,8 +285,9 @@ final class HashDbAddDatabaseDialog extends javax.swing.JDialog { } try { File db = new File(databasePathTextField.getText()); - File idx = new File(databasePathTextField.getText() + "-md5.idx"); - if (!db.exists() && !idx.exists()) { + File idx = new File(databasePathTextField.getText() + ".kdb"); + File idx_old = new File(databasePathTextField.getText() + "-md5.idx"); + if (!db.exists() && !idx.exists() && !idx_old.exists()) { JOptionPane.showMessageDialog(this, "Selected file does not exist"); return; } From f3635ca754fc6c7cf44e13f43d6f913d6f05764a Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 25 Oct 2013 14:50:24 -0400 Subject: [PATCH 02/30] Adjust label text for hash import dialog. --- .../src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties | 4 ++-- .../autopsy/hashdatabase/HashDbAddDatabaseDialog.form | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index a9aead73cb..3c63f386fb 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -15,9 +15,9 @@ HashDbAddDatabaseDialog.nsrlRadioButton.text=NSRL HashDbAddDatabaseDialog.knownBadRadioButton.text=Known Bad HashDbAddDatabaseDialog.databasePathTextField.text= HashDbAddDatabaseDialog.browseButton.text=Browse -HashDbAddDatabaseDialog.jLabel1.text=Enter the name of the database: +HashDbAddDatabaseDialog.jLabel1.text=Display name of database: HashDbAddDatabaseDialog.databaseNameTextField.text= -HashDbAddDatabaseDialog.jLabel2.text=Select the type of database: +HashDbAddDatabaseDialog.jLabel2.text=Type of database: HashDbAddDatabaseDialog.useForIngestCheckbox.text=Enable for ingest HashDbAddDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest HashDbSearchPanel.hashTable.columnModel.title0=MD5 Hashes diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.form index f336266aed..52051b0957 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.form @@ -10,6 +10,7 @@ + From a1c6352559ee707f3dec6b474ae247c7af779a04 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 25 Oct 2013 14:58:09 -0400 Subject: [PATCH 03/30] HashDbAddDatabaseDialog class renamed to HashDbImportDatabaseDialog --- .../autopsy/hashdatabase/Bundle.properties | 22 ++++++------- ...g.form => HashDbImportDatabaseDialog.form} | 22 ++++++------- ...g.java => HashDbImportDatabaseDialog.java} | 32 +++++++++---------- .../hashdatabase/HashDbManagementPanel.java | 2 +- 4 files changed, 39 insertions(+), 39 deletions(-) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashDbAddDatabaseDialog.form => HashDbImportDatabaseDialog.form} (86%) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashDbAddDatabaseDialog.java => HashDbImportDatabaseDialog.java} (90%) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index 3c63f386fb..4841f13887 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -9,17 +9,6 @@ HashDbSimplePanel.notableLabel.text=Known Bad Database(s): HashDbSimplePanel.knownValLabel.text=- HashDbSimplePanel.notableValLabel.text=- HashDbSimplePanel.jLabel1.text=Enable known bad databases for ingest: -HashDbAddDatabaseDialog.cancelButton.text=Cancel -HashDbAddDatabaseDialog.okButton.text=OK -HashDbAddDatabaseDialog.nsrlRadioButton.text=NSRL -HashDbAddDatabaseDialog.knownBadRadioButton.text=Known Bad -HashDbAddDatabaseDialog.databasePathTextField.text= -HashDbAddDatabaseDialog.browseButton.text=Browse -HashDbAddDatabaseDialog.jLabel1.text=Display name of database: -HashDbAddDatabaseDialog.databaseNameTextField.text= -HashDbAddDatabaseDialog.jLabel2.text=Type of database: -HashDbAddDatabaseDialog.useForIngestCheckbox.text=Enable for ingest -HashDbAddDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest HashDbSearchPanel.hashTable.columnModel.title0=MD5 Hashes HashDbSearchPanel.hashTable.columnModel.title3=Title 4 HashDbSearchPanel.hashTable.columnModel.title2=Title 3 @@ -62,3 +51,14 @@ ModalNoButtons.CURRENTLYON_LABEL.text=Currently Indexing x of y ModalNoButtons.GO_GET_COFFEE_LABEL.text=Hash databases are currently being indexed, this may take some time. ModalNoButtons.CURRENTDB_LABEL.text=(CurrentDb) ModalNoButtons.CANCEL_BUTTON.text=Cancel +HashDbImportDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest +HashDbImportDatabaseDialog.useForIngestCheckbox.text=Enable for ingest +HashDbImportDatabaseDialog.jLabel1.text=Display name of database: +HashDbImportDatabaseDialog.databaseNameTextField.text= +HashDbImportDatabaseDialog.databasePathTextField.text= +HashDbImportDatabaseDialog.browseButton.text=Browse +HashDbImportDatabaseDialog.nsrlRadioButton.text=NSRL +HashDbImportDatabaseDialog.knownBadRadioButton.text=Known Bad +HashDbImportDatabaseDialog.jLabel2.text=Type of database: +HashDbImportDatabaseDialog.okButton.text=OK +HashDbImportDatabaseDialog.cancelButton.text=Cancel diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.form similarity index 86% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.form rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.form index 52051b0957..e6473a9688 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.form @@ -111,7 +111,7 @@ - + @@ -121,7 +121,7 @@ - + @@ -131,14 +131,14 @@ - + - + @@ -151,7 +151,7 @@ - + @@ -165,7 +165,7 @@ - + @@ -175,21 +175,21 @@ - + - + - + @@ -197,7 +197,7 @@ - + @@ -208,7 +208,7 @@ - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java similarity index 90% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index 56e5427355..71d0334eb1 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -37,16 +37,16 @@ import org.sleuthkit.datamodel.TskException; * * @author dfickling */ -final class HashDbAddDatabaseDialog extends javax.swing.JDialog { +final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private JFileChooser fc = new JFileChooser(); private String databaseName; - private static final Logger logger = Logger.getLogger(HashDbAddDatabaseDialog.class.getName()); + private static final Logger logger = Logger.getLogger(HashDbImportDatabaseDialog.class.getName()); /** - * Creates new form HashDbAddDatabaseDialog + * Creates new form HashDbImportDatabaseDialog */ - HashDbAddDatabaseDialog() { - super(new javax.swing.JFrame(), "Add Hash Database", true); + HashDbImportDatabaseDialog() { + super(new javax.swing.JFrame(), "Import Hash Database", true); setResizable(false); initComponents(); customizeComponents(); @@ -100,23 +100,23 @@ final class HashDbAddDatabaseDialog extends javax.swing.JDialog { setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.okButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.okButton.text")); // NOI18N okButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { okButtonActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.cancelButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.cancelButton.text")); // NOI18N cancelButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { cancelButtonActionPerformed(evt); } }); - databasePathTextField.setText(org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.databasePathTextField.text")); // NOI18N + databasePathTextField.setText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.databasePathTextField.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.browseButton.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() { public void actionPerformed(java.awt.event.ActionEvent evt) { browseButtonActionPerformed(evt); @@ -124,7 +124,7 @@ final class HashDbAddDatabaseDialog extends javax.swing.JDialog { }); buttonGroup1.add(nsrlRadioButton); - org.openide.awt.Mnemonics.setLocalizedText(nsrlRadioButton, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.nsrlRadioButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(nsrlRadioButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.nsrlRadioButton.text")); // NOI18N nsrlRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { nsrlRadioButtonActionPerformed(evt); @@ -133,21 +133,21 @@ final class HashDbAddDatabaseDialog extends javax.swing.JDialog { buttonGroup1.add(knownBadRadioButton); knownBadRadioButton.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(knownBadRadioButton, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.knownBadRadioButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(knownBadRadioButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.knownBadRadioButton.text")); // NOI18N knownBadRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { knownBadRadioButtonActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.jLabel1.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.jLabel1.text")); // NOI18N - databaseNameTextField.setText(org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.databaseNameTextField.text")); // NOI18N + databaseNameTextField.setText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.databaseNameTextField.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.jLabel2.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(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.useForIngestCheckbox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.useForIngestCheckbox.text")); // NOI18N useForIngestCheckbox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { useForIngestCheckboxActionPerformed(evt); @@ -155,7 +155,7 @@ final class HashDbAddDatabaseDialog extends javax.swing.JDialog { }); sendInboxMessagesCheckbox.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(sendInboxMessagesCheckbox, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.sendInboxMessagesCheckbox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(sendInboxMessagesCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.sendInboxMessagesCheckbox.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index d64b93ec92..f517867898 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -613,7 +613,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private javax.swing.JCheckBox useForIngestCheckbox; // End of variables declaration//GEN-END:variables private void importHashSet(java.awt.event.ActionEvent evt) { - String name = new HashDbAddDatabaseDialog().display(); + String name = new HashDbImportDatabaseDialog().display(); if(name != null) { hashSetTableModel.selectRowByName(name); } From 2256e737a4ff6b84b615af134d35c2b82e625cc2 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 25 Oct 2013 15:12:31 -0400 Subject: [PATCH 04/30] Added stub implementation of new AddContentToHashDbAction class --- .../AddContentToHashDbAction.java | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100755 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java new file mode 100755 index 0000000000..64dec2f494 --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -0,0 +1,101 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 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.awt.event.ActionEvent; +import java.util.Collection; +import java.util.logging.Level; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JOptionPane; +import org.openide.util.Utilities; +import org.openide.util.Lookup; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.ingest.IngestConfigurator; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Instances of this Action allow users to content to a hash database. + */ +public class AddContentToHashDbAction extends AbstractAction { + // 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). + private static AddContentToHashDbAction instance; + private static String SINGLE_SELECTION_NAME = "Add file to hash database"; + private static String MULTIPLE_SELECTION_NAME = "Add file) to hash database"; + + public static synchronized AddContentToHashDbAction getInstance() { + if (null == instance) { + instance = new AddContentToHashDbAction(); + } + + instance.setEnabled(true); + instance.putValue(Action.NAME, 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 selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + if (selectedFiles.size() > 1) { + instance.putValue(Action.NAME, 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 void actionPerformed(ActionEvent event) { + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + for (AbstractFile file : selectedFiles) { + try { + // RJCTODO: Complete this method. + String md5Hash = file.getMd5Hash(); + if (null != md5Hash) { + throw new TskCoreException("RJCTODO"); + } + } + catch (TskCoreException ex) { + Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); + JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + "to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); + } + } + } +} From 6aec5f35d5393422f92959cece069dd10a20aa34 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 25 Oct 2013 15:25:44 -0400 Subject: [PATCH 05/30] Add skeleton of new Create Hash Database GUI. --- .../autopsy/hashdatabase/Bundle.properties | 12 + .../HashDbCreateDatabaseDialog.form | 217 ++++++++++++ .../HashDbCreateDatabaseDialog.java | 322 ++++++++++++++++++ .../hashdatabase/HashDbManagementPanel.form | 27 +- .../hashdatabase/HashDbManagementPanel.java | 32 +- 5 files changed, 607 insertions(+), 3 deletions(-) create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index 4841f13887..e02678bfe5 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -62,3 +62,15 @@ 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.knownBadRadioButton.text=Known Bad +HashDbCreateDatabaseDialog.nsrlRadioButton.text=NSRL +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=Display name of database: +HashDbCreateDatabaseDialog.databaseNameTextField.text= +HashDbManagementPanel.importButton1.text=Create Database diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form new file mode 100644 index 0000000000..1342083256 --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form @@ -0,0 +1,217 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java new file mode 100644 index 0000000000..780f727412 --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -0,0 +1,322 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 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.awt.Dimension; +import java.awt.Toolkit; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +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 org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; +import org.sleuthkit.datamodel.SleuthkitJNI; +import org.sleuthkit.datamodel.TskException; + +/** + * Creation is a different GUI class than importing + */ +final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { + + private JFileChooser fc = new JFileChooser(); + private String databaseName; + private static final Logger logger = Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()); + /** + * Creates new form HashDbCreateDatabaseDialog + */ + HashDbCreateDatabaseDialog() { + super(new javax.swing.JFrame(), "Create Hash Database", true); + setResizable(false); + initComponents(); + customizeComponents(); + } + + void customizeComponents() { + fc.setDragEnabled(false); + fc.setFileSelectionMode(JFileChooser.FILES_ONLY); + String[] EXTENSION = new String[] { "txt", "kdb", "idx", "hash", "Hash", "hsh"}; + FileNameExtensionFilter filter = new FileNameExtensionFilter( + "Hash Database File", EXTENSION); + fc.setFileFilter(filter); + fc.setMultiSelectionEnabled(false); + } + + String display() { + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); + + // set the popUp window / JFrame + int w = this.getSize().width; + int h = this.getSize().height; + + // set the location of the popUp Window on the center of the screen + setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); + + this.setVisible(true); + return databaseName; + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + buttonGroup1 = new javax.swing.ButtonGroup(); + okButton = new javax.swing.JButton(); + cancelButton = new javax.swing.JButton(); + databasePathTextField = new javax.swing.JTextField(); + browseButton = new javax.swing.JButton(); + nsrlRadioButton = new javax.swing.JRadioButton(); + knownBadRadioButton = new javax.swing.JRadioButton(); + jLabel1 = new javax.swing.JLabel(); + databaseNameTextField = new javax.swing.JTextField(); + jLabel2 = new javax.swing.JLabel(); + useForIngestCheckbox = new javax.swing.JCheckBox(); + sendInboxMessagesCheckbox = new javax.swing.JCheckBox(); + + 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() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.cancelButton.text")); // NOI18N + cancelButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cancelButtonActionPerformed(evt); + } + }); + + 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(nsrlRadioButton); + org.openide.awt.Mnemonics.setLocalizedText(nsrlRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.nsrlRadioButton.text")); // NOI18N + nsrlRadioButton.setEnabled(false); + nsrlRadioButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + nsrlRadioButtonActionPerformed(evt); + } + }); + + buttonGroup1.add(knownBadRadioButton); + knownBadRadioButton.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(knownBadRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.knownBadRadioButton.text")); // NOI18N + knownBadRadioButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + knownBadRadioButtonActionPerformed(evt); + } + }); + + 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 + + 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() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + useForIngestCheckboxActionPerformed(evt); + } + }); + + sendInboxMessagesCheckbox.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(sendInboxMessagesCheckbox, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.sendInboxMessagesCheckbox.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .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)) + .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(nsrlRadioButton)) + .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)))) + ); + 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(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(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(nsrlRadioButton) + .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()) + ); + + pack(); + }// //GEN-END:initComponents + + private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed + String oldText = databasePathTextField.getText(); + // set the current directory of the FileChooser if the databasePath Field is valid + File currentDir = new File(oldText); + if (currentDir.exists()) { + fc.setCurrentDirectory(currentDir); + } + int retval = fc.showSaveDialog(this); + if (retval == JFileChooser.APPROVE_OPTION) { + File f = fc.getSelectedFile(); + try { + String filePath = f.getCanonicalPath(); + if (HashDb.isIndexPath(filePath)) { + filePath = HashDb.toDatabasePath(filePath); + } + String derivedName = f.getName(); + databasePathTextField.setText(filePath); + databaseNameTextField.setText(derivedName); + if (derivedName.toLowerCase().contains("nsrl")) { + nsrlRadioButton.setSelected(true); + nsrlRadioButtonActionPerformed(null); + } + } catch (IOException ex) { + logger.log(Level.WARNING, "Couldn't get selected file path.", ex); + } + } + }//GEN-LAST:event_browseButtonActionPerformed + + private void nsrlRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nsrlRadioButtonActionPerformed + sendInboxMessagesCheckbox.setSelected(false); + sendInboxMessagesCheckbox.setEnabled(false); + }//GEN-LAST:event_nsrlRadioButtonActionPerformed + + private void knownBadRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownBadRadioButtonActionPerformed + sendInboxMessagesCheckbox.setSelected(true); + sendInboxMessagesCheckbox.setEnabled(true); + }//GEN-LAST:event_knownBadRadioButtonActionPerformed + + private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed + this.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; + } + + DBType type; + if(nsrlRadioButton.isSelected()) { + type = DBType.NSRL; + } else { + type = DBType.KNOWN_BAD; + } + + /// @todo Call the HashDb create factory method here +// HashDb db = HashDb.create(databaseNameTextField.getText(), +// Arrays.asList(new String[] {databasePathTextField.getText()}), +// useForIngestCheckbox.isSelected(), +// sendInboxMessagesCheckbox.isSelected(), +// type); + +// if(type == DBType.KNOWN_BAD) { +// HashDbXML.getCurrent().addKnownBadSet(db); +// } else if(type == DBType.NSRL) { +// HashDbXML.getCurrent().setNSRLSet(db); +// } + databaseName = databaseNameTextField.getText(); + this.dispose(); + }//GEN-LAST:event_okButtonActionPerformed + + private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed + // TODO add your handling code here: + }//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.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JRadioButton knownBadRadioButton; + private javax.swing.JRadioButton nsrlRadioButton; + private javax.swing.JButton okButton; + private javax.swing.JCheckBox sendInboxMessagesCheckbox; + private javax.swing.JCheckBox useForIngestCheckbox; + // End of variables declaration//GEN-END:variables +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form index ab3578fe41..a59153fa65 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form @@ -115,6 +115,7 @@ + @@ -170,7 +171,7 @@ - + @@ -178,6 +179,8 @@ + + @@ -379,5 +382,27 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index f517867898..442c220df5 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -179,6 +179,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP optionsLabel = new javax.swing.JLabel(); informationSeparator = new javax.swing.JSeparator(); optionsSeparator = new javax.swing.JSeparator(); + importButton1 = new javax.swing.JButton(); org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.jLabel2.text")); // NOI18N @@ -278,6 +279,17 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.optionsLabel.text")); // NOI18N + importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/import16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.importButton1.text")); // NOI18N + importButton1.setMaximumSize(new java.awt.Dimension(140, 25)); + importButton1.setMinimumSize(new java.awt.Dimension(140, 25)); + importButton1.setPreferredSize(new java.awt.Dimension(140, 25)); + importButton1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + importButton1ActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -325,7 +337,8 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP .addComponent(hashDbNameLabel))) .addComponent(useForIngestCheckbox) .addComponent(showInboxMessagesCheckBox) - .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE)))))) + .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE))))) + .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap(40, Short.MAX_VALUE)) ); layout.setVerticalGroup( @@ -370,11 +383,13 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP .addGap(18, 18, 18) .addComponent(ingestWarningLabel) .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 422, Short.MAX_VALUE)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 391, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(importButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) ); }// //GEN-END:initComponents @@ -489,6 +504,10 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP importHashSet(evt); }//GEN-LAST:event_importButtonActionPerformed + private void importButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importButton1ActionPerformed + createHashSet(evt); + }//GEN-LAST:event_importButton1ActionPerformed + @Override public void load() { hashSetTable.clearSelection(); // Deselect all rows @@ -594,6 +613,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private javax.swing.JLabel hashDbTypeLabel; private javax.swing.JTable hashSetTable; private javax.swing.JButton importButton; + private javax.swing.JButton importButton1; private javax.swing.JButton indexButton; private javax.swing.JLabel indexLabel; private javax.swing.JLabel informationLabel; @@ -620,6 +640,14 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP resync(); } + private void createHashSet(java.awt.event.ActionEvent evt) { + String name = new HashDbCreateDatabaseDialog().display(); + if(name != null) { + hashSetTableModel.selectRowByName(name); + } + resync(); + } + /** * The visual display of hash databases loaded. */ From 66babd6068b208f91933e5e756c1a4a4a643aa08 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 25 Oct 2013 15:53:53 -0400 Subject: [PATCH 06/30] Prevent overwriting existing files from create database dialog. --- .../HashDbCreateDatabaseDialog.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index 780f727412..a60a1232fd 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -38,7 +38,8 @@ import org.sleuthkit.datamodel.TskException; */ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { - private JFileChooser fc = new JFileChooser(); + private JFileChooser fc; + private String databaseName; private static final Logger logger = Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()); /** @@ -47,6 +48,22 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { HashDbCreateDatabaseDialog() { super(new javax.swing.JFrame(), "Create Hash Database", true); setResizable(false); + + fc = new JFileChooser() { + @Override + public void approveSelection() { + File ftemp = getSelectedFile(); + if (ftemp.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) { + cancelSelection(); + } + return; + } + super.approveSelection(); + } + }; + initComponents(); customizeComponents(); } @@ -236,6 +253,9 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { int retval = fc.showSaveDialog(this); if (retval == JFileChooser.APPROVE_OPTION) { File f = fc.getSelectedFile(); + + ///@todo check if file already exists + try { String filePath = f.getCanonicalPath(); if (HashDb.isIndexPath(filePath)) { From f2591c721244173307fa305464ccee84ad6a27d5 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 25 Oct 2013 16:08:16 -0400 Subject: [PATCH 07/30] Wired up new AddContentToHashDbAction stub --- .../autopsy/datamodel/DirectoryNode.java | 4 +++- .../org/sleuthkit/autopsy/datamodel/FileNode.java | 4 +++- .../autopsy/datamodel/LayoutFileNode.java | 6 ++++-- .../autopsy/datamodel/LocalFileNode.java | 4 +++- .../autopsy/datamodel/VirtualDirectoryNode.java | 4 +++- .../directorytree}/AddContentToHashDbAction.java | 4 ++-- .../directorytree/DataResultFilterNode.java | 7 ++++++- .../directorytree/ExplorerNodeActionVisitor.java | 15 ++++++++++----- .../keywordsearch/KeywordSearchFilterNode.java | 2 ++ 9 files changed, 36 insertions(+), 14 deletions(-) rename {HashDatabase/src/org/sleuthkit/autopsy/hashdatabase => Core/src/org/sleuthkit/autopsy/directorytree}/AddContentToHashDbAction.java (95%) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index 3c4d33c253..a2828140ab 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; +import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; @@ -77,6 +78,7 @@ public class DirectoryNode extends AbstractFsContentNode { actions.add(ExtractAction.getInstance()); actions.add(null); // creates a menu separator actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentToHashDbAction.getInstance()); return actions.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index 9ca87fd8a7..614b34daff 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; +import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -85,6 +86,7 @@ public class FileNode extends AbstractFsContentNode { actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.add(AddContentToHashDbAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index 9224131ad6..d7384b05d8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; @@ -102,13 +103,14 @@ public class LayoutFileNode extends AbstractAbstractFileNode { @Override public Action[] getActions(boolean context) { - List actionsList = new ArrayList(); + List actionsList = new ArrayList<>(); actionsList.add(new NewWindowViewAction("View in New Window", this)); actionsList.add(new ExternalViewerAction("Open in External Viewer", this)); actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.add(AddContentToHashDbAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index 78711736b9..be3a93f602 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -26,6 +26,7 @@ import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.TYPE; +import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -92,7 +93,8 @@ public class LocalFileNode extends AbstractAbstractFileNode { actionsList.add(ExtractAction.getInstance()); actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator - actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.add(AddContentToHashDbAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 756a376d11..c0b9a6a841 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,7 @@ import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; @@ -82,6 +83,7 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode visit(final Directory d) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentToHashDbAction.getInstance()); return actions; } @Override public List visit(final VirtualDirectory d) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentToHashDbAction.getInstance()); return actions; } @Override public List visit(final DerivedFile d) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentToHashDbAction.getInstance()); return actions; } @Override public List visit(final LocalFile d) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentToHashDbAction.getInstance()); return actions; } @Override public List visit(final org.sleuthkit.datamodel.File d) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentToHashDbAction.getInstance()); return actions; } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index 968631e27a..006839fcc5 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.DerivedFile; @@ -152,6 +153,7 @@ class KeywordSearchFilterNode extends FilterNode { actions.add(new HashSearchAction("Search for files with the same MD5 hash", getOriginal())); actions.add(null); // creates a menu separator actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentToHashDbAction.getInstance()); return actions; } From bd083e7b8d3338ebf8330b96929ea0ca2d23648d Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 25 Oct 2013 16:19:41 -0400 Subject: [PATCH 08/30] Update the create button. The new icon can be improved later. --- .../hashdatabase/HashDbCreateDatabaseDialog.java | 4 +--- .../hashdatabase/HashDbManagementPanel.form | 7 +++++-- .../hashdatabase/HashDbManagementPanel.java | 5 +++-- .../hashdatabase/btn_icon_create_new_16.png | Bin 0 -> 744 bytes 4 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/btn_icon_create_new_16.png diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index a60a1232fd..90b852310d 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -252,9 +252,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } int retval = fc.showSaveDialog(this); if (retval == JFileChooser.APPROVE_OPTION) { - File f = fc.getSelectedFile(); - - ///@todo check if file already exists + File f = fc.getSelectedFile(); try { String filePath = f.getCanonicalPath(); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form index a59153fa65..6a5753371f 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form @@ -115,7 +115,7 @@ - + @@ -385,11 +385,14 @@ - + + + + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index 442c220df5..76ad80bbd9 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -279,8 +279,9 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.optionsLabel.text")); // NOI18N - importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/import16.png"))); // NOI18N + importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/btn_icon_create_new_16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.importButton1.text")); // NOI18N + importButton1.setMargin(new java.awt.Insets(2, 11, 2, 14)); importButton1.setMaximumSize(new java.awt.Dimension(140, 25)); importButton1.setMinimumSize(new java.awt.Dimension(140, 25)); importButton1.setPreferredSize(new java.awt.Dimension(140, 25)); @@ -338,7 +339,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP .addComponent(useForIngestCheckbox) .addComponent(showInboxMessagesCheckBox) .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE))))) - .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap(40, Short.MAX_VALUE)) ); layout.setVerticalGroup( diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/btn_icon_create_new_16.png b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/btn_icon_create_new_16.png new file mode 100644 index 0000000000000000000000000000000000000000..86c1018f3912e1e39fdb52a275fc979c55224da4 GIT binary patch literal 744 zcmVP)ikZ z^;)fllQn6r|0mAgLZLuDpGQOx5r&6{uK`pl74+%9I8Xc*p2JE)YGZ_yT+WgHbmyHd z6N?B+Db^bgQ95OyP$V`XoldAf2sjP;tNtg&;TYwd;M+q62FDmJUEsmv?{?jzqbdEq z>wnIg7h8`|r9(PtgX3e0+T3D}7p&B|xti5m}dxye2deeh{$s zqCuSWh1fA$74Und(%689INYaEazxY<%zsvaDfY?Tu(GB9BC5$8X zc8=Dz*Z-YYD=RB`;HpyUYo*jEP=1#HrPL;Br@1`cie60wX^TNU&c(qiOC!0@zW?~6 a>5VtgY;za!XkOX?0000 Date: Fri, 25 Oct 2013 17:15:59 -0400 Subject: [PATCH 09/30] Added new API to HashDb class (start of SleuthkitKNI hash db facade) --- .../autopsy/hashdatabase/HashDb.java | 47 +++++++++++++++++-- .../hashdatabase/HashDbAddDatabaseDialog.java | 21 +++++---- .../autopsy/hashdatabase/HashDbXML.java | 30 +++++++----- 3 files changed, 73 insertions(+), 25 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index 6f623157a6..c1b68d8ade 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,14 +21,17 @@ package org.sleuthkit.autopsy.hashdatabase; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; +import java.util.Collections; import java.util.List; import java.util.logging.Level; import javax.swing.SwingWorker; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; -import org.openide.util.Cancellable; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitJNI; +import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskException; /** @@ -66,8 +69,31 @@ public class HashDb implements Comparable { private boolean showInboxMessages; private boolean indexing; private DBType type; + private int handle; - public HashDb(String name, List databasePaths, boolean useForIngest, boolean showInboxMessages, DBType type) { + static public HashDb openHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) throws TskCoreException { + HashDb database = new HashDb(SleuthkitJNI.openHashDatabase(databasePath), name, Collections.singletonList(databasePath), useForIngest, showInboxMessages, type); + addToXMLFile(database); + return database; + } + + static public HashDb createHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) throws TskCoreException { + HashDb database = new HashDb(SleuthkitJNI.newHashDatabase(databasePath), name, Collections.singletonList(databasePath), useForIngest, showInboxMessages, type); + addToXMLFile(database); + return database; + } + + static private void addToXMLFile(HashDb database) { + if (database.getDbType() == HashDb.DBType.NSRL) { + HashDbXML.getCurrent().setNSRLSet(database); + } + else { + HashDbXML.getCurrent().addKnownBadSet(database); + } + } + + private HashDb(int handle, String name, List databasePaths, boolean useForIngest, boolean showInboxMessages, DBType type) { + this.handle = handle; this.name = name; this.databasePaths = databasePaths; this.useForIngest = useForIngest; @@ -76,6 +102,21 @@ public class HashDb implements Comparable { this.indexing = false; } + public boolean isUpdateable() { + // RJCTODO: Complete this + return true; + } + + public void addContent(Content content) throws TskCoreException { + // @@@ This only works for AbstractFiles at present. + if (content instanceof AbstractFile) { + AbstractFile file = (AbstractFile)content; + if (null != file.getMd5Hash()) { + SleuthkitJNI.addToHashDatabase(file.getName(), file.getMd5Hash(), "", "", handle); + } + } + } + void addPropertyChangeListener(PropertyChangeListener pcl) { pcs.addPropertyChangeListener(pcl); } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java index 56e5427355..1b34ad620f 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java @@ -303,16 +303,17 @@ final class HashDbAddDatabaseDialog extends javax.swing.JDialog { } else { type = DBType.KNOWN_BAD; } - HashDb db = new HashDb(databaseNameTextField.getText(), - Arrays.asList(new String[] {databasePathTextField.getText()}), - useForIngestCheckbox.isSelected(), - sendInboxMessagesCheckbox.isSelected(), - type); - if(type == DBType.KNOWN_BAD) { - HashDbXML.getCurrent().addKnownBadSet(db); - } else if(type == DBType.NSRL) { - HashDbXML.getCurrent().setNSRLSet(db); - } + // RJCTODO: Sam is replacing this class. +// HashDb db = new HashDb(databaseNameTextField.getText(), +// Arrays.asList(new String[] {databasePathTextField.getText()}), +// useForIngestCheckbox.isSelected(), +// sendInboxMessagesCheckbox.isSelected(), +// type); +// if(type == DBType.KNOWN_BAD) { +// HashDbXML.getCurrent().addKnownBadSet(db); +// } else if(type == DBType.NSRL) { +// HashDbXML.getCurrent().setNSRLSet(db); +// } databaseName = databaseNameTextField.getText(); this.dispose(); }//GEN-LAST:event_okButtonActionPerformed diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java index 9ddc638b9e..0ac5f8b31c 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,6 +32,7 @@ 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.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; @@ -63,7 +64,7 @@ public class HashDbXML { private boolean calculate; private HashDbXML(String xmlFile) { - knownBadSets = new ArrayList(); + knownBadSets = new ArrayList<>(); this.xmlFile = xmlFile; } @@ -82,7 +83,7 @@ public class HashDbXML { * Get the hash sets */ public List getAllSets() { - List ret = new ArrayList(); + List ret = new ArrayList<>(); if(nsrlSet != null) { ret.add(nsrlSet); } @@ -285,9 +286,10 @@ public class HashDbXML { final String showInboxMessages = setEl.getAttribute(SET_SHOW_INBOX_MESSAGES); Boolean useForIngestBool = Boolean.parseBoolean(useForIngest); Boolean showInboxMessagesBool = Boolean.parseBoolean(showInboxMessages); - List paths = new ArrayList(); + List paths = new ArrayList<>(); // Parse all paths + // @@@ TODO: There is no need for more than one path. NodeList pathsNList = setEl.getElementsByTagName(PATH_EL); final int numPaths = pathsNList.getLength(); for (int j = 0; j < numPaths; ++j) { @@ -330,16 +332,20 @@ public class HashDbXML { } if(paths.isEmpty()) { - logger.log(Level.WARNING, "No paths were set for hash_set at index {0}. Removing the database.", i); - } else { // No paths for this entry, the user most likely declined to search for them + logger.log(Level.WARNING, "No paths were set for hash_set at index {0}. Removing the database.", i); + } + else { DBType typeDBType = DBType.valueOf(type); - HashDb set = new HashDb(name, paths, useForIngestBool, showInboxMessagesBool, typeDBType); - - if(typeDBType == DBType.KNOWN_BAD) { - knownBadSets.add(set); - } else if(typeDBType == DBType.NSRL) { - this.nsrlSet = set; + try { + // @@@ Note that this method calls back to addKnownBadSet() or setNSRLSet(). + // In the future, this class will become an inner class of HashDb and will only handle reading and + // writing the XML file. + HashDb.openHashDatabase(name, paths.get(0), useForIngestBool, showInboxMessagesBool, typeDBType); + } + catch (TskCoreException ex) { + Logger.getLogger(HashDbXML.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); + JOptionPane.showMessageDialog(null, "Unable to open " + paths.get(0) + " hash database.", "Open Hash Database Error", JOptionPane.ERROR_MESSAGE); } } } From cd8b25745876dba5d12ac05ad4590f18fc7faa2e Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 25 Oct 2013 17:33:06 -0400 Subject: [PATCH 10/30] Extended the HasdDb API --- .../org/sleuthkit/autopsy/hashdatabase/HashDb.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index c1b68d8ade..e9f87f158b 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.hashdatabase; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Level; @@ -92,6 +93,17 @@ public class HashDb implements Comparable { } } + static public List getUpdateableHashDatabases() { + ArrayList updateableDbs = new ArrayList<>(); + List candidateDbs = HashDbXML.getCurrent().getKnownBadSets(); + for (HashDb db : candidateDbs) { + if (db.isUpdateable()) { + updateableDbs.add(db); + } + } + return updateableDbs; + } + private HashDb(int handle, String name, List databasePaths, boolean useForIngest, boolean showInboxMessages, DBType type) { this.handle = handle; this.name = name; From 136f93d38c0e877a288664c68fecdf517ec5baa5 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 25 Oct 2013 17:53:45 -0400 Subject: [PATCH 11/30] Changed HashDb method name and updated comments --- .../src/org/sleuthkit/autopsy/hashdatabase/HashDb.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index e9f87f158b..e86dcc2492 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -65,7 +65,7 @@ public class HashDb implements Comparable { private static final String INDEX_SUFFIX_OLD = "-md5.idx"; private String name; - private List databasePaths; // TODO: Length limited to one for now... + private List databasePaths; // TODO: Only need a single path, may only need to store handle private boolean useForIngest; private boolean showInboxMessages; private boolean indexing; @@ -119,7 +119,7 @@ public class HashDb implements Comparable { return true; } - public void addContent(Content content) throws TskCoreException { + public void addContentHash(Content content) throws TskCoreException { // @@@ This only works for AbstractFiles at present. if (content instanceof AbstractFile) { AbstractFile file = (AbstractFile)content; @@ -203,7 +203,7 @@ public class HashDb implements Comparable { * @return a File initialized with the database path */ File databaseFile() { - return new File(databasePaths.get(0)); // TODO: support multiple paths + return new File(databasePaths.get(0)); // TODO: don't support multiple paths } /** @@ -212,7 +212,7 @@ public class HashDb implements Comparable { * path */ File indexFile() { - return new File(toIndexPath(databasePaths.get(0))); // TODO: support multiple paths + return new File(toIndexPath(databasePaths.get(0))); // TODO: don't support multiple paths } /** From 6cb5b47af495a2834d234f39f430b5008564cf5d Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 25 Oct 2013 18:01:18 -0400 Subject: [PATCH 12/30] Update create and import dialogs for the new HashDB interface. --- .../HashDbCreateDatabaseDialog.java | 21 ++++++++----------- .../HashDbImportDatabaseDialog.java | 21 +++++++++---------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index 90b852310d..f17eabd0bd 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -302,19 +302,16 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } else { type = DBType.KNOWN_BAD; } + + try + { + HashDb db = HashDb.createHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + } catch (TskException ex) { + logger.log(Level.WARNING, "Database creation error: ", ex); + JOptionPane.showMessageDialog(this, "Database file cannot be created.\n"); + return; + } - /// @todo Call the HashDb create factory method here -// HashDb db = HashDb.create(databaseNameTextField.getText(), -// Arrays.asList(new String[] {databasePathTextField.getText()}), -// useForIngestCheckbox.isSelected(), -// sendInboxMessagesCheckbox.isSelected(), -// type); - -// if(type == DBType.KNOWN_BAD) { -// HashDbXML.getCurrent().addKnownBadSet(db); -// } else if(type == DBType.NSRL) { -// HashDbXML.getCurrent().setNSRLSet(db); -// } databaseName = databaseNameTextField.getText(); this.dispose(); }//GEN-LAST:event_okButtonActionPerformed diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index d62c764b9c..71d769f8df 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -303,17 +303,16 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { } else { type = DBType.KNOWN_BAD; } - // RJCTODO: Sam is replacing this class. -// HashDb db = new HashDb(databaseNameTextField.getText(), -// Arrays.asList(new String[] {databasePathTextField.getText()}), -// useForIngestCheckbox.isSelected(), -// sendInboxMessagesCheckbox.isSelected(), -// type); -// if(type == DBType.KNOWN_BAD) { -// HashDbXML.getCurrent().addKnownBadSet(db); -// } else if(type == DBType.NSRL) { -// HashDbXML.getCurrent().setNSRLSet(db); -// } + + try + { + HashDb db = HashDb.openHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + } catch (TskException ex) { + logger.log(Level.WARNING, "Invalid database: ", ex); + JOptionPane.showMessageDialog(this, "Database file you chose cannot be opened.\n" + "If it was just an index, please try to recreate it from the database"); + return; + } + databaseName = databaseNameTextField.getText(); this.dispose(); }//GEN-LAST:event_okButtonActionPerformed From c13f41f67cf2028c2d6942e86812f327f16245b0 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 28 Oct 2013 15:09:58 -0400 Subject: [PATCH 13/30] Changed plumbing for adding content to hash db actions --- .../ContextMenuActionsProvider.java | 37 +++++++++++ .../coreutils/ContextMenuExtensionPoint.java | 45 ++++++++++++++ .../autopsy/datamodel/DirectoryNode.java | 2 - .../sleuthkit/autopsy/datamodel/FileNode.java | 2 - .../autopsy/datamodel/LayoutFileNode.java | 2 - .../autopsy/datamodel/LocalFileNode.java | 2 - .../datamodel/VirtualDirectoryNode.java | 2 - .../directorytree/DataResultFilterNode.java | 5 -- .../ExplorerNodeActionVisitor.java | 5 -- .../AddContentToHashDbAction.java | 61 +++++++++++++------ .../autopsy/hashdatabase/HashDbXML.java | 1 - .../KeywordSearchFilterNode.java | 2 +- 12 files changed, 127 insertions(+), 39 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java create mode 100755 Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java rename {Core/src/org/sleuthkit/autopsy/directorytree => HashDatabase/src/org/sleuthkit/autopsy/hashdatabase}/AddContentToHashDbAction.java (58%) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java new file mode 100755 index 0000000000..1d84ca2c6c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java @@ -0,0 +1,37 @@ +/* + * 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.corecomponentinterfaces; + +import java.util.List; +import javax.swing.Action; + +/** + * Implementers of this interface provide Actions that will be added to context + * menus in Autopsy. + */ +public interface ContextMenuActionsProvider { + /** + * Gets context menu Actions appropriate to the org.sleuthkit.datamodel + * objects in the NetBeans Lookup for the active TopComponent. + * Implementers can discover the data model objects by calling + * org.openide.util.Utilities.actionsGlobalContext().lookupAll(). + * @return A list, possibly empty, of Action objects. + */ + List getActions(); +} diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java b/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java new file mode 100755 index 0000000000..f066d20de9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java @@ -0,0 +1,45 @@ +/* + * 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.coreutils; + +import org.openide.util.Lookup; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.swing.Action; +import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider; + +/** + * This class implements the ContextMenuActionsProvider extension point. + */ +public class ContextMenuExtensionPoint { + /** + * Gets all of the Actions provided by registered implementers of the + * ContextMenuActionsProvider interface. + * @return A list, possibly empty, of Action objects. + */ + static public List getActions() { + ArrayList actions = new ArrayList<>(); + Collection actionProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class); + for (ContextMenuActionsProvider provider : actionProviders) { + actions.addAll(provider.getActions()); + } + return actions; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index a2828140ab..182a64c61d 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; -import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; @@ -78,7 +77,6 @@ public class DirectoryNode extends AbstractFsContentNode { actions.add(ExtractAction.getInstance()); actions.add(null); // creates a menu separator actions.add(TagAbstractFileAction.getInstance()); - actions.add(AddContentToHashDbAction.getInstance()); return actions.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index 614b34daff..04c0c1a078 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; -import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -86,7 +85,6 @@ public class FileNode extends AbstractFsContentNode { actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); - actionsList.add(AddContentToHashDbAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index d7384b05d8..5dd48d1ae1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; -import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; @@ -110,7 +109,6 @@ public class LayoutFileNode extends AbstractAbstractFileNode { actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); - actionsList.add(AddContentToHashDbAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index be3a93f602..af8ef7549f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -26,7 +26,6 @@ import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.TYPE; -import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -94,7 +93,6 @@ public class LocalFileNode extends AbstractAbstractFileNode { actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); - actionsList.add(AddContentToHashDbAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index c0b9a6a841..76062876bc 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -25,7 +25,6 @@ import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; @@ -83,7 +82,6 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode visit(final Directory d) { List actions = new ArrayList<>(); actions.add(TagAbstractFileAction.getInstance()); - actions.add(AddContentToHashDbAction.getInstance()); return actions; } @@ -111,7 +110,6 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); - actions.add(AddContentToHashDbAction.getInstance()); return actions; } @@ -120,7 +118,6 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); - actions.add(AddContentToHashDbAction.getInstance()); return actions; } @@ -129,7 +126,6 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); - actions.add(AddContentToHashDbAction.getInstance()); return actions; } @@ -138,7 +134,6 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); - actions.add(AddContentToHashDbAction.getInstance()); return actions; } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java similarity index 58% rename from Core/src/org/sleuthkit/autopsy/directorytree/AddContentToHashDbAction.java rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index 44999ef5c1..e7ee2e548d 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -16,25 +16,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.directorytree; +package org.sleuthkit.autopsy.hashdatabase; import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.Collection; 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; import org.openide.util.Utilities; import org.openide.util.Lookup; -import org.sleuthkit.autopsy.coreutils.Logger; +import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.ingest.IngestConfigurator; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this Action allow users to content to a hash database. */ -public class AddContentToHashDbAction extends AbstractAction { +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). @@ -81,21 +85,44 @@ public class AddContentToHashDbAction extends AbstractAction { super(SINGLE_SELECTION_NAME); } + @Override + public JMenuItem getPopupPresenter() { + return new AddContentToHashDbMenu(); + } + @Override public void actionPerformed(ActionEvent event) { - Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); - for (AbstractFile file : selectedFiles) { - try { - // RJCTODO: Complete this method. - String md5Hash = file.getMd5Hash(); - if (null != md5Hash) { - throw new TskCoreException("RJCTODO"); - } + } + + private class AddContentToHashDbMenu extends JMenu { + AddContentToHashDbMenu() { + // RJCTODO: Need super call? + + // Get the current set of updateable hash databases and add each + // one as a menu item. + for (final HashDb database : HashDbXML.getCurrent().getKnownBadSets()) { + if (database.isUpdateable()) { + JMenuItem databaseItem = add(database.getName()); + databaseItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + for (AbstractFile file : selectedFiles) { + String md5Hash = file.getMd5Hash(); + if (null != md5Hash) { + try { + database.addContentHash(file); + } + catch (TskCoreException ex) { + Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); + JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + "to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); + } + } + } + } + }); + } } - catch (TskCoreException ex) { - Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); - JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + "to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); - } - } - } + } + } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java index 0ac5f8b31c..e8f0ff8bee 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java @@ -32,7 +32,6 @@ 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.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index 006839fcc5..8f83110767 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -33,7 +33,7 @@ import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; +import org.sleuthkit.autopsy.hashdatabase.AddContentToHashDbAction; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.DerivedFile; From 40ee532e1cd961c0b5256a1a0509ac97078879ea Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 28 Oct 2013 17:47:20 -0400 Subject: [PATCH 14/30] Implemented ContextMenuActionProvider interface in HashDatabase module --- .../ContextMenuActionsProvider.java | 11 ++-- .../coreutils/ContextMenuExtensionPoint.java | 6 +- .../autopsy/datamodel/DirectoryNode.java | 2 + .../sleuthkit/autopsy/datamodel/FileNode.java | 2 + .../autopsy/datamodel/LayoutFileNode.java | 2 + .../autopsy/datamodel/LocalFileNode.java | 2 + .../datamodel/VirtualDirectoryNode.java | 2 + .../directorytree/DataResultFilterNode.java | 6 ++ .../ExplorerNodeActionVisitor.java | 6 ++ .../AddContentToHashDbAction.java | 62 +++++++++++-------- .../HashDbContextMenuActionsProvider.java | 41 ++++++++++++ .../KeywordSearchFilterNode.java | 4 +- 12 files changed, 113 insertions(+), 33 deletions(-) create mode 100755 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbContextMenuActionsProvider.java diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java index 1d84ca2c6c..aff714f736 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java @@ -27,11 +27,12 @@ import javax.swing.Action; */ public interface ContextMenuActionsProvider { /** - * Gets context menu Actions appropriate to the org.sleuthkit.datamodel - * objects in the NetBeans Lookup for the active TopComponent. - * Implementers can discover the data model objects by calling - * org.openide.util.Utilities.actionsGlobalContext().lookupAll(). + * Gets context menu Actions for the currently selected data model objects + * exposed by the NetBeans Lookup of the active TopComponent. Implementers + * should discover the selected objects by calling + * org.openide.util.Utilities.actionsGlobalContext().lookupAll() for the + * org.sleuthkit.datamodel classes of interest to the provider. * @return A list, possibly empty, of Action objects. */ - List getActions(); + public List getActions(); } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java b/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java index f066d20de9..fcf626283c 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java @@ -38,7 +38,11 @@ public class ContextMenuExtensionPoint { ArrayList actions = new ArrayList<>(); Collection actionProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class); for (ContextMenuActionsProvider provider : actionProviders) { - actions.addAll(provider.getActions()); + List providerActions = provider.getActions(); + if (!providerActions.isEmpty()) { + actions.add(null); // Separator to set off this provider's actions. + actions.addAll(provider.getActions()); + } } return actions; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index 182a64c61d..ca7aae9a04 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; @@ -77,6 +78,7 @@ public class DirectoryNode extends AbstractFsContentNode { actions.add(ExtractAction.getInstance()); actions.add(null); // creates a menu separator actions.add(TagAbstractFileAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index 04c0c1a078..4403463706 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -85,6 +86,7 @@ public class FileNode extends AbstractFsContentNode { actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index 5dd48d1ae1..aace8dc731 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; @@ -109,6 +110,7 @@ public class LayoutFileNode extends AbstractAbstractFileNode { actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index af8ef7549f..19a2d15314 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.TYPE; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; @@ -93,6 +94,7 @@ public class LocalFileNode extends AbstractAbstractFileNode { actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 76062876bc..d7d4fdda17 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; @@ -82,6 +83,7 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode visit(final Directory d) { List actions = new ArrayList<>(); actions.add(TagAbstractFileAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } @@ -110,6 +112,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } @@ -118,6 +121,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } @@ -126,6 +130,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } @@ -134,6 +139,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index e7ee2e548d..250d44e0a5 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.hashdatabase; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collection; +import java.util.List; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.Action; @@ -44,8 +45,9 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente // node in the array returns a reference to the same action object from Node.getActions(boolean). 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 static String MULTIPLE_SELECTION_NAME = "Add files to hash database"; + private String menuText; + public static synchronized AddContentToHashDbAction getInstance() { if (null == instance) { instance = new AddContentToHashDbAction(); @@ -53,6 +55,7 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente 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); @@ -65,6 +68,7 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente Collection 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); @@ -87,7 +91,7 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente @Override public JMenuItem getPopupPresenter() { - return new AddContentToHashDbMenu(); + return new AddContentToHashDbMenu(menuText); } @Override @@ -95,34 +99,42 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente } private class AddContentToHashDbMenu extends JMenu { - AddContentToHashDbMenu() { - // RJCTODO: Need super call? + AddContentToHashDbMenu(String menuText) { + super(menuText); // Get the current set of updateable hash databases and add each // one as a menu item. - for (final HashDb database : HashDbXML.getCurrent().getKnownBadSets()) { - if (database.isUpdateable()) { - JMenuItem databaseItem = add(database.getName()); - databaseItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); - for (AbstractFile file : selectedFiles) { - String md5Hash = file.getMd5Hash(); - if (null != md5Hash) { - try { - database.addContentHash(file); - } - catch (TskCoreException ex) { - Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); - JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + "to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); - } - } + List hashDatabases = HashDbXML.getCurrent().getKnownBadSets(); + if (!hashDatabases.isEmpty()) { + for (final HashDb database : HashDbXML.getCurrent().getKnownBadSets()) { + if (database.isUpdateable()) { + JMenuItem databaseItem = add(database.getName()); + databaseItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + for (AbstractFile file : selectedFiles) { + String md5Hash = file.getMd5Hash(); + if (null != md5Hash) { + try { + database.addContentHash(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); + } + } + } } - } - }); + }); + } } } + else { + JMenuItem empty = new JMenuItem("No hash databases"); + empty.setEnabled(false); + add(empty); + } } } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbContextMenuActionsProvider.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbContextMenuActionsProvider.java new file mode 100755 index 0000000000..6f03e7095b --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbContextMenuActionsProvider.java @@ -0,0 +1,41 @@ +/* + * 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.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.swing.Action; +import org.openide.util.Utilities; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider; +import org.sleuthkit.datamodel.AbstractFile; + +@ServiceProvider(service = ContextMenuActionsProvider.class) +public class HashDbContextMenuActionsProvider implements ContextMenuActionsProvider { + @Override + public List getActions() { + ArrayList actions = new ArrayList<>(); + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + if (!selectedFiles.isEmpty()) { + actions.add(AddContentToHashDbAction.getInstance()); + } + return actions; + } +} diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index 8f83110767..603682c9da 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -28,12 +28,12 @@ import org.openide.nodes.PropertySupport; import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ProxyLookup; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.hashdatabase.AddContentToHashDbAction; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.DerivedFile; @@ -153,7 +153,7 @@ class KeywordSearchFilterNode extends FilterNode { actions.add(new HashSearchAction("Search for files with the same MD5 hash", getOriginal())); actions.add(null); // creates a menu separator actions.add(TagAbstractFileAction.getInstance()); - actions.add(AddContentToHashDbAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } From 58ce29be25e8af5bd19660ff64cf35873f18cadc Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 29 Oct 2013 18:43:27 -0400 Subject: [PATCH 15/30] Added XML file save to HasDb.openDatabase() --- .../src/org/sleuthkit/autopsy/hashdatabase/HashDb.java | 6 ++++-- .../autopsy/hashdatabase/HashDbImportDatabaseDialog.java | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index e86dcc2492..e92a40be1b 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -85,12 +85,14 @@ public class HashDb implements Comparable { } static private void addToXMLFile(HashDb database) { + HashDbXML xmlFileManager = HashDbXML.getCurrent(); if (database.getDbType() == HashDb.DBType.NSRL) { - HashDbXML.getCurrent().setNSRLSet(database); + xmlFileManager.setNSRLSet(database); } else { - HashDbXML.getCurrent().addKnownBadSet(database); + xmlFileManager.addKnownBadSet(database); } + xmlFileManager.save(); } static public List getUpdateableHashDatabases() { diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index 71d769f8df..910cd6cacb 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -306,7 +306,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { try { - HashDb db = HashDb.openHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + HashDb.openHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); } catch (TskException ex) { logger.log(Level.WARNING, "Invalid database: ", ex); JOptionPane.showMessageDialog(this, "Database file you chose cannot be opened.\n" + "If it was just an index, please try to recreate it from the database"); From 6bcbc2eb11c786e4f4baa70ad89ae952c420aac0 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 29 Oct 2013 19:44:20 -0400 Subject: [PATCH 16/30] Added needed space to an error message in AddContentToHashDbAction --- .../autopsy/hashdatabase/AddContentToHashDbAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index 250d44e0a5..c92f0722cd 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -121,7 +121,7 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente } 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 hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); } } } From 6fda5b6793ea7ace50f29251574d22245b19e6d5 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Wed, 30 Oct 2013 18:34:16 -0400 Subject: [PATCH 17/30] Fix compile error due to rename of newHashDatabase(). --- HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index e92a40be1b..3105e40296 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -79,7 +79,7 @@ public class HashDb implements Comparable { } static public HashDb createHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) throws TskCoreException { - HashDb database = new HashDb(SleuthkitJNI.newHashDatabase(databasePath), name, Collections.singletonList(databasePath), useForIngest, showInboxMessages, type); + HashDb database = new HashDb(SleuthkitJNI.createHashDatabase(databasePath), name, Collections.singletonList(databasePath), useForIngest, showInboxMessages, type); addToXMLFile(database); return database; } From 6407d3835f998ef2463f9c1686467f9cbcbdadb2 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 31 Oct 2013 09:56:25 -0400 Subject: [PATCH 18/30] Interim checkin of new hash db API work --- .../AddContentToHashDbAction.java | 2 +- .../autopsy/hashdatabase/HashDb.java | 91 ++++++-------- .../HashDbImportDatabaseDialog.java | 114 +++++++----------- .../hashdatabase/HashDbIngestModule.java | 4 +- .../hashdatabase/HashDbManagementPanel.java | 9 +- .../autopsy/hashdatabase/HashDbXML.java | 5 +- .../autopsy/hashdatabase/ModalNoButtons.form | 1 + 7 files changed, 92 insertions(+), 134 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index c92f0722cd..1715c15e52 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -117,7 +117,7 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente String md5Hash = file.getMd5Hash(); if (null != md5Hash) { try { - database.addContentHash(file); + database.addToHashDatabase(file); } catch (TskCoreException ex) { Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error adding to hash database", ex); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index e92a40be1b..d993eb2ff6 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -36,16 +36,12 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskException; /** - * Hash database representation of NSRL and Known Bad hash databases - * with indexing capability - * + * Instances of this class represent known file hash set databases. */ public class HashDb implements Comparable { - enum EVENT {INDEXING_DONE }; private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); - public enum DBType{ NSRL("NSRL"), KNOWN_BAD("Known Bad"); @@ -65,7 +61,7 @@ public class HashDb implements Comparable { private static final String INDEX_SUFFIX_OLD = "-md5.idx"; private String name; - private List databasePaths; // TODO: Only need a single path, may only need to store handle + private String databasePath; private boolean useForIngest; private boolean showInboxMessages; private boolean indexing; @@ -73,20 +69,20 @@ public class HashDb implements Comparable { private int handle; static public HashDb openHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) throws TskCoreException { - HashDb database = new HashDb(SleuthkitJNI.openHashDatabase(databasePath), name, Collections.singletonList(databasePath), useForIngest, showInboxMessages, type); + HashDb database = new HashDb(SleuthkitJNI.openHashDatabase(databasePath), name, databasePath, useForIngest, showInboxMessages, type); addToXMLFile(database); return database; } static public HashDb createHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) throws TskCoreException { - HashDb database = new HashDb(SleuthkitJNI.newHashDatabase(databasePath), name, Collections.singletonList(databasePath), useForIngest, showInboxMessages, type); + HashDb database = new HashDb(SleuthkitJNI.createHashDatabase(databasePath), name, databasePath, useForIngest, showInboxMessages, type); addToXMLFile(database); return database; } static private void addToXMLFile(HashDb database) { HashDbXML xmlFileManager = HashDbXML.getCurrent(); - if (database.getDbType() == HashDb.DBType.NSRL) { + if (database.getDbType() == DBType.NSRL) { xmlFileManager.setNSRLSet(database); } else { @@ -106,10 +102,10 @@ public class HashDb implements Comparable { return updateableDbs; } - private HashDb(int handle, String name, List databasePaths, boolean useForIngest, boolean showInboxMessages, DBType type) { + private HashDb(int handle, String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) { this.handle = handle; this.name = name; - this.databasePaths = databasePaths; + this.databasePath = databasePath; this.useForIngest = useForIngest; this.showInboxMessages = showInboxMessages; this.type = type; @@ -121,8 +117,9 @@ public class HashDb implements Comparable { return true; } - public void addContentHash(Content content) throws TskCoreException { - // @@@ This only works for AbstractFiles at present. + public void addToHashDatabase(Content content) throws TskCoreException { + // TODO: This only works for AbstractFiles at present. Change when Content + // can be queried for hashes. if (content instanceof AbstractFile) { AbstractFile file = (AbstractFile)content; if (null != file.getMd5Hash()) { @@ -155,8 +152,8 @@ public class HashDb implements Comparable { return name; } - List getDatabasePaths() { - return databasePaths; + String getDatabasePath() { + return databasePath; } void setUseForIngest(boolean useForIngest) { @@ -167,18 +164,6 @@ public class HashDb implements Comparable { this.showInboxMessages = showInboxMessages; } - void setName(String name) { - this.name = name; - } - - void setDatabasePaths(List databasePaths) { - this.databasePaths = databasePaths; - } - - void setDbType(DBType type) { - this.type = type; - } - /** * Checks if the database exists. * @return true if a file exists at the database path, else false @@ -193,9 +178,11 @@ public class HashDb implements Comparable { */ boolean indexExists() { try { - return hasIndex(databasePaths.get(0)); // TODO: support multiple paths - } catch (TskException ex) { - Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error checking if index exists.", ex); + // RJCTODO: Replace with new API call. + return SleuthkitJNI.lookupIndexExists(databasePath); + } + catch (TskException ex) { + Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error checking if index exists", ex); return false; } } @@ -205,7 +192,7 @@ public class HashDb implements Comparable { * @return a File initialized with the database path */ File databaseFile() { - return new File(databasePaths.get(0)); // TODO: don't support multiple paths + return new File(databasePath); } /** @@ -214,7 +201,7 @@ public class HashDb implements Comparable { * path */ File indexFile() { - return new File(toIndexPath(databasePaths.get(0))); // TODO: don't support multiple paths + return new File(toIndexPath(databasePath)); } /** @@ -224,6 +211,7 @@ public class HashDb implements Comparable { * file, else false */ boolean isOutdated() { + // RJCTODO: Need to adapt this to set status correctly File i = indexFile(); File db = databaseFile(); @@ -243,19 +231,25 @@ public class HashDb implements Comparable { * @return IndexStatus enum according to their definitions */ IndexStatus status() { - boolean i = this.indexExists(); - boolean db = this.databaseExists(); - - if(indexing) + // RJCTODO: Fix this using new API + + if (indexing) { return IndexStatus.INDEXING; - if (i) { - if (db) { + } + +// if (SleuthkitJNI.hashDatabaseIsLookupIndexOnly(handle)) { +// return databaseExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; +// } + + if (indexExists()) { + if (databaseExists()) { return this.isOutdated() ? IndexStatus.INDEX_OUTDATED : IndexStatus.INDEX_CURRENT; - } else { + } + else { return IndexStatus.NO_DB; } } else { - return db ? IndexStatus.NO_INDEX : IndexStatus.NONE; + return databaseExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; } } @@ -337,32 +331,21 @@ public class HashDb implements Comparable { return this.name.compareTo(o.name); } - /* Thread that creates a database's index */ private class CreateIndex extends SwingWorker { - private ProgressHandle progress; - CreateIndex(){}; + CreateIndex() { + }; @Override protected Object doInBackground() throws Exception { progress = ProgressHandleFactory.createHandle("Indexing " + name); - - /** We need proper cancel support in TSK to make the task cancellable - new Cancellable() { - Override - public boolean cancel() { - return CreateIndex.this.cancel(true); - } - }); - */ progress.start(); progress.switchToIndeterminate(); - SleuthkitJNI.createLookupIndex(databasePaths.get(0)); + SleuthkitJNI.createLookupIndex(databasePath); return null; } - /* clean up or start the worker threads */ @Override protected void done() { indexing = false; diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index 910cd6cacb..99428cc10e 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,35 +16,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.hashdatabase; import java.awt.Dimension; import java.awt.Toolkit; import java.io.File; import java.io.IOException; -import java.util.Arrays; 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 org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; -import org.sleuthkit.datamodel.SleuthkitJNI; -import org.sleuthkit.datamodel.TskException; +import org.sleuthkit.datamodel.TskCoreException; /** - * - * @author dfickling + * Instances of this class allow a user to select a hash database for import. */ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { + private JFileChooser fileChooser = new JFileChooser(); + private HashDb importedHashDatabase; - private JFileChooser fc = new JFileChooser(); - private String databaseName; - private static final Logger logger = Logger.getLogger(HashDbImportDatabaseDialog.class.getName()); - /** - * Creates new form HashDbImportDatabaseDialog - */ HashDbImportDatabaseDialog() { super(new javax.swing.JFrame(), "Import Hash Database", true); setResizable(false); @@ -53,27 +45,20 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { } void customizeComponents() { - fc.setDragEnabled(false); - fc.setFileSelectionMode(JFileChooser.FILES_ONLY); + 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); - fc.setFileFilter(filter); - fc.setMultiSelectionEnabled(false); + FileNameExtensionFilter filter = new FileNameExtensionFilter("Hash Database File", EXTENSION); + fileChooser.setFileFilter(filter); + fileChooser.setMultiSelectionEnabled(false); } - String display() { + HashDb display() { + // Center and display the dialog. Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); - - // set the popUp window / JFrame - int w = this.getSize().width; - int h = this.getSize().height; - - // set the location of the popUp Window on the center of the screen - setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); - + setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2); this.setVisible(true); - return databaseName; + return importedHashDatabase; } /** @@ -227,36 +212,21 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { }// //GEN-END:initComponents private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed - String oldText = databasePathTextField.getText(); - // set the current directory of the FileChooser if the databasePath Field is valid - File currentDir = new File(oldText); + File currentDir = new File(databasePathTextField.getText()); if (currentDir.exists()) { - fc.setCurrentDirectory(currentDir); + fileChooser.setCurrentDirectory(currentDir); } - int retval = fc.showOpenDialog(this); + int retval = fileChooser.showOpenDialog(this); if (retval == JFileChooser.APPROVE_OPTION) { - File f = fc.getSelectedFile(); + File f = fileChooser.getSelectedFile(); try { String filePath = f.getCanonicalPath(); - if (HashDb.isIndexPath(filePath)) { - filePath = HashDb.toDatabasePath(filePath); - } - String derivedName = SleuthkitJNI.getDatabaseName(filePath); databasePathTextField.setText(filePath); - databaseNameTextField.setText(derivedName); - if (derivedName.toLowerCase().contains("nsrl")) { - nsrlRadioButton.setSelected(true); - nsrlRadioButtonActionPerformed(null); - } - } catch (IOException ex) { - logger.log(Level.WARNING, "Couldn't get selected file path.", ex); - } catch (TskException ex) { - logger.log(Level.WARNING, "Invalid database: ", ex); - int tryAgain = JOptionPane.showConfirmDialog(this, "Database file you chose cannot be opened.\n" + "If it was just an index, please try to recreate it from the database.\n" + "Would you like to choose another database?", "Invalid File", JOptionPane.YES_NO_OPTION); - if (tryAgain == JOptionPane.YES_OPTION) { - browseButtonActionPerformed(evt); - } - } + databaseNameTextField.setText(HashDb.toDatabasePath(filePath)); + } + catch (IOException ex) { + Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Failed to get path of selected file", ex); + } } }//GEN-LAST:event_browseButtonActionPerformed @@ -279,46 +249,48 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { JOptionPane.showMessageDialog(this, "Database path cannot be empty"); return; } + if(databaseNameTextField.getText().isEmpty()) { - JOptionPane.showMessageDialog(this, "Database name cannot be empty"); + JOptionPane.showMessageDialog(this, "Database display name cannot be empty"); return; } + + String filePath; try { - File db = new File(databasePathTextField.getText()); - File idx = new File(databasePathTextField.getText() + ".kdb"); - File idx_old = new File(databasePathTextField.getText() + "-md5.idx"); - if (!db.exists() && !idx.exists() && !idx_old.exists()) { + File file = new File(databasePathTextField.getText()); + if (!file.exists()) { JOptionPane.showMessageDialog(this, "Selected file does not exist"); return; } - String path = db.getCanonicalPath(); - SleuthkitJNI.getDatabaseName(path); - } catch (Exception ex) { + filePath = file.getCanonicalPath(); + } + catch (IOException ex) { + Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Invalid database: ", ex); JOptionPane.showMessageDialog(this, "Database file you chose cannot be opened.\n" + "If it was just an index, please try to recreate it from the database"); return; } + DBType type; - if(nsrlRadioButton.isSelected()) { + if (nsrlRadioButton.isSelected()) { type = DBType.NSRL; - } else { + } + else { type = DBType.KNOWN_BAD; } - try - { - HashDb.openHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); - } catch (TskException ex) { - logger.log(Level.WARNING, "Invalid database: ", ex); + try { + importedHashDatabase = HashDb.openHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + } + catch (TskCoreException ex) { + Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Invalid database: ", ex); JOptionPane.showMessageDialog(this, "Database file you chose cannot be opened.\n" + "If it was just an index, please try to recreate it from the database"); return; } - - databaseName = databaseNameTextField.getText(); + this.dispose(); }//GEN-LAST:event_okButtonActionPerformed private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed - // TODO add your handling code here: }//GEN-LAST:event_useForIngestCheckboxActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java index 5d83630b62..dae714a6db 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java @@ -99,14 +99,14 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { if (nsrl != null && nsrl.getUseForIngest() && IndexStatus.isIngestible(nsrl.status())) { nsrlIsSet = true; this.nsrlSet = nsrl; - nsrlPointer = skCase.setNSRLDatabase(nsrl.getDatabasePaths().get(0)); + nsrlPointer = skCase.setNSRLDatabase(nsrl.getDatabasePath()); } for (HashDb db : hdbxml.getKnownBadSets()) { IndexStatus status = db.status(); if (db.getUseForIngest() && IndexStatus.isIngestible(status)) { knownBadIsSet = true; - int ret = skCase.addKnownBadDatabase(db.getDatabasePaths().get(0)); // TODO: support multiple paths + int ret = skCase.addKnownBadDatabase(db.getDatabasePath()); knownBadSets.put(ret, db); } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index 76ad80bbd9..812b6a3849 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -110,7 +110,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP } setButtonFromIndexStatus(this.indexButton, this.hashDbIndexStatusLabel, status); - String shortenPath = db.getDatabasePaths().get(0); + String shortenPath = db.getDatabasePath(); this.hashDbLocationLabel.setToolTipText(shortenPath); if(shortenPath.length() > 50){ shortenPath = shortenPath.substring(0, 10 + shortenPath.substring(10).indexOf(File.separator) + 1) + "..." + @@ -633,10 +633,11 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private javax.swing.JLabel typeLabel; private javax.swing.JCheckBox useForIngestCheckbox; // End of variables declaration//GEN-END:variables + private void importHashSet(java.awt.event.ActionEvent evt) { - String name = new HashDbImportDatabaseDialog().display(); - if(name != null) { - hashSetTableModel.selectRowByName(name); + HashDb hashDb = new HashDbImportDatabaseDialog().display(); + if (hashDb != null) { + hashSetTableModel.selectRowByName(hashDb.getName()); } resync(); } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java index e8f0ff8bee..fcff2bf385 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.hashdatabase; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.logging.Level; import javax.swing.JFileChooser; @@ -205,7 +206,7 @@ public class HashDbXML { for (HashDb set : knownBadSets) { String useForIngest = Boolean.toString(set.getUseForIngest()); String showInboxMessages = Boolean.toString(set.getShowInboxMessages()); - List paths = set.getDatabasePaths(); + List paths = Collections.singletonList(set.getDatabasePath()); String type = DBType.KNOWN_BAD.toString(); Element setEl = doc.createElement(SET_EL); @@ -227,7 +228,7 @@ public class HashDbXML { if(nsrlSet != null) { String useForIngest = Boolean.toString(nsrlSet.getUseForIngest()); String showInboxMessages = Boolean.toString(nsrlSet.getShowInboxMessages()); - List paths = nsrlSet.getDatabasePaths(); + List paths = Collections.singletonList(nsrlSet.getDatabasePath()); String type = DBType.NSRL.toString(); Element setEl = doc.createElement(SET_EL); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.form index df913c59e1..7ed52bedf9 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.form @@ -17,6 +17,7 @@ + From e7824e879fbe71f945995dcf6cd7040d4c4e4495 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Thu, 31 Oct 2013 16:52:24 -0400 Subject: [PATCH 19/30] Added new regression test for HashDB JNI operations. --- .../autopsy/testing/RegressionTest.java | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java index b7c798e4ea..af3ebc35c6 100644 --- a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java +++ b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java @@ -60,6 +60,9 @@ import org.netbeans.junit.NbModuleSuite; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.keywordsearch.*; +import org.sleuthkit.datamodel.SleuthkitJNI; +import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.datamodel.TskException; /** * This test expects the following system properties to be set: img_path: The @@ -93,7 +96,8 @@ public class RegressionTest extends TestCase { NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(RegressionTest.class). clusters(".*"). enableModules(".*"); - conf = conf.addTest("testNewCaseWizardOpen", + conf = conf.addTest("testHashDbJni", + "testNewCaseWizardOpen", "testNewCaseWizard", "testStartAddDataSource", "testConfigureIngest1", @@ -103,7 +107,8 @@ public class RegressionTest extends TestCase { "testAddSourceWizard1", "testIngest", "testGenerateReportToolbar", - "testGenerateReportButton"); + "testGenerateReportButton" + ); return NbModuleSuite.create(conf); @@ -125,6 +130,39 @@ public class RegressionTest extends TestCase { public void tearDown() { } + public void testHashDbJni() { + logger.info("HashDb JNI"); + try + { + String hashfn = "regtestHash.kdb"; + String md5hash = "b8c51089ebcdf9f11154a021438f5bd6"; + String md5hash2 = "cb4aca35f3fd54aacf96da9cd9acadb8"; + String md5hashBad = "35b299c6fcf47ece375b3221bdc16969"; + + logger.info("Creating hash db " + hashfn); + int handle = SleuthkitJNI.createHashDatabase(hashfn); + + logger.info("Adding hash " + md5hash); + SleuthkitJNI.addToHashDatabase("", md5hash, "", "", handle); + + logger.info("Adding hash " + md5hash2); + SleuthkitJNI.addToHashDatabase("", md5hash2, "", "", handle); + + logger.info("Querying for known hash " + md5hash); + TskData.FileKnown k = SleuthkitJNI.lookupInHashDatabase(md5hash, handle); + logger.info("Query result: " + k.toString()); + + logger.info("Querying for unknown hash " + md5hashBad); + TskData.FileKnown k2 = SleuthkitJNI.lookupInHashDatabase(md5hashBad, handle); + logger.info("Query result: " + k2.toString()); + + } catch (TskException ex) { + logger.log(Level.WARNING, "Database creation error: ", ex); + logger.info("A TskException occurred."); + return; + } + } + public void testNewCaseWizardOpen() { logger.info("New Case"); NbDialogOperator nbdo = new NbDialogOperator("Welcome"); From a3d5c123450f6551b21c1ff6d2d2888f4d1f7305 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 31 Oct 2013 21:02:31 -0400 Subject: [PATCH 20/30] Interim checkin --- .../AddContentToHashDbAction.java | 6 +- .../HashDatabaseOptionsPanelController.java | 2 +- .../autopsy/hashdatabase/HashDb.java | 341 +++++++----------- .../HashDbCreateDatabaseDialog.java | 20 +- .../HashDbImportDatabaseDialog.java | 10 +- .../hashdatabase/HashDbIngestModule.java | 22 +- .../hashdatabase/HashDbManagementPanel.java | 120 +++--- .../hashdatabase/HashDbSimplePanel.java | 80 ++-- .../autopsy/hashdatabase/HashDbXML.java | 242 +++++++++---- .../autopsy/hashdatabase/IndexStatus.java | 28 +- .../autopsy/hashdatabase/ModalNoButtons.java | 4 +- 11 files changed, 423 insertions(+), 452 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index 1715c15e52..ca4d481097 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -104,11 +104,11 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente // Get the current set of updateable hash databases and add each // one as a menu item. - List hashDatabases = HashDbXML.getCurrent().getKnownBadSets(); + List hashDatabases = HashDbXML.getInstance().getKnownBadSets(); if (!hashDatabases.isEmpty()) { - for (final HashDb database : HashDbXML.getCurrent().getKnownBadSets()) { + for (final HashDb database : HashDbXML.getInstance().getKnownBadSets()) { if (database.isUpdateable()) { - JMenuItem databaseItem = add(database.getName()); + JMenuItem databaseItem = add(database.getDisplayName()); databaseItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java index 2492db7d5f..7b81b5619f 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java @@ -55,7 +55,7 @@ public final class HashDatabaseOptionsPanelController extends OptionsPanelContro @Override public void cancel() { // Reset the XML on cancel - HashDbXML.getCurrent().reload(); + HashDbXML.getInstance().reload(); } @Override diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index d993eb2ff6..e791f3caac 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -20,108 +20,92 @@ package org.sleuthkit.autopsy.hashdatabase; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.logging.Level; 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.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskException; /** * Instances of this class represent known file hash set databases. */ +// TODO: Make this an inner class of a rewritten HashDbXML, and give it a private constructor. public class HashDb implements Comparable { - enum EVENT {INDEXING_DONE }; - private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + enum EVENT {INDEXING_DONE}; - public enum DBType{ - NSRL("NSRL"), KNOWN_BAD("Known Bad"); + enum KNOWN_FILES_HASH_SET_TYPE{ + NSRL("NSRL"), + KNOWN_BAD("Known Bad"); private String displayName; - private DBType(String displayName) { + private KNOWN_FILES_HASH_SET_TYPE(String displayName) { this.displayName = displayName; } - public String getDisplayName() { + String getDisplayName() { return this.displayName; } } - // Suffix added to the end of a database name to get its index file - private static final String INDEX_SUFFIX = ".kdb"; - private static final String INDEX_SUFFIX_OLD = "-md5.idx"; + private static final String INDEX_FILE_EXTENSION = ".kdb"; + private static final String LEGACY_INDEX_FILE_EXTENSION = "-md5.idx"; - private String name; + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + private String displayName; private String databasePath; private boolean useForIngest; private boolean showInboxMessages; - private boolean indexing; - private DBType type; + private KNOWN_FILES_HASH_SET_TYPE type; private int handle; + private boolean indexing; + private boolean acceptsUpdates = false; - static public HashDb openHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) throws TskCoreException { - HashDb database = new HashDb(SleuthkitJNI.openHashDatabase(databasePath), name, databasePath, useForIngest, showInboxMessages, type); - addToXMLFile(database); - return database; - } - - static public HashDb createHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) throws TskCoreException { - HashDb database = new HashDb(SleuthkitJNI.createHashDatabase(databasePath), name, databasePath, useForIngest, showInboxMessages, type); - addToXMLFile(database); - return database; - } - - static private void addToXMLFile(HashDb database) { - HashDbXML xmlFileManager = HashDbXML.getCurrent(); - if (database.getDbType() == DBType.NSRL) { - xmlFileManager.setNSRLSet(database); - } - else { - xmlFileManager.addKnownBadSet(database); - } - xmlFileManager.save(); - } - - static public List getUpdateableHashDatabases() { - ArrayList updateableDbs = new ArrayList<>(); - List candidateDbs = HashDbXML.getCurrent().getKnownBadSets(); - for (HashDb db : candidateDbs) { - if (db.isUpdateable()) { - updateableDbs.add(db); - } - } - return updateableDbs; - } - - private HashDb(int handle, String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) { - this.handle = handle; - this.name = name; + HashDb(int handle, String name, String databasePath, boolean useForIngest, boolean showInboxMessages, KNOWN_FILES_HASH_SET_TYPE type) { + this.displayName = name; this.databasePath = databasePath; this.useForIngest = useForIngest; this.showInboxMessages = showInboxMessages; this.type = type; + this.handle = handle; this.indexing = false; + + try { + acceptsUpdates = SleuthkitJNI.isUpdateableHashDatabase(this.handle); + } + catch (TskCoreException ex) { + // RJCTODO + acceptsUpdates = false; + } + } + + @Override + public int compareTo(HashDb o) { + return this.displayName.compareTo(o.displayName); + } + + /** + * Indicates whether the hash database accepts updates. + * @return True if the database accepts updates, false otherwise. + */ + boolean isUpdateable() { + return acceptsUpdates; } - public boolean isUpdateable() { - // RJCTODO: Complete this - return true; - } - + /** + * 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 addToHashDatabase(Content content) 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(), "", "", handle); } @@ -135,152 +119,62 @@ public class HashDb implements Comparable { void removePropertyChangeListener(PropertyChangeListener pcl) { pcs.removePropertyChangeListener(pcl); } - - boolean getUseForIngest() { - return useForIngest; - } - - boolean getShowInboxMessages() { - return showInboxMessages; - } - - DBType getDbType() { - return type; - } - - String getName() { - return name; + + String getDisplayName() { + return displayName; } String getDatabasePath() { return databasePath; } + KNOWN_FILES_HASH_SET_TYPE getKnownType() { + return type; + } + + boolean getUseForIngest() { + return useForIngest; + } + void setUseForIngest(boolean useForIngest) { this.useForIngest = useForIngest; } + + boolean getShowInboxMessages() { + return showInboxMessages; + } void setShowInboxMessages(boolean showInboxMessages) { this.showInboxMessages = showInboxMessages; } - - /** - * Checks if the database exists. - * @return true if a file exists at the database path, else false - */ - boolean databaseExists() { - return databaseFile().exists(); - } - - /** - * Checks if Sleuth Kit can open the index for the database path. - * @return true if the index was found and opened successfully, else false - */ - boolean indexExists() { + + boolean hasLookupIndex() { try { - // RJCTODO: Replace with new API call. - return SleuthkitJNI.lookupIndexExists(databasePath); - } - catch (TskException ex) { - Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error checking if index exists", ex); + return SleuthkitJNI.lookupIndexForHashDatabaseExists(handle); + } + catch (TskCoreException ex) { + // RJCTODO return false; } } - - /** - * Gets the database file. - * @return a File initialized with the database path - */ - File databaseFile() { - return new File(databasePath); + + boolean hasLegacyLookupIndexOnly() throws TskCoreException { + // RJCTODO: Add SleuthkitJNI call + return false; } - /** - * Gets the index file - * @return a File initialized with an index path derived from the database - * path - */ - File indexFile() { - return new File(toIndexPath(databasePath)); - } - - /** - * Checks if the index file is older than the database file - * @return true if there is are files at the index path and the database - * path, and the index file has an older modified-time than the database - * file, else false - */ - boolean isOutdated() { - // RJCTODO: Need to adapt this to set status correctly - File i = indexFile(); - File db = databaseFile(); - - return i.exists() && db.exists() && isOlderThan(i, db); + // TODO: This is a temporary expedient until HashDb becomes an inner class of HashDbXML. + void setAcceptsUpdates(boolean acceptsUpdates) { + this.acceptsUpdates = acceptsUpdates; } - /** - * Checks if the database is being indexed - */ - boolean isIndexing() { - return indexing; - } - - /** - * Returns the status of the HashDb as determined from indexExists(), - * databaseExists(), and isOutdated() - * @return IndexStatus enum according to their definitions - */ - IndexStatus status() { - // RJCTODO: Fix this using new API - - if (indexing) { - return IndexStatus.INDEXING; - } - -// if (SleuthkitJNI.hashDatabaseIsLookupIndexOnly(handle)) { -// return databaseExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; -// } - - if (indexExists()) { - if (databaseExists()) { - return this.isOutdated() ? IndexStatus.INDEX_OUTDATED : IndexStatus.INDEX_CURRENT; - } - else { - return IndexStatus.NO_DB; - } - } else { - return databaseExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; - } - } - - /** - * Tries to index the database (overwrites any existing index) - * @throws TskException if an error occurs in the SleuthKit bindings - */ - void createIndex() throws TskException { - indexing = true; - CreateIndex creator = new CreateIndex(); - creator.execute(); - } - - /** - * Checks if one file is older than an other - * @param a first file - * @param b second file - * @return true if the first file's last modified data is before the second - * file's last modified date - */ - private static boolean isOlderThan(File a, File b) { - return a.lastModified() < b.lastModified(); - } - /** * Determines if a path points to an index by checking the suffix * @param path * @return true if index */ static boolean isIndexPath(String path) { - return (path.endsWith(INDEX_SUFFIX) || path.endsWith(INDEX_SUFFIX_OLD)); + return (path.endsWith(INDEX_FILE_EXTENSION) || path.endsWith(LEGACY_INDEX_FILE_EXTENSION)); } /** @@ -289,10 +183,10 @@ public class HashDb implements Comparable { * @return */ static String toDatabasePath(String indexPath) { - if (indexPath.endsWith(INDEX_SUFFIX_OLD)) { - return indexPath.substring(0, indexPath.lastIndexOf(INDEX_SUFFIX_OLD)); + if (indexPath.endsWith(LEGACY_INDEX_FILE_EXTENSION)) { + return indexPath.substring(0, indexPath.lastIndexOf(LEGACY_INDEX_FILE_EXTENSION)); } else { - return indexPath.substring(0, indexPath.lastIndexOf(INDEX_SUFFIX)); + return indexPath.substring(0, indexPath.lastIndexOf(INDEX_FILE_EXTENSION)); } } @@ -302,35 +196,59 @@ public class HashDb implements Comparable { * @return */ static String toIndexPath(String databasePath) { - return databasePath.concat(INDEX_SUFFIX); + return databasePath.concat(INDEX_FILE_EXTENSION); + } + + boolean isIndexing() { + return indexing; } - /** - * Derives old-format index path from an database path by appending the suffix. - * @param databasePath - * @return - */ - static String toOldIndexPath(String databasePath) { - return databasePath.concat(INDEX_SUFFIX_OLD); - } - - /** - * Calls Sleuth Kit method via JNI to determine whether there is an - * index for the given path - * @param databasePath path Path for the database the index is of - * (database doesn't have to actually exist)' - * @return true if index exists - * @throws TskException if there is an error in the JNI call - */ - static boolean hasIndex(String databasePath) throws TskException { - return SleuthkitJNI.lookupIndexExists(databasePath); + IndexStatus getStatus() { + // RJCTODO: Fix this using new API + + if (indexing) { + return IndexStatus.INDEXING; + } + +// return new File(databasePath).exists(); + + +// return new File(toIndexPath(databasePath)); + + +// if (SleuthkitJNI.hashDatabaseIsLookupIndexOnly(handle)) { +// return databaseExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; +// } + +// return databasePath.concat(LEGACY_INDEX_FILE_EXTENSION); + + + // Outdated applies only to legacy databases where the legacy index file exists and is older +// File i = indexFile(); +// File db = new File(databasePath); +// +// return i.exists() && db.exists() && isOlderThan(i, db); +// +// if (indexExists()) { +// if (databaseSourceFileExists()) { +// return this.isOutdated() ? IndexStatus.INDEX_OUTDATED : IndexStatus.INDEX_CURRENT; +// } +// else { +// return IndexStatus.NO_DB; +// } +// } else { +// return databaseSourceFileExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; +// } + return IndexStatus.INDEXING; } - - @Override - public int compareTo(HashDb o) { - return this.name.compareTo(o.name); + + // Tries to index the database (overwrites any existing index) using a + // SwingWorker. + void createIndex() throws TskCoreException { + CreateIndex creator = new CreateIndex(); + creator.execute(); } - + private class CreateIndex extends SwingWorker { private ProgressHandle progress; @@ -339,10 +257,11 @@ public class HashDb implements Comparable { @Override protected Object doInBackground() throws Exception { - progress = ProgressHandleFactory.createHandle("Indexing " + name); + indexing = true; + progress = ProgressHandleFactory.createHandle("Indexing " + displayName); progress.start(); progress.switchToIndeterminate(); - SleuthkitJNI.createLookupIndex(databasePath); + SleuthkitJNI.createLookupIndexForHashDatabase(handle); return null; } @@ -350,7 +269,7 @@ public class HashDb implements Comparable { protected void done() { indexing = false; progress.finish(); - pcs.firePropertyChange(EVENT.INDEXING_DONE.toString(), null, name); + pcs.firePropertyChange(EVENT.INDEXING_DONE.toString(), null, displayName); } } } \ No newline at end of file diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index f17eabd0bd..43ca4be56c 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -29,8 +29,9 @@ 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.DBType; +import org.sleuthkit.autopsy.hashdatabase.HashDb.KNOWN_FILES_HASH_SET_TYPE; import org.sleuthkit.datamodel.SleuthkitJNI; +import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskException; /** @@ -40,7 +41,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { private JFileChooser fc; - private String databaseName; + private HashDb hashDb = null; private static final Logger logger = Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()); /** * Creates new form HashDbCreateDatabaseDialog @@ -78,7 +79,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { fc.setMultiSelectionEnabled(false); } - String display() { + HashDb display() { Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); // set the popUp window / JFrame @@ -89,7 +90,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); this.setVisible(true); - return databaseName; + return hashDb; } /** @@ -296,23 +297,22 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { return; } - DBType type; + KNOWN_FILES_HASH_SET_TYPE type; if(nsrlRadioButton.isSelected()) { - type = DBType.NSRL; + type = KNOWN_FILES_HASH_SET_TYPE.NSRL; } else { - type = DBType.KNOWN_BAD; + type = KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD; } try { - HashDb db = HashDb.createHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); - } catch (TskException ex) { + hashDb = HashDbXML.getInstance().createHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + } catch (TskCoreException ex) { logger.log(Level.WARNING, "Database creation error: ", ex); JOptionPane.showMessageDialog(this, "Database file cannot be created.\n"); return; } - databaseName = databaseNameTextField.getText(); this.dispose(); }//GEN-LAST:event_okButtonActionPerformed diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index 99428cc10e..f841d77101 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -27,7 +27,7 @@ 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.DBType; +import org.sleuthkit.autopsy.hashdatabase.HashDb.KNOWN_FILES_HASH_SET_TYPE; import org.sleuthkit.datamodel.TskCoreException; /** @@ -270,16 +270,16 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { return; } - DBType type; + KNOWN_FILES_HASH_SET_TYPE type; if (nsrlRadioButton.isSelected()) { - type = DBType.NSRL; + type = KNOWN_FILES_HASH_SET_TYPE.NSRL; } else { - type = DBType.KNOWN_BAD; + type = KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD; } try { - importedHashDatabase = HashDb.openHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + importedHashDatabase = HashDbXML.getInstance().importHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); } catch (TskCoreException ex) { Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Invalid database: ", ex); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java index dae714a6db..d4a1a2506f 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java @@ -87,23 +87,23 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { services = IngestServices.getDefault(); this.skCase = Case.getCurrentCase().getSleuthkitCase(); try { - HashDbXML hdbxml = HashDbXML.getCurrent(); + HashDbXML hdbxml = HashDbXML.getInstance(); nsrlSet = null; knownBadSets.clear(); - skCase.clearLookupDatabases(); + hdbxml.closeHashDatabases(); nsrlIsSet = false; knownBadIsSet = false; calcHashesIsSet = hdbxml.getCalculate(); HashDb nsrl = hdbxml.getNSRLSet(); - if (nsrl != null && nsrl.getUseForIngest() && IndexStatus.isIngestible(nsrl.status())) { + if (nsrl != null && nsrl.getUseForIngest() && IndexStatus.isIngestible(nsrl.getStatus())) { nsrlIsSet = true; this.nsrlSet = nsrl; nsrlPointer = skCase.setNSRLDatabase(nsrl.getDatabasePath()); } for (HashDb db : hdbxml.getKnownBadSets()) { - IndexStatus status = db.status(); + IndexStatus status = db.getStatus(); if (db.getUseForIngest() && IndexStatus.isIngestible(status)) { knownBadIsSet = true; int ret = skCase.addKnownBadDatabase(db.getDatabasePath()); @@ -140,7 +140,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { detailsSb.append("

Databases Used:

\n
    "); for (HashDb db : knownBadSets.values()) { - detailsSb.append("
  • ").append(db.getName()).append("
  • \n"); + detailsSb.append("
  • ").append(db.getDisplayName()).append("
  • \n"); } detailsSb.append("
"); @@ -151,7 +151,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { private void clearHashDatabaseHandles() { try { - skCase.clearLookupDatabases(); + HashDbXML.getInstance().closeHashDatabases(); } catch (TskCoreException ex) { logger.log(Level.WARNING, "Error clearing hash database handles. ", ex); } @@ -218,7 +218,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { @Override public javax.swing.JPanel getSimpleConfiguration(String context) { - HashDbXML.getCurrent().reload(); + HashDbXML.getInstance().reload(); return new HashDbSimplePanel(); } @@ -243,7 +243,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { @Override public void saveSimpleConfiguration() { - HashDbXML.getCurrent().save(); + HashDbXML.getInstance().save(); } private void processBadFile(AbstractFile abstractFile, String md5Hash, String hashSetName, boolean showInboxMessage) { @@ -343,7 +343,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { "Error encountered while setting known bad state for " + name + ".")); ret = ProcessResult.ERROR; } - String hashSetName = entry.getValue().getName(); + String hashSetName = entry.getValue().getDisplayName(); processBadFile(file, md5Hash, hashSetName, entry.getValue().getShowInboxMessages()); } } @@ -379,9 +379,9 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { public ArrayList getKnownBadSetNames() { ArrayList knownBadSetNames = new ArrayList<>(); - HashDbXML hdbxml = HashDbXML.getCurrent(); + HashDbXML hdbxml = HashDbXML.getInstance(); for (HashDb db : hdbxml.getKnownBadSets()) { - knownBadSetNames.add(db.getName()); + knownBadSetNames.add(db.getDisplayName()); } return knownBadSetNames; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index 812b6a3849..693d01f3b2 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -43,6 +43,7 @@ import javax.swing.table.TableCellRenderer; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.datamodel.TskCoreException; final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsPanel { @@ -77,7 +78,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP if (!listSelectionModel.isSelectionEmpty()) { int index = listSelectionModel.getMinSelectionIndex(); listSelectionModel.setSelectionInterval(index, index); - HashDbXML loader = HashDbXML.getCurrent(); + HashDbXML loader = HashDbXML.getInstance(); HashDb current = loader.getAllSets().get(index); initUI(current); } else { @@ -90,20 +91,20 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private void initUI(HashDb db) { boolean useForIngestEnabled = db != null && !ingestRunning; boolean useForIngestSelected = db != null && db.getUseForIngest(); - boolean showInboxMessagesEnabled = db != null && !ingestRunning && useForIngestSelected && db.getDbType().equals(HashDb.DBType.KNOWN_BAD); + boolean showInboxMessagesEnabled = db != null && !ingestRunning && useForIngestSelected && db.getKnownType().equals(HashDb.KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD); boolean showInboxMessagesSelected = db != null && db.getShowInboxMessages(); boolean deleteButtonEnabled = db != null && !ingestRunning; boolean importButtonEnabled = !ingestRunning; if (db == null) { - setButtonFromIndexStatus(this.indexButton, this.hashDbIndexStatusLabel, IndexStatus.NONE); + setButtonFromIndexStatus(this.indexButton, this.hashDbIndexStatusLabel, IndexStatus.NO_INDEX); this.hashDbLocationLabel.setText("No database selected"); this.hashDbNameLabel.setText("No database selected"); this.hashDbIndexStatusLabel.setText("No database selected"); this.hashDbTypeLabel.setText("No database selected"); } else { //check if dn in indexing state - String dbName = db.getName(); - IndexStatus status = db.status(); + String dbName = db.getDisplayName(); + IndexStatus status = db.getStatus(); Boolean state = indexingState.get(dbName); if (state != null && state.equals(Boolean.TRUE) ) { status = IndexStatus.INDEXING; @@ -117,8 +118,8 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP shortenPath.substring((shortenPath.length() - 20) + shortenPath.substring(shortenPath.length() - 20).indexOf(File.separator)); } this.hashDbLocationLabel.setText(shortenPath); - this.hashDbNameLabel.setText(db.getName()); - this.hashDbTypeLabel.setText(db.getDbType().getDisplayName()); + this.hashDbNameLabel.setText(db.getDisplayName()); + this.hashDbTypeLabel.setText(db.getKnownType().getDisplayName()); } this.useForIngestCheckbox.setSelected(useForIngestSelected); this.useForIngestCheckbox.setEnabled(useForIngestEnabled); @@ -142,7 +143,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP int selection = getSelection(); if(selection != -1) { - initUI(HashDbXML.getCurrent().getAllSets().get(selection)); + initUI(HashDbXML.getInstance().getAllSets().get(selection)); } } @@ -397,7 +398,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private void indexButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexButtonActionPerformed int selected = getSelection(); - final HashDb current = HashDbXML.getCurrent().getAllSets().get(selected); + final HashDb current = HashDbXML.getInstance().getAllSets().get(selected); current.addPropertyChangeListener(new PropertyChangeListener() { @Override @@ -406,19 +407,19 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP //update tracking of indexing status indexingState.put((String)evt.getNewValue(), Boolean.FALSE); - setButtonFromIndexStatus(indexButton, hashDbIndexStatusLabel, current.status()); + setButtonFromIndexStatus(indexButton, hashDbIndexStatusLabel, current.getStatus()); resync(); } } }); - indexingState.put(current.getName(), Boolean.TRUE); + indexingState.put(current.getDisplayName(), Boolean.TRUE); ModalNoButtons singleMNB = new ModalNoButtons(this, new Frame(), current); //Modal reference, to be removed later singleMNB.setLocationRelativeTo(null); singleMNB.setVisible(true); singleMNB.setModal(true); //End Modal reference - indexingState.put(current.getName(), Boolean.FALSE); - setButtonFromIndexStatus(indexButton, this.hashDbIndexStatusLabel, current.status()); + indexingState.put(current.getDisplayName(), Boolean.FALSE); + setButtonFromIndexStatus(indexButton, this.hashDbIndexStatusLabel, current.getStatus()); }//GEN-LAST:event_indexButtonActionPerformed private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed @@ -428,15 +429,15 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) { int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getCurrent(); + HashDbXML xmlHandle = HashDbXML.getInstance(); if (xmlHandle.getNSRLSet() != null) { if (selected == 0) { - HashDbXML.getCurrent().removeNSRLSet(); + HashDbXML.getInstance().removeNSRLSet(); } else { - HashDbXML.getCurrent().removeKnownBadSetAt(selected - 1); + HashDbXML.getInstance().removeKnownBadSetAt(selected - 1); } } else { - HashDbXML.getCurrent().removeKnownBadSetAt(selected); + HashDbXML.getInstance().removeKnownBadSetAt(selected); } hashSetTableModel.resync(); } @@ -445,15 +446,15 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private void hashSetTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_hashSetTableKeyPressed if (evt.getKeyCode() == KeyEvent.VK_DELETE) { int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getCurrent(); + HashDbXML xmlHandle = HashDbXML.getInstance(); if (xmlHandle.getNSRLSet() != null) { if (selected == 0) { - HashDbXML.getCurrent().removeNSRLSet(); + HashDbXML.getInstance().removeNSRLSet(); } else { - HashDbXML.getCurrent().removeKnownBadSetAt(selected - 1); + HashDbXML.getInstance().removeKnownBadSetAt(selected - 1); } } else { - HashDbXML.getCurrent().removeKnownBadSetAt(selected); + HashDbXML.getInstance().removeKnownBadSetAt(selected); } } hashSetTableModel.resync(); @@ -461,43 +462,43 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getCurrent(); + HashDbXML xmlHandle = HashDbXML.getInstance(); if (xmlHandle.getNSRLSet() != null) { if (selected == 0) { - HashDb current = HashDbXML.getCurrent().getNSRLSet(); + HashDb current = HashDbXML.getInstance().getNSRLSet(); current.setUseForIngest(useForIngestCheckbox.isSelected()); - HashDbXML.getCurrent().setNSRLSet(current); + HashDbXML.getInstance().setNSRLSet(current); } else { - HashDb current = HashDbXML.getCurrent().getKnownBadSets().remove(selected - 1); + HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected - 1); current.setUseForIngest(useForIngestCheckbox.isSelected()); - HashDbXML.getCurrent().addKnownBadSet(selected - 1, current); + HashDbXML.getInstance().addKnownBadSet(selected - 1, current); this.showInboxMessagesCheckBox.setEnabled(useForIngestCheckbox.isSelected()); } } else { - HashDb current = HashDbXML.getCurrent().getKnownBadSets().remove(selected); + HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected); current.setUseForIngest(useForIngestCheckbox.isSelected()); - HashDbXML.getCurrent().addKnownBadSet(selected, current); + HashDbXML.getInstance().addKnownBadSet(selected, current); this.showInboxMessagesCheckBox.setEnabled(useForIngestCheckbox.isSelected()); } }//GEN-LAST:event_useForIngestCheckboxActionPerformed private void showInboxMessagesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showInboxMessagesCheckBoxActionPerformed int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getCurrent(); + HashDbXML xmlHandle = HashDbXML.getInstance(); if (xmlHandle.getNSRLSet() != null) { if (selected == 0) { - HashDb current = HashDbXML.getCurrent().getNSRLSet(); + HashDb current = HashDbXML.getInstance().getNSRLSet(); current.setShowInboxMessages(showInboxMessagesCheckBox.isSelected()); - HashDbXML.getCurrent().setNSRLSet(current); + HashDbXML.getInstance().setNSRLSet(current); } else { - HashDb current = HashDbXML.getCurrent().getKnownBadSets().remove(selected - 1); + HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected - 1); current.setShowInboxMessages(showInboxMessagesCheckBox.isSelected()); - HashDbXML.getCurrent().addKnownBadSet(selected - 1, current); + HashDbXML.getInstance().addKnownBadSet(selected - 1, current); } } else { - HashDb current = HashDbXML.getCurrent().getKnownBadSets().remove(selected); + HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected); current.setShowInboxMessages(showInboxMessagesCheckBox.isSelected()); - HashDbXML.getCurrent().addKnownBadSet(selected, current); + HashDbXML.getInstance().addKnownBadSet(selected, current); } }//GEN-LAST:event_showInboxMessagesCheckBoxActionPerformed @@ -512,7 +513,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP @Override public void load() { hashSetTable.clearSelection(); // Deselect all rows - HashDbXML.getCurrent().reload(); // Reload XML + HashDbXML.getInstance().reload(); // Reload XML initUI(null); // Update the UI hashSetTableModel.resync(); // resync the table setIngestStatus(IngestManager.getDefault().isIngestRunning()); // check if ingest is running @@ -539,7 +540,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP else if (unindexed.size() > 1){ showInvalidIndex(true, unindexed); } - HashDbXML.getCurrent().save(); + HashDbXML.getInstance().save(); } @@ -550,18 +551,18 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP * @param toRemove a list of HashDbs that are unindexed */ void removeThese(List toRemove) { - HashDbXML xmlHandle = HashDbXML.getCurrent(); + HashDbXML xmlHandle = HashDbXML.getInstance(); for (HashDb hdb : toRemove) { for (int i = 0; i < hashSetTableModel.getRowCount(); i++) { if (hashSetTableModel.getDBAt(i).equals(hdb)) { if (xmlHandle.getNSRLSet() != null) { if (i == 0) { - HashDbXML.getCurrent().removeNSRLSet(); + HashDbXML.getInstance().removeNSRLSet(); } else { - HashDbXML.getCurrent().removeKnownBadSetAt(i - 1); + HashDbXML.getInstance().removeKnownBadSetAt(i - 1); } } else { - HashDbXML.getCurrent().removeKnownBadSetAt(i); + HashDbXML.getInstance().removeKnownBadSetAt(i); } hashSetTableModel.resync(); } @@ -579,7 +580,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP String total = ""; String message; for(HashDb hdb : unindexed){ - total+= "\n" + hdb.getName(); + total+= "\n" + hdb.getDisplayName(); } if(plural){ message = "The following databases are not indexed, would you like to index them now? \n " + total; @@ -637,15 +638,15 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private void importHashSet(java.awt.event.ActionEvent evt) { HashDb hashDb = new HashDbImportDatabaseDialog().display(); if (hashDb != null) { - hashSetTableModel.selectRowByName(hashDb.getName()); + hashSetTableModel.selectRowByName(hashDb.getDisplayName()); } resync(); } private void createHashSet(java.awt.event.ActionEvent evt) { - String name = new HashDbCreateDatabaseDialog().display(); - if(name != null) { - hashSetTableModel.selectRowByName(name); + HashDb hashDb = new HashDbCreateDatabaseDialog().display(); + if (null != hashDb) { + hashSetTableModel.selectRowByName(hashDb.getDisplayName()); } resync(); } @@ -675,7 +676,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private class HashSetTableModel extends AbstractTableModel { - private HashDbXML xmlHandle = HashDbXML.getCurrent(); + private HashDbXML xmlHandle = HashDbXML.getInstance(); @Override public int getColumnCount() { @@ -695,18 +696,17 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP @Override public Object getValueAt(int rowIndex, int columnIndex) { if(xmlHandle.getNSRLSet() == null) { - return getDBAt(rowIndex).getName(); + return getDBAt(rowIndex).getDisplayName(); } else { - return rowIndex == 0 ? getDBAt(rowIndex).getName() + " (NSRL)" : getDBAt(rowIndex).getName(); + return rowIndex == 0 ? getDBAt(rowIndex).getDisplayName() + " (NSRL)" : getDBAt(rowIndex).getDisplayName(); } } //Internal function for determining whether a companion -md5.idx file exists private boolean indexExists(int rowIndex){ - return getDBAt(rowIndex).indexExists(); + return getDBAt(rowIndex).hasLookupIndex(); } - - + //Internal function for getting the DB at a certain index. Used as-is, as well as by dispatch from getValueAt() and indexExists() private HashDb getDBAt(int rowIndex){ if (xmlHandle.getNSRLSet() != null) { @@ -725,18 +725,18 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP HashDb NSRL = xmlHandle.getNSRLSet(); List bad = xmlHandle.getKnownBadSets(); if(NSRL != null) { - if(NSRL.getName().equals(name)) { + if(NSRL.getDisplayName().equals(name)) { setSelection(0); } else { for(int i=0; i sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,18 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * HashDbSimplePanel.java - * - * Created on May 7, 2012, 10:38:26 AM - */ package org.sleuthkit.autopsy.hashdatabase; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; -import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; @@ -35,16 +28,13 @@ import javax.swing.table.TableColumn; import org.sleuthkit.autopsy.ingest.IngestManager; /** - * - * @author dfickling + * Instances of this class are used as a file ingest module configuration panel + * by the known files hash set lookup file ingest module. */ -public class HashDbSimplePanel extends javax.swing.JPanel { - - private static final Logger logger = Logger.getLogger(HashDbSimplePanel.class.getName()); +public class HashDbSimplePanel extends javax.swing.JPanel { private HashTableModel knownBadTableModel; private HashDb nsrl; - /** Creates new form HashDbSimplePanel */ public HashDbSimplePanel() { knownBadTableModel = new HashTableModel(); initComponents(); @@ -52,12 +42,9 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } private void reloadCalc() { - final HashDbXML xmlHandle = HashDbXML.getCurrent(); + final HashDbXML xmlHandle = HashDbXML.getInstance(); final HashDb nsrlDb = xmlHandle.getNSRLSet(); - final boolean nsrlUsed = - nsrlDb != null - && nsrlDb.getUseForIngest()== true - && nsrlDb.indexExists(); + final boolean nsrlUsed = nsrlDb != null && nsrlDb.getUseForIngest()== true && nsrlDb.hasLookupIndex(); final List knowns = xmlHandle.getKnownBadSets(); final boolean knownExists = !knowns.isEmpty(); boolean knownUsed = false; @@ -70,8 +57,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } } - if(! nsrlUsed - && ! knownUsed ) { + if (!nsrlUsed && !knownUsed ) { calcHashesButton.setEnabled(true); calcHashesButton.setSelected(true); xmlHandle.setCalculate(true); @@ -83,7 +69,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } private void customizeComponents() { - final HashDbXML xmlHandle = HashDbXML.getCurrent(); + final HashDbXML xmlHandle = HashDbXML.getInstance(); calcHashesButton.addActionListener( new ActionListener() { @Override @@ -93,8 +79,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } else { xmlHandle.setCalculate(false); } - } - + } }); notableHashTable.setModel(knownBadTableModel); @@ -104,7 +89,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { //customize column witdhs final int width1 = jScrollPane1.getPreferredSize().width; notableHashTable.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); - TableColumn column1 = null; + TableColumn column1; for (int i = 0; i < notableHashTable.getColumnCount(); i++) { column1 = notableHashTable.getColumnModel().getColumn(i); if (i == 0) { @@ -117,6 +102,24 @@ public class HashDbSimplePanel extends javax.swing.JPanel { reloadSets(); } + private void reloadSets() { + nsrl = HashDbXML.getInstance().getNSRLSet(); + + if (nsrl == null || nsrl.getUseForIngest() == false) { + nsrlDbLabelVal.setText("Disabled"); + } + else if (nsrl.hasLookupIndex() == false) { + nsrlDbLabelVal.setText("Disabled (No index)"); + } + else { + nsrlDbLabelVal.setText("Enabled"); + } + + reloadCalc(); + + knownBadTableModel.resync(); + } + /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is @@ -193,29 +196,9 @@ public class HashDbSimplePanel extends javax.swing.JPanel { private javax.swing.JLabel nsrlDbLabelVal; // End of variables declaration//GEN-END:variables - private void reloadSets() { - nsrl = HashDbXML.getCurrent().getNSRLSet(); - - if (nsrl == null || nsrl.getUseForIngest() == false) { - nsrlDbLabelVal.setText("Disabled"); - } - else if (nsrl.indexExists() == false) { - nsrlDbLabelVal.setText("Disabled (No index)"); - } - else { - nsrlDbLabelVal.setText("Enabled"); - } - - reloadCalc(); - - knownBadTableModel.resync(); - } - - - private class HashTableModel extends AbstractTableModel { - private HashDbXML xmlHandle = HashDbXML.getCurrent(); + private HashDbXML xmlHandle = HashDbXML.getInstance(); private void resync() { fireTableDataChanged(); @@ -245,7 +228,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { if (columnIndex == 0) { return db.getUseForIngest(); } else { - return db.getName(); + return db.getDisplayName(); } } } @@ -259,7 +242,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if(columnIndex == 0){ HashDb db = xmlHandle.getKnownBadSets().get(rowIndex); - if(((Boolean) getValueAt(rowIndex, columnIndex)) || IndexStatus.isIngestible(db.status())) { + if(((Boolean) getValueAt(rowIndex, columnIndex)) || IndexStatus.isIngestible(db.getStatus())) { db.setUseForIngest((Boolean) aValue); } else { JOptionPane.showMessageDialog(HashDbSimplePanel.this, "Databases must be indexed before they can be used for ingest"); @@ -272,6 +255,5 @@ public class HashDbSimplePanel extends javax.swing.JPanel { public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); } - } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java index fcff2bf385..fb527ec43f 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java @@ -33,13 +33,24 @@ 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.DBType; +import org.sleuthkit.autopsy.hashdatabase.HashDb.KNOWN_FILES_HASH_SET_TYPE; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; +/** + * This class is a singleton that handles the import and creation of known files + * hash set databases, manages the instances of the databases, and provides a + * means for persisting the configuration of the hash sets. + */ +// TODO: The class needs to renamed to something like HashDbManager - its use of +// XML as a configuration persistence mechanism should be an implementation detail +// hidden from its clients. More importantly, this class should be rewritten into +// full and true encapsulation of state and behavior rather than a mixture of a +// configuration manager with something that can be manipulated like a mere data +// structure by its clients. public class HashDbXML { private static final String ROOT_EL = "hash_sets"; private static final String SET_EL = "hash_set"; @@ -63,110 +74,171 @@ public class HashDbXML { private String xmlFile; private boolean calculate; - private HashDbXML(String xmlFile) { - knownBadSets = new ArrayList<>(); - this.xmlFile = xmlFile; - } - /** - * get instance for managing the current keyword list of the application + * Gets the singleton instance of this class. */ - static synchronized HashDbXML getCurrent() { + static synchronized HashDbXML getInstance() { if (currentInstance == null) { currentInstance = new HashDbXML(CUR_HASHSET_FILE); currentInstance.reload(); } return currentInstance; } + + private HashDbXML(String xmlFile) { + knownBadSets = new ArrayList<>(); + this.xmlFile = xmlFile; + } + + /** + * Imports an existing known files hash database. + * @param displayName Name used to represent the 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 type The known type of the database. + * @return A HashDb object representation of the new hash database. + * @throws TskCoreException + */ + // TODO: When this class is rewritten, this method should become private. It should add the HashDb object to the appropriate internal collection + // and to the XML file, and should save the XML file. + HashDb importHashDatabase(String displayName, String databasePath, boolean useForIngest, boolean showInboxMessages, KNOWN_FILES_HASH_SET_TYPE type) throws TskCoreException { + return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), displayName, databasePath, useForIngest, showInboxMessages, type); + } /** - * Get the hash sets + * Creates a new known files hash database. + * @param displayName Name used to represent the 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 type The known type of the database. + * @return A HashDb object representation of the opened hash database. + * @throws TskCoreException */ - public List getAllSets() { - List ret = new ArrayList<>(); - if(nsrlSet != null) { - ret.add(nsrlSet); - } - ret.addAll(knownBadSets); - return ret; + // TODO: When this class is rewritten, this method should become private. It should add the HashDb object to the appropriate internal collection + // and to the XML file, and should save the XML file. + HashDb createHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, KNOWN_FILES_HASH_SET_TYPE type) throws TskCoreException { + return new HashDb(SleuthkitJNI.createHashDatabase(databasePath), name, databasePath, useForIngest, showInboxMessages, type); } - - /** - * Get the Known Bad sets + + /** + * Sets the configured National Software Reference Library (NSRL) known + * files hash set. Does not save the configuration. */ - public List getKnownBadSets() { - return knownBadSets; + // TODO: When this class is rewritten, the class should be responsible for saving + // the configuration rather than deferring this responsibility to its clients. + public void setNSRLSet(HashDb set) { + this.nsrlSet = set; } - + /** - * Get the NSRL set + * Gets the configured National Software Reference Library (NSRL) known files hash set. + * @return A HashDb object representing the hash set or null if an NSRL set + * has not been added to the configuration. */ public HashDb getNSRLSet() { return nsrlSet; } - - /** - * Add a known bad hash set + + /** + * Removes the configured National Software Reference Library (NSRL) known + * files hash set. Does not save the configuration. */ + // TODO: When this class is rewritten, the class should be responsible for saving + // the configuration rather than deferring this responsibility to its clients. + public void removeNSRLSet() { + this.nsrlSet = null; + } + + /** + * Adds a known bad files hash set to the configuration. Does not save the + * configuration. + */ + // TODO: When this class is rewritten, the class should be responsible for saving + // the configuration rather than deferring this responsibility to its clients. public void addKnownBadSet(HashDb set) { knownBadSets.add(set); - //save(); } - + /** - * Add a known bad hash set + * Adds a known bad files hash set to the configuration. The set is added to + * the internal known bad sets collection at the index specified by the + * caller. Note that this method does not save the configuration. */ + // TODO: This method is an OO abomination that should be discarded when this + // class is rewritten. public void addKnownBadSet(int index, HashDb set) { knownBadSets.add(index, set); - //save(); } - - /** - * Set the NSRL hash set (override old set) + + /** + * Gets the configured known bad files hash sets. + * @return A list, possibly empty, of HashDb objects representing the hash + * sets. */ - public void setNSRLSet(HashDb set) { - this.nsrlSet = set; - //save(); - } - - /** - * Remove a hash known bad set - */ - public void removeKnownBadSetAt(int index) { - knownBadSets.remove(index); - //save(); + public List getKnownBadSets() { + return Collections.unmodifiableList(knownBadSets); } /** - * Remove the NSRL database + * Removes the known bad files hash set from the internal known bad files + * hash sets collection at the specified index. Does not save the configuration. */ - public void removeNSRLSet() { - this.nsrlSet = null; - //save(); + // TODO: This method is an OO abomination that should be replaced by a proper + // remove() when this class is rewritten. Also, the class should be responsible for saving + // the configuration rather than deferring this responsibility to its clients. + public void removeKnownBadSetAt(int index) { + knownBadSets.remove(index); + } + + /** + * Gets the configured known files hash sets that accept updates. + * @return A list, possibly empty, of HashDb objects. + */ + public List getUpdateableHashSets() { + ArrayList updateableDbs = new ArrayList<>(); + for (HashDb db : knownBadSets) { + if (db.isUpdateable()) { + updateableDbs.add(db); + } + } + return Collections.unmodifiableList(updateableDbs); + } + + /** + * Gets all of the configured known files hash sets. + * @return A list, possibly empty, of HashDb objects representing the hash + * sets. + */ + public List getAllSets() { + List hashDbs = new ArrayList<>(); + if (nsrlSet != null) { + hashDbs.add(nsrlSet); + } + hashDbs.addAll(knownBadSets); + return Collections.unmodifiableList(hashDbs); } /** - * load the file or create new + * Reloads the configuration file if it exists, creates it otherwise. */ + // TODO: When this class is rewritten, the class should be responsible for saving + // the configuration rather than deferring this responsibility to its clients. public void reload() { + // TODO: This does not look like it is correct. Revisit when time permits. boolean created = false; - - //TODO clearing the list causes a bug: we lose track of the state - //whether db is being indexed, we should somehow preserve the state when loading new HashDb objects - knownBadSets.clear(); nsrlSet = null; + knownBadSets.clear(); - if (!this.setsFileExists()) { - //create new if it doesn't exist + if (!setsFileExists()) { save(); created = true; } - //load, if fails to load create new; save regardless load(); if (!created) { - //create new if failed to load save(); } } @@ -175,22 +247,27 @@ public class HashDbXML { * Sets the local variable calculate to the given boolean. * @param set the state to make calculate */ + // TODO: Does this have any use? public void setCalculate(boolean set) { this.calculate = set; - //save(); } /** * Returns the value of the local boolean calculate. * @return true if calculate is true, false otherwise */ + // TODO: Does this have any use? public boolean getCalculate() { return this.calculate; } /** - * writes out current sets file replacing the last one + * Saves the known files hash sets configuration to disk. + * @return True on success, false otherwise. */ + // TODO: When this class is rewritten, the class should be responsible for saving + // the configuration rather than deferring this responsibility to its clients. + // It looks like there is code duplication here. public boolean save() { boolean success = false; @@ -203,14 +280,15 @@ public class HashDbXML { Element rootEl = doc.createElement(ROOT_EL); doc.appendChild(rootEl); + // TODO: Remove all the multiple database paths stuff, it was a mistake. for (HashDb set : knownBadSets) { String useForIngest = Boolean.toString(set.getUseForIngest()); String showInboxMessages = Boolean.toString(set.getShowInboxMessages()); List paths = Collections.singletonList(set.getDatabasePath()); - String type = DBType.KNOWN_BAD.toString(); + String type = KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD.toString(); Element setEl = doc.createElement(SET_EL); - setEl.setAttribute(SET_NAME_ATTR, set.getName()); + setEl.setAttribute(SET_NAME_ATTR, set.getDisplayName()); setEl.setAttribute(SET_TYPE_ATTR, type); setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, useForIngest); setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, showInboxMessages); @@ -225,14 +303,15 @@ public class HashDbXML { rootEl.appendChild(setEl); } + // TODO: Remove all the multiple database paths stuff, it was a mistake. if(nsrlSet != null) { String useForIngest = Boolean.toString(nsrlSet.getUseForIngest()); String showInboxMessages = Boolean.toString(nsrlSet.getShowInboxMessages()); List paths = Collections.singletonList(nsrlSet.getDatabasePath()); - String type = DBType.NSRL.toString(); + String type = KNOWN_FILES_HASH_SET_TYPE.NSRL.toString(); Element setEl = doc.createElement(SET_EL); - setEl.setAttribute(SET_NAME_ATTR, nsrlSet.getName()); + setEl.setAttribute(SET_NAME_ATTR, nsrlSet.getDisplayName()); setEl.setAttribute(SET_TYPE_ATTR, type); setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, useForIngest); setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, showInboxMessages); @@ -246,23 +325,22 @@ public class HashDbXML { } rootEl.appendChild(setEl); } - + + // TODO: Does this have any use? String calcValue = Boolean.toString(calculate); Element setCalc = doc.createElement(SET_CALC); setCalc.setAttribute(SET_VALUE, calcValue); rootEl.appendChild(setCalc); success = XMLUtil.saveDoc(HashDbXML.class, xmlFile, ENCODING, doc); - } catch (ParserConfigurationException e) { + } + catch (ParserConfigurationException e) { logger.log(Level.SEVERE, "Error saving hash sets: can't initialize parser.", e); } return success; } - /** - * load and parse XML, then dispose - */ - public boolean load() { + private boolean load() { final Document doc = XMLUtil.loadDoc(HashDbXML.class, xmlFile, XSDFILE); if (doc == null) { return false; @@ -288,8 +366,7 @@ public class HashDbXML { Boolean showInboxMessagesBool = Boolean.parseBoolean(showInboxMessages); List paths = new ArrayList<>(); - // Parse all paths - // @@@ TODO: There is no need for more than one path. + // TODO: Remove all the multiple database paths stuff, it was a mistake. NodeList pathsNList = setEl.getElementsByTagName(PATH_EL); final int numPaths = pathsNList.getLength(); for (int j = 0; j < numPaths; ++j) { @@ -336,12 +413,15 @@ public class HashDbXML { logger.log(Level.WARNING, "No paths were set for hash_set at index {0}. Removing the database.", i); } else { - DBType typeDBType = DBType.valueOf(type); + KNOWN_FILES_HASH_SET_TYPE typeDBType = KNOWN_FILES_HASH_SET_TYPE.valueOf(type); try { - // @@@ Note that this method calls back to addKnownBadSet() or setNSRLSet(). - // In the future, this class will become an inner class of HashDb and will only handle reading and - // writing the XML file. - HashDb.openHashDatabase(name, paths.get(0), useForIngestBool, showInboxMessagesBool, typeDBType); + HashDb db = importHashDatabase(name, paths.get(0), useForIngestBool, showInboxMessagesBool, typeDBType); + if (typeDBType == KNOWN_FILES_HASH_SET_TYPE.NSRL) { + setNSRLSet(db); + } + else { + addKnownBadSet(db); + } } catch (TskCoreException ex) { Logger.getLogger(HashDbXML.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); @@ -425,7 +505,13 @@ public class HashDbXML { private boolean setsFileExists() { File f = new File(xmlFile); return f.exists() && f.canRead() && f.canWrite(); - } - + } + /** + * Closes all open hash databases. + * @throws TskCoreException + */ + void closeHashDatabases() throws TskCoreException { + SleuthkitJNI.closeHashDatabases(); + } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java index cf02a9f326..9867257b68 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java @@ -26,29 +26,23 @@ package org.sleuthkit.autopsy.hashdatabase; enum IndexStatus { /** - * The index and database both exist, and the index is older. + * The index exists but the database does not. This indicates a text index + * without an accompanying text database. */ - INDEX_OUTDATED("WARNING: Index is older than database"), + INDEX_ONLY("Index only"), /** - * The index and database both exist, and the index is not older. + * The database exists but the index does not. This indicates a text database + * with no index. */ - INDEX_CURRENT("Database and index exist"), + NO_INDEX("No index"), /** - * The index exists but the database does not. + * The index is currently being generated. */ - NO_DB("Index exists (no database)"), + INDEXING("Index is currently being generated"), /** - * The database exists but the index does not. + * The index is generated. */ - NO_INDEX("ERROR: Index does not exist"), - /** - * Neither the index nor the database exists. - */ - NONE("ERROR: No index or database"), - /** - * The index is currently being generated - */ - INDEXING("Index is currently being generated"); + INDEXED("Indexed"); private String message; @@ -68,6 +62,6 @@ enum IndexStatus { } public static boolean isIngestible(IndexStatus status) { - return status == NO_DB || status == INDEX_CURRENT || status == INDEX_OUTDATED; + return status == INDEX_ONLY || status == INDEXED; } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java index 4a7862bea1..4d7e6f38c4 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java @@ -203,7 +203,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen */ private void indexThis() { this.INDEXING_PROGBAR.setIndeterminate(true); - currentDb = this.toIndex.getName(); + currentDb = this.toIndex.getDisplayName(); this.CURRENTDB_LABEL.setText("(" + currentDb + ")"); this.length = 1; this.CURRENTLYON_LABEL.setText("Currently indexing 1 database"); @@ -224,7 +224,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen length = this.unindexed.size(); this.INDEXING_PROGBAR.setIndeterminate(true); for (HashDb db : this.unindexed) { - currentDb = db.getName(); + currentDb = db.getDisplayName(); this.CURRENTDB_LABEL.setText("(" + currentDb + ")"); this.CURRENTLYON_LABEL.setText("Currently indexing 1 of " + length); if (!db.isIndexing()) { From 5b071ef991a6406593b06f3c645e6033aae5fd3a Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 1 Nov 2013 17:16:17 -0400 Subject: [PATCH 21/30] lookupIndexForHashDatabaseExists was renamed. --- HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index e791f3caac..de690820a9 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -150,7 +150,7 @@ public class HashDb implements Comparable { boolean hasLookupIndex() { try { - return SleuthkitJNI.lookupIndexForHashDatabaseExists(handle); + return SleuthkitJNI.hashDatabaseHasLegacyLookupIndexOnly(handle); } catch (TskCoreException ex) { // RJCTODO From f550722e6ae86fed2bfb66b9e47c02c5a69c16e9 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 1 Nov 2013 17:17:33 -0400 Subject: [PATCH 22/30] Rename "Create Database" button to "New Database" and change icon to be consistent with new keyword list. --- .../autopsy/hashdatabase/Bundle.properties | 2 +- .../hashdatabase/HashDbManagementPanel.form | 5 +---- .../hashdatabase/HashDbManagementPanel.java | 3 +-- .../org/sleuthkit/autopsy/hashdatabase/new16.png | Bin 0 -> 1661 bytes 4 files changed, 3 insertions(+), 7 deletions(-) create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/new16.png diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index e02678bfe5..822541f5fa 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -73,4 +73,4 @@ HashDbCreateDatabaseDialog.okButton.text=OK HashDbCreateDatabaseDialog.useForIngestCheckbox.text=Enable for ingest HashDbCreateDatabaseDialog.jLabel1.text=Display name of database: HashDbCreateDatabaseDialog.databaseNameTextField.text= -HashDbManagementPanel.importButton1.text=Create Database +HashDbManagementPanel.importButton1.text=New Database diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form index 6a5753371f..121d7644c8 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form @@ -385,14 +385,11 @@ - + - - - diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index 693d01f3b2..488286a794 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -280,9 +280,8 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.optionsLabel.text")); // NOI18N - importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/btn_icon_create_new_16.png"))); // NOI18N + importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/new16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.importButton1.text")); // NOI18N - importButton1.setMargin(new java.awt.Insets(2, 11, 2, 14)); importButton1.setMaximumSize(new java.awt.Dimension(140, 25)); importButton1.setMinimumSize(new java.awt.Dimension(140, 25)); importButton1.setPreferredSize(new java.awt.Dimension(140, 25)); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/new16.png b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/new16.png new file mode 100644 index 0000000000000000000000000000000000000000..f286d2b6c08f6d06e4d8143b9eabde178ae7c591 GIT binary patch literal 1661 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`Jj+tIX_n~5oC^DMQ#CujeSKy zVsdtBi9%9pdS;%jl7fPQl0s&Rtx~wDuYqrYb81GWM^#a3aFt(3a#eP+Wr~u$9hXgo z6;N|-YDuC(MQ%=Bu~mhw64*>DAR8pCucQE0Qj%?}1aWkPZ-9bxeo?A|iJqZuvVpOQ zf{B@)k-3qjxtWeaaAJvqS7M%mk-37AfdP;(vNANZGBE@?1`L$!xPY`xQA(Oskc%7C zP9V=#DWjyMz)D}gyu4hm+*mKaC|%#s($Z4jz)0W7NEfI=x41H|B(Xv_uUHvk2+SOp z)Z*l#%mQ$5fy_-z$}cUkRZ;?31P4&hB^JOf$}5Hj9xxd7D-sLz4fPE4;U)t$+5iQu zz!8yO6q28xV}~WqY(P3u6d`Oy=udS?EJ?KkhKGf&fswAEd5D3Lm9d$XiD?v)euyG8 z?Y{XbnQ4_s+KqLMOhODTtqcsTOpKt~krY9-+vtM=0x4j?p$_sBnz#ai082@RhgU&q zQ4Tm-Qj+ykb5e6t^Gb?=VP=RLW+};5Y57IDi6wTKxryni`UQFEHu?xbyzYaz8kj7A z$xbgQE&AS2kV>*VwVqd5hxeTe)u>*a{V2c<8CeJ_!oe z`f>1K%#VNjKgXU6WRR1y`@ccwb(^u;QWa03Nh%BD*4OXe_paW+_p`QwDZ}Yac{#t| zTG}Q`6j{h*Y>hgTw%Pi4;gz##&6%^}k3?Rz7d%qP(~x`HM2h$J=RMyU#2H%zI6hv# zx-B;@j<1~ImMTMN=*7~x3LF!H7G+AUT2*A|z~Q(y%=xm(k|`XDddy2Qxf&K}tXLJ* z#g)PNp;lf~_4LzCN>hTSotx{|Ubfp;fJLIM@%`_s96*=df6px7D#%bMb2-QCVySKM ztb3oT9x)im@U3pp=qiX6Kk+M$!ELdiPrjnK*n-tH@r+-pY`^`keVH!dwrz&RhJXYo zyXCH{

jf7WXFSTW}=-%N>w11Dz|$1@!=SaSRArrU454ty>?uv+O$>!eQcImYLnxNG$*UdpL w-#>o*UBCbH<;(dB*|$UW=A3`dpm#ui>Ee?P2bFSG0IL87Pgg&ebxsLQ06SFuDgXcg literal 0 HcmV?d00001 From 593cdef606c0af51daa7373812d9b890dbc1daf1 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 1 Nov 2013 17:27:53 -0400 Subject: [PATCH 23/30] Rearrange the HashDb mgmt buttons to be more consistent with Keyword List mgmt layout. --- .../hashdatabase/HashDbManagementPanel.form | 20 +++++++++---------- .../hashdatabase/HashDbManagementPanel.java | 17 ++++++++-------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form index 121d7644c8..5530d19c33 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form @@ -62,14 +62,7 @@ - - - - - - - - + @@ -115,7 +108,12 @@ - + + + + + + @@ -176,10 +174,10 @@ - + - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index 488286a794..6e4a2b17d9 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -300,12 +300,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(hashDatabasesLabel) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(importButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, 132, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 275, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addGroup(layout.createSequentialGroup() @@ -339,7 +334,11 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP .addComponent(useForIngestCheckbox) .addComponent(showInboxMessagesCheckBox) .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE))))) - .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(importButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap(40, Short.MAX_VALUE)) ); layout.setVerticalGroup( @@ -388,9 +387,9 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(importButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) ); }// //GEN-END:initComponents From 9bb68be4605790b44495997f05b07eae402ba786 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 1 Nov 2013 17:28:43 -0400 Subject: [PATCH 24/30] Do not change the file path when the user is trying to make a new database. --- .../autopsy/hashdatabase/HashDbCreateDatabaseDialog.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index 43ca4be56c..7cc74400c7 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -257,9 +257,6 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { try { String filePath = f.getCanonicalPath(); - if (HashDb.isIndexPath(filePath)) { - filePath = HashDb.toDatabasePath(filePath); - } String derivedName = f.getName(); databasePathTextField.setText(filePath); databaseNameTextField.setText(derivedName); From cda61becb93667c8912d7aeea537c68aae1f598c Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 4 Nov 2013 15:24:19 -0500 Subject: [PATCH 25/30] Fixed name of SleuthkitJNI method call in HashDb class --- HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index e791f3caac..91a86ab134 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -150,7 +150,7 @@ public class HashDb implements Comparable { boolean hasLookupIndex() { try { - return SleuthkitJNI.lookupIndexForHashDatabaseExists(handle); + return SleuthkitJNI.hashDatabaseHasLookupIndex(handle); } catch (TskCoreException ex) { // RJCTODO From d1ef3ae9df65be64c4b1bd21aac2dc7e012940cf Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 4 Nov 2013 18:25:02 -0500 Subject: [PATCH 26/30] First cut at fully integrated create hash database capability --- HashDatabase/nbproject/project.xml | 9 + .../AddContentToHashDbAction.java | 40 ++-- .../autopsy/hashdatabase/HashDb.java | 197 +++++++++--------- .../HashDbCreateDatabaseDialog.java | 108 ++++------ .../HashDbImportDatabaseDialog.java | 59 +++--- .../hashdatabase/HashDbIngestModule.java | 3 +- .../hashdatabase/HashDbManagementPanel.java | 51 +++-- .../hashdatabase/HashDbSimplePanel.java | 18 +- .../autopsy/hashdatabase/HashDbXML.java | 191 ++++++----------- .../autopsy/hashdatabase/ModalNoButtons.java | 2 +- 10 files changed, 313 insertions(+), 365 deletions(-) diff --git a/HashDatabase/nbproject/project.xml b/HashDatabase/nbproject/project.xml index 3a743f01d0..cedf7748b2 100644 --- a/HashDatabase/nbproject/project.xml +++ b/HashDatabase/nbproject/project.xml @@ -81,6 +81,15 @@ 7.0 + + org.sleuthkit.autopsy.corelibs + + + + 3 + 1.1 + + org.sleuthkit.autopsy.hashdatabase diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index ca4d481097..7f01819fdd 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -106,28 +106,26 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente // one as a menu item. List hashDatabases = HashDbXML.getInstance().getKnownBadSets(); if (!hashDatabases.isEmpty()) { - for (final HashDb database : HashDbXML.getInstance().getKnownBadSets()) { - if (database.isUpdateable()) { - JMenuItem databaseItem = add(database.getDisplayName()); - databaseItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); - for (AbstractFile file : selectedFiles) { - String md5Hash = file.getMd5Hash(); - if (null != md5Hash) { - try { - database.addToHashDatabase(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); - } - } - } + for (final HashDb database : HashDbXML.getInstance().getUpdateableHashSets()) { + JMenuItem databaseItem = add(database.getDisplayName()); + databaseItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + for (AbstractFile file : selectedFiles) { + String md5Hash = file.getMd5Hash(); + if (null != md5Hash) { + try { + database.add(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); + } + } } - }); - } + } + }); } } else { diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index 1c194a7541..024ea46764 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -27,21 +27,24 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; /** - * Instances of this class represent known file hash set databases. + * Instances of this class represent the hash databases underlying known files + * hash sets. */ -// TODO: Make this an inner class of a rewritten HashDbXML, and give it a private constructor. public class HashDb implements Comparable { - enum EVENT {INDEXING_DONE}; + public enum Event { + INDEXING_DONE + } - enum KNOWN_FILES_HASH_SET_TYPE{ + public enum KnownFilesType{ NSRL("NSRL"), KNOWN_BAD("Known Bad"); private String displayName; - private KNOWN_FILES_HASH_SET_TYPE(String displayName) { + private KnownFilesType(String displayName) { this.displayName = displayName; } @@ -50,20 +53,47 @@ public class HashDb implements Comparable { } } + /** + * Opens an existing 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 hash database should be used during ingest. + * @param showInboxMessages A flag indicating whether hash set hit messages should be sent to the application inbox. + * @param knownType The known files type of the database. + * @return A HashDb object representation of the new hash database. + * @throws TskCoreException + */ + public static HashDb openHashDatabase(String hashSetName, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType knownType) throws TskCoreException { + return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); + } + + /** + * Creates a new hash database. + * @param hashSetName Name used to represent the 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 knownType The known files type of 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 type) throws TskCoreException { + return new HashDb(SleuthkitJNI.createHashDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, type); + } + private static final String INDEX_FILE_EXTENSION = ".kdb"; private static final String LEGACY_INDEX_FILE_EXTENSION = "-md5.idx"; - private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); private String displayName; private String databasePath; private boolean useForIngest; private boolean showInboxMessages; - private KNOWN_FILES_HASH_SET_TYPE type; + private KnownFilesType type; private int handle; private boolean indexing; - private boolean acceptsUpdates = false; - HashDb(int handle, String name, String databasePath, boolean useForIngest, boolean showInboxMessages, KNOWN_FILES_HASH_SET_TYPE type) { + HashDb(int handle, String name, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType type) { this.displayName = name; this.databasePath = databasePath; this.useForIngest = useForIngest; @@ -71,14 +101,6 @@ public class HashDb implements Comparable { this.type = type; this.handle = handle; this.indexing = false; - - try { - acceptsUpdates = SleuthkitJNI.isUpdateableHashDatabase(this.handle); - } - catch (TskCoreException ex) { - // RJCTODO - acceptsUpdates = false; - } } @Override @@ -86,38 +108,12 @@ public class HashDb implements Comparable { return this.displayName.compareTo(o.displayName); } - /** - * Indicates whether the hash database accepts updates. - * @return True if the database accepts updates, false otherwise. - */ - boolean isUpdateable() { - return acceptsUpdates; - } - - /** - * 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 addToHashDatabase(Content content) 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(), "", "", handle); - } - } - } - void addPropertyChangeListener(PropertyChangeListener pcl) { - pcs.addPropertyChangeListener(pcl); + propertyChangeSupport.addPropertyChangeListener(pcl); } void removePropertyChangeListener(PropertyChangeListener pcl) { - pcs.removePropertyChangeListener(pcl); + propertyChangeSupport.removePropertyChangeListener(pcl); } String getDisplayName() { @@ -128,7 +124,7 @@ public class HashDb implements Comparable { return databasePath; } - KNOWN_FILES_HASH_SET_TYPE getKnownType() { + KnownFilesType getKnownFilesType() { return type; } @@ -158,37 +154,55 @@ public class HashDb implements Comparable { } } - boolean hasLegacyLookupIndexOnly() throws TskCoreException { + boolean hasTextLookupIndexOnly() throws TskCoreException { return SleuthkitJNI.hashDatabaseHasLegacyLookupIndexOnly(handle); } - // TODO: This is a temporary expedient until HashDb becomes an inner class of HashDbXML. - void setAcceptsUpdates(boolean acceptsUpdates) { - this.acceptsUpdates = acceptsUpdates; + /** + * 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); } /** - * Determines if a path points to an index by checking the suffix - * @param path - * @return true if index + * 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 */ - static boolean isIndexPath(String path) { - return (path.endsWith(INDEX_FILE_EXTENSION) || path.endsWith(LEGACY_INDEX_FILE_EXTENSION)); - } - - /** - * Derives database path from an image path by removing the suffix. - * @param indexPath - * @return - */ - static String toDatabasePath(String indexPath) { - if (indexPath.endsWith(LEGACY_INDEX_FILE_EXTENSION)) { - return indexPath.substring(0, indexPath.lastIndexOf(LEGACY_INDEX_FILE_EXTENSION)); - } else { - return indexPath.substring(0, indexPath.lastIndexOf(INDEX_FILE_EXTENSION)); + public void add(Content content) 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(), "", "", handle); + } } } - + + public TskData.FileKnown lookUp(Content content) throws TskCoreException { + TskData.FileKnown result = TskData.FileKnown.UKNOWN; + // 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()) { + if (type == KnownFilesType.NSRL) { + result = SleuthkitJNI.lookupInNSRLDatabase(file.getMd5Hash()); + } + else { + result = SleuthkitJNI.lookupInHashDatabase(file.getMd5Hash(), handle); + } + } + } + return result; + } + /** * Derives index path from an database path by appending the suffix. * @param databasePath @@ -202,43 +216,22 @@ public class HashDb implements Comparable { return indexing; } - IndexStatus getStatus() { - // RJCTODO: Fix this using new API + IndexStatus getStatus() throws TskCoreException { + IndexStatus status = IndexStatus.NO_INDEX; if (indexing) { - return IndexStatus.INDEXING; + status = IndexStatus.INDEXING; + } + else if (hasLookupIndex()) { + if (hasTextLookupIndexOnly()) { + status = IndexStatus.INDEX_ONLY; + } + else { + status = IndexStatus.INDEXED; + } } -// return new File(databasePath).exists(); - - -// return new File(toIndexPath(databasePath)); - - -// if (SleuthkitJNI.hashDatabaseIsLookupIndexOnly(handle)) { -// return databaseExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; -// } - -// return databasePath.concat(LEGACY_INDEX_FILE_EXTENSION); - - - // Outdated applies only to legacy databases where the legacy index file exists and is older -// File i = indexFile(); -// File db = new File(databasePath); -// -// return i.exists() && db.exists() && isOlderThan(i, db); -// -// if (indexExists()) { -// if (databaseSourceFileExists()) { -// return this.isOutdated() ? IndexStatus.INDEX_OUTDATED : IndexStatus.INDEX_CURRENT; -// } -// else { -// return IndexStatus.NO_DB; -// } -// } else { -// return databaseSourceFileExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; -// } - return IndexStatus.INDEXING; + return status; } // Tries to index the database (overwrites any existing index) using a @@ -268,7 +261,7 @@ public class HashDb implements Comparable { protected void done() { indexing = false; progress.finish(); - pcs.firePropertyChange(EVENT.INDEXING_DONE.toString(), null, displayName); + propertyChangeSupport.firePropertyChange(Event.INDEXING_DONE.toString(), null, displayName); } } } \ No newline at end of file diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index 7cc74400c7..86d01b8def 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -23,38 +23,33 @@ import java.awt.Dimension; import java.awt.Toolkit; import java.io.File; import java.io.IOException; -import java.util.Arrays; 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 org.sleuthkit.autopsy.hashdatabase.HashDb.KNOWN_FILES_HASH_SET_TYPE; -import org.sleuthkit.datamodel.SleuthkitJNI; +import org.apache.commons.io.FilenameUtils; +import org.sleuthkit.autopsy.hashdatabase.HashDb.KnownFilesType; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskException; -/** - * Creation is a different GUI class than importing - */ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { - - private JFileChooser fc; - - private HashDb hashDb = null; - private static final Logger logger = Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()); - /** - * Creates new form HashDbCreateDatabaseDialog - */ + private JFileChooser fileChooser; + private HashDb newHashDb = null; + HashDbCreateDatabaseDialog() { super(new javax.swing.JFrame(), "Create Hash Database", true); - setResizable(false); - - fc = new JFileChooser() { + setResizable(false); + fileChooser = new JFileChooser() { @Override public void approveSelection() { - File ftemp = getSelectedFile(); - if (ftemp.exists()) { + 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) { + 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) { cancelSelection(); @@ -70,27 +65,20 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } void customizeComponents() { - fc.setDragEnabled(false); - fc.setFileSelectionMode(JFileChooser.FILES_ONLY); + 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); - fc.setFileFilter(filter); - fc.setMultiSelectionEnabled(false); + FileNameExtensionFilter filter = new FileNameExtensionFilter("Hash Database File", EXTENSION); + fileChooser.setFileFilter(filter); + fileChooser.setMultiSelectionEnabled(false); } - HashDb display() { + HashDb doDialog() { + newHashDb = null; Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); - - // set the popUp window / JFrame - int w = this.getSize().width; - int h = this.getSize().height; - - // set the location of the popUp Window on the center of the screen - setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); - - this.setVisible(true); - return hashDb; + setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2); + this.setVisible(true); + return newHashDb; } /** @@ -245,28 +233,20 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { }// //GEN-END:initComponents private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed - String oldText = databasePathTextField.getText(); - // set the current directory of the FileChooser if the databasePath Field is valid - File currentDir = new File(oldText); - if (currentDir.exists()) { - fc.setCurrentDirectory(currentDir); - } - int retval = fc.showSaveDialog(this); - if (retval == JFileChooser.APPROVE_OPTION) { - File f = fc.getSelectedFile(); - - try { - String filePath = f.getCanonicalPath(); - String derivedName = f.getName(); - databasePathTextField.setText(filePath); - databaseNameTextField.setText(derivedName); - if (derivedName.toLowerCase().contains("nsrl")) { + 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")) { nsrlRadioButton.setSelected(true); nsrlRadioButtonActionPerformed(null); } - } catch (IOException ex) { - logger.log(Level.WARNING, "Couldn't get selected file path.", ex); - } + } + } + catch (IOException ex) { + Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, "Couldn't get selected file path.", ex); } }//GEN-LAST:event_browseButtonActionPerformed @@ -294,19 +274,20 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { return; } - KNOWN_FILES_HASH_SET_TYPE type; + KnownFilesType type; if(nsrlRadioButton.isSelected()) { - type = KNOWN_FILES_HASH_SET_TYPE.NSRL; + type = KnownFilesType.NSRL; } else { - type = KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD; + type = KnownFilesType.KNOWN_BAD; } try { - hashDb = HashDbXML.getInstance().createHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Database creation error: ", ex); - JOptionPane.showMessageDialog(this, "Database file cannot be created.\n"); + newHashDb = HashDb.createHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + } + catch (TskCoreException ex) { + Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.SEVERE, "Hash database creation error", ex); + JOptionPane.showMessageDialog(this, "Failed to create hash database."); return; } @@ -314,7 +295,6 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { }//GEN-LAST:event_okButtonActionPerformed private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed - // TODO add your handling code here: }//GEN-LAST:event_useForIngestCheckboxActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index f841d77101..42e8af23a8 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -27,15 +27,16 @@ 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.KNOWN_FILES_HASH_SET_TYPE; +import org.sleuthkit.autopsy.hashdatabase.HashDb.KnownFilesType; import org.sleuthkit.datamodel.TskCoreException; +import org.apache.commons.io.FilenameUtils; /** * Instances of this class allow a user to select a hash database for import. */ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private JFileChooser fileChooser = new JFileChooser(); - private HashDb importedHashDatabase; + private HashDb selectedHashDb; HashDbImportDatabaseDialog() { super(new javax.swing.JFrame(), "Import Hash Database", true); @@ -53,12 +54,15 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { fileChooser.setMultiSelectionEnabled(false); } - HashDb display() { + 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 importedHashDatabase; + + return selectedHashDb; } /** @@ -215,17 +219,15 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { File currentDir = new File(databasePathTextField.getText()); if (currentDir.exists()) { fileChooser.setCurrentDirectory(currentDir); - } - int retval = fileChooser.showOpenDialog(this); - if (retval == JFileChooser.APPROVE_OPTION) { - File f = fileChooser.getSelectedFile(); + } + if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + File databaseFile = fileChooser.getSelectedFile(); try { - String filePath = f.getCanonicalPath(); - databasePathTextField.setText(filePath); - databaseNameTextField.setText(HashDb.toDatabasePath(filePath)); + databasePathTextField.setText(databaseFile.getCanonicalPath()); + databaseNameTextField.setText(FilenameUtils.removeExtension(databaseFile.getName())); } catch (IOException ex) { - Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Failed to get path of selected file", ex); + Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Failed to get path of selected database", ex); } } }//GEN-LAST:event_browseButtonActionPerformed @@ -246,44 +248,45 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed if(databasePathTextField.getText().isEmpty()) { - JOptionPane.showMessageDialog(this, "Database path cannot be empty"); + JOptionPane.showMessageDialog(this, "Database path cannot be empty."); return; } if(databaseNameTextField.getText().isEmpty()) { - JOptionPane.showMessageDialog(this, "Database display name cannot be empty"); + JOptionPane.showMessageDialog(this, "Database display name cannot be empty."); return; } - + + File file = new File(databasePathTextField.getText()); + if (!file.exists()) { + JOptionPane.showMessageDialog(this, "Selected database does not exist."); + return; + } + String filePath; try { - File file = new File(databasePathTextField.getText()); - if (!file.exists()) { - JOptionPane.showMessageDialog(this, "Selected file does not exist"); - return; - } filePath = file.getCanonicalPath(); } catch (IOException ex) { - Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Invalid database: ", ex); - JOptionPane.showMessageDialog(this, "Database file you chose cannot be opened.\n" + "If it was just an index, please try to recreate it from the database"); + 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; } - KNOWN_FILES_HASH_SET_TYPE type; + KnownFilesType type; if (nsrlRadioButton.isSelected()) { - type = KNOWN_FILES_HASH_SET_TYPE.NSRL; + type = KnownFilesType.NSRL; } else { - type = KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD; + type = KnownFilesType.KNOWN_BAD; } try { - importedHashDatabase = HashDbXML.getInstance().importHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + selectedHashDb = HashDb.openHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); } catch (TskCoreException ex) { - Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Invalid database: ", ex); - JOptionPane.showMessageDialog(this, "Database file you chose cannot be opened.\n" + "If it was just an index, please try to recreate it from the database"); + 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."); return; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java index d4a1a2506f..a39292889d 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java @@ -90,10 +90,9 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { HashDbXML hdbxml = HashDbXML.getInstance(); nsrlSet = null; knownBadSets.clear(); - hdbxml.closeHashDatabases(); nsrlIsSet = false; knownBadIsSet = false; - calcHashesIsSet = hdbxml.getCalculate(); + calcHashesIsSet = hdbxml.shouldAlwaysCalculateHashes(); HashDb nsrl = hdbxml.getNSRLSet(); if (nsrl != null && nsrl.getUseForIngest() && IndexStatus.isIngestible(nsrl.getStatus())) { diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index 6e4a2b17d9..43afd118c1 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -91,7 +91,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private void initUI(HashDb db) { boolean useForIngestEnabled = db != null && !ingestRunning; boolean useForIngestSelected = db != null && db.getUseForIngest(); - boolean showInboxMessagesEnabled = db != null && !ingestRunning && useForIngestSelected && db.getKnownType().equals(HashDb.KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD); + boolean showInboxMessagesEnabled = db != null && !ingestRunning && useForIngestSelected && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD); boolean showInboxMessagesSelected = db != null && db.getShowInboxMessages(); boolean deleteButtonEnabled = db != null && !ingestRunning; boolean importButtonEnabled = !ingestRunning; @@ -104,7 +104,13 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP } else { //check if dn in indexing state String dbName = db.getDisplayName(); - IndexStatus status = db.getStatus(); + IndexStatus status = IndexStatus.NO_INDEX; + try { + status = db.getStatus(); + } + catch (TskCoreException ex) { + // RJCTODO + } Boolean state = indexingState.get(dbName); if (state != null && state.equals(Boolean.TRUE) ) { status = IndexStatus.INDEXING; @@ -119,7 +125,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP } this.hashDbLocationLabel.setText(shortenPath); this.hashDbNameLabel.setText(db.getDisplayName()); - this.hashDbTypeLabel.setText(db.getKnownType().getDisplayName()); + this.hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); } this.useForIngestCheckbox.setSelected(useForIngestSelected); this.useForIngestCheckbox.setEnabled(useForIngestEnabled); @@ -401,23 +407,36 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP @Override public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(HashDb.EVENT.INDEXING_DONE.toString())) { + if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) { //update tracking of indexing status indexingState.put((String)evt.getNewValue(), Boolean.FALSE); - - setButtonFromIndexStatus(indexButton, hashDbIndexStatusLabel, current.getStatus()); + IndexStatus status = IndexStatus.NO_INDEX; + try { + status = current.getStatus(); + } + catch (TskCoreException ex) { + // RJCTODO + } + setButtonFromIndexStatus(indexButton, hashDbIndexStatusLabel, status); resync(); } } }); - indexingState.put(current.getDisplayName(), Boolean.TRUE); - ModalNoButtons singleMNB = new ModalNoButtons(this, new Frame(), current); //Modal reference, to be removed later - singleMNB.setLocationRelativeTo(null); - singleMNB.setVisible(true); - singleMNB.setModal(true); //End Modal reference - indexingState.put(current.getDisplayName(), Boolean.FALSE); - setButtonFromIndexStatus(indexButton, this.hashDbIndexStatusLabel, current.getStatus()); + indexingState.put(current.getDisplayName(), Boolean.TRUE); + ModalNoButtons singleMNB = new ModalNoButtons(this, new Frame(), current); //Modal reference, to be removed later + singleMNB.setLocationRelativeTo(null); + singleMNB.setVisible(true); + singleMNB.setModal(true); //End Modal reference + indexingState.put(current.getDisplayName(), Boolean.FALSE); + IndexStatus status = IndexStatus.NO_INDEX; + try { + status = current.getStatus(); + } + catch (TskCoreException ex) { + // RJCTODO + } + setButtonFromIndexStatus(indexButton, this.hashDbIndexStatusLabel, status); }//GEN-LAST:event_indexButtonActionPerformed private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed @@ -634,16 +653,18 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP // End of variables declaration//GEN-END:variables private void importHashSet(java.awt.event.ActionEvent evt) { - HashDb hashDb = new HashDbImportDatabaseDialog().display(); + HashDb hashDb = new HashDbImportDatabaseDialog().doDialog(); if (hashDb != null) { + HashDbXML.getInstance().addSet(hashDb); hashSetTableModel.selectRowByName(hashDb.getDisplayName()); } resync(); } private void createHashSet(java.awt.event.ActionEvent evt) { - HashDb hashDb = new HashDbCreateDatabaseDialog().display(); + HashDb hashDb = new HashDbCreateDatabaseDialog().doDialog(); if (null != hashDb) { + HashDbXML.getInstance().addSet(hashDb); hashSetTableModel.selectRowByName(hashDb.getDisplayName()); } resync(); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java index c1b82a8f89..81c2adac37 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java @@ -26,6 +26,7 @@ import javax.swing.JTable; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableColumn; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this class are used as a file ingest module configuration panel @@ -60,11 +61,11 @@ public class HashDbSimplePanel extends javax.swing.JPanel { if (!nsrlUsed && !knownUsed ) { calcHashesButton.setEnabled(true); calcHashesButton.setSelected(true); - xmlHandle.setCalculate(true); + xmlHandle.setShouldAlwaysCalculateHashes(true); } else { calcHashesButton.setEnabled(false); calcHashesButton.setSelected(false); - xmlHandle.setCalculate(false); + xmlHandle.setShouldAlwaysCalculateHashes(false); } } @@ -75,9 +76,9 @@ public class HashDbSimplePanel extends javax.swing.JPanel { @Override public void actionPerformed(ActionEvent e) { if(calcHashesButton.isSelected()) { - xmlHandle.setCalculate(true); + xmlHandle.setShouldAlwaysCalculateHashes(true); } else { - xmlHandle.setCalculate(false); + xmlHandle.setShouldAlwaysCalculateHashes(false); } } }); @@ -242,7 +243,14 @@ public class HashDbSimplePanel extends javax.swing.JPanel { public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if(columnIndex == 0){ HashDb db = xmlHandle.getKnownBadSets().get(rowIndex); - if(((Boolean) getValueAt(rowIndex, columnIndex)) || IndexStatus.isIngestible(db.getStatus())) { + IndexStatus status = IndexStatus.NO_INDEX; + try { + status = db.getStatus(); + } + catch (TskCoreException ex) { + // RJCTODO + } + if(((Boolean) getValueAt(rowIndex, columnIndex)) || IndexStatus.isIngestible(status)) { db.setUseForIngest((Boolean) aValue); } else { JOptionPane.showMessageDialog(HashDbSimplePanel.this, "Databases must be indexed before they can be used for ingest"); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java index fb527ec43f..e333e0c1f7 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java @@ -33,7 +33,7 @@ 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.KNOWN_FILES_HASH_SET_TYPE; +import org.sleuthkit.autopsy.hashdatabase.HashDb.KnownFilesType; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; import org.w3c.dom.Document; @@ -41,16 +41,10 @@ import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** - * This class is a singleton that handles the import and creation of known files - * hash set databases, manages the instances of the databases, and provides a - * means for persisting the configuration of the hash sets. + * This class is a singleton that manages the configuration of the hash databases + * that serve as hash sets for the identification of known files, known good files, + * and known bad files. */ -// TODO: The class needs to renamed to something like HashDbManager - its use of -// XML as a configuration persistence mechanism should be an implementation detail -// hidden from its clients. More importantly, this class should be rewritten into -// full and true encapsulation of state and behavior rather than a mixture of a -// configuration manager with something that can be manipulated like a mere data -// structure by its clients. public class HashDbXML { private static final String ROOT_EL = "hash_sets"; private static final String SET_EL = "hash_set"; @@ -63,71 +57,45 @@ public class HashDbXML { private static final String CUR_HASHSETS_FILE_NAME = "hashsets.xml"; private static final String XSDFILE = "HashsetsSchema.xsd"; private static final String ENCODING = "UTF-8"; - private static final String CUR_HASHSET_FILE = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME; private static final String SET_CALC = "hash_calculate"; private static final String SET_VALUE = "value"; private static final Logger logger = Logger.getLogger(HashDbXML.class.getName()); - private static HashDbXML currentInstance; - - private List knownBadSets; + private static HashDbXML instance; + private List knownBadSets = new ArrayList<>(); private HashDb nsrlSet; - private String xmlFile; - private boolean calculate; + private boolean alwaysCalculateHashes; + private String xmlFile = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME; /** * Gets the singleton instance of this class. */ - static synchronized HashDbXML getInstance() { - if (currentInstance == null) { - currentInstance = new HashDbXML(CUR_HASHSET_FILE); - currentInstance.reload(); + public static synchronized HashDbXML getInstance() { + if (instance == null) { + instance = new HashDbXML(); + instance.reload(); } - return currentInstance; + return instance; } - private HashDbXML(String xmlFile) { - knownBadSets = new ArrayList<>(); - this.xmlFile = xmlFile; + private HashDbXML() { } - + /** - * Imports an existing known files hash database. - * @param displayName Name used to represent the 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 type The known type of the database. - * @return A HashDb object representation of the new hash database. - * @throws TskCoreException + * Adds a hash database to the hash set configuration. */ - // TODO: When this class is rewritten, this method should become private. It should add the HashDb object to the appropriate internal collection - // and to the XML file, and should save the XML file. - HashDb importHashDatabase(String displayName, String databasePath, boolean useForIngest, boolean showInboxMessages, KNOWN_FILES_HASH_SET_TYPE type) throws TskCoreException { - return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), displayName, databasePath, useForIngest, showInboxMessages, type); + public void addSet(HashDb set) { + if (set.getKnownFilesType() == HashDb.KnownFilesType.NSRL) { + setNSRLSet(set); + } + else { + addKnownBadSet(set); + } } - /** - * Creates a new known files hash database. - * @param displayName Name used to represent the 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 type The known type of the database. - * @return A HashDb object representation of the opened hash database. - * @throws TskCoreException - */ - // TODO: When this class is rewritten, this method should become private. It should add the HashDb object to the appropriate internal collection - // and to the XML file, and should save the XML file. - HashDb createHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, KNOWN_FILES_HASH_SET_TYPE type) throws TskCoreException { - return new HashDb(SleuthkitJNI.createHashDatabase(databasePath), name, databasePath, useForIngest, showInboxMessages, type); - } - /** * Sets the configured National Software Reference Library (NSRL) known * files hash set. Does not save the configuration. */ - // TODO: When this class is rewritten, the class should be responsible for saving - // the configuration rather than deferring this responsibility to its clients. public void setNSRLSet(HashDb set) { this.nsrlSet = set; } @@ -145,8 +113,6 @@ public class HashDbXML { * Removes the configured National Software Reference Library (NSRL) known * files hash set. Does not save the configuration. */ - // TODO: When this class is rewritten, the class should be responsible for saving - // the configuration rather than deferring this responsibility to its clients. public void removeNSRLSet() { this.nsrlSet = null; } @@ -155,8 +121,6 @@ public class HashDbXML { * Adds a known bad files hash set to the configuration. Does not save the * configuration. */ - // TODO: When this class is rewritten, the class should be responsible for saving - // the configuration rather than deferring this responsibility to its clients. public void addKnownBadSet(HashDb set) { knownBadSets.add(set); } @@ -166,8 +130,6 @@ public class HashDbXML { * the internal known bad sets collection at the index specified by the * caller. Note that this method does not save the configuration. */ - // TODO: This method is an OO abomination that should be discarded when this - // class is rewritten. public void addKnownBadSet(int index, HashDb set) { knownBadSets.add(index, set); } @@ -185,9 +147,6 @@ public class HashDbXML { * Removes the known bad files hash set from the internal known bad files * hash sets collection at the specified index. Does not save the configuration. */ - // TODO: This method is an OO abomination that should be replaced by a proper - // remove() when this class is rewritten. Also, the class should be responsible for saving - // the configuration rather than deferring this responsibility to its clients. public void removeKnownBadSetAt(int index) { knownBadSets.remove(index); } @@ -199,8 +158,13 @@ public class HashDbXML { public List getUpdateableHashSets() { ArrayList updateableDbs = new ArrayList<>(); for (HashDb db : knownBadSets) { - if (db.isUpdateable()) { - updateableDbs.add(db); + try { + if (db.isUpdateable()) { + updateableDbs.add(db); + } + } + catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error checking updateable status of " + db.getDatabasePath(), ex); } } return Collections.unmodifiableList(updateableDbs); @@ -223,8 +187,6 @@ public class HashDbXML { /** * Reloads the configuration file if it exists, creates it otherwise. */ - // TODO: When this class is rewritten, the class should be responsible for saving - // the configuration rather than deferring this responsibility to its clients. public void reload() { // TODO: This does not look like it is correct. Revisit when time permits. boolean created = false; @@ -244,30 +206,27 @@ public class HashDbXML { } /** - * Sets the local variable calculate to the given boolean. - * @param set the state to make calculate + * Sets the value for the flag indicates whether hashes should be calculated + * for content even if no hash databases are configured. */ - // TODO: Does this have any use? - public void setCalculate(boolean set) { - this.calculate = set; + public void setShouldAlwaysCalculateHashes(boolean alwaysCalculateHashes) { + this.alwaysCalculateHashes = alwaysCalculateHashes; } /** - * Returns the value of the local boolean calculate. - * @return true if calculate is true, false otherwise + * Accesses the flag that indicates whether hashes should be calculated + * for content even if no hash databases are configured. */ - // TODO: Does this have any use? - public boolean getCalculate() { - return this.calculate; + public boolean shouldAlwaysCalculateHashes() { + return alwaysCalculateHashes; } /** - * Saves the known files hash sets configuration to disk. + * Saves the known files hash sets configuration to disk. Note that the + * configuration is only saved on demand to support cancellation of + * configuration panels and dialogs. * @return True on success, false otherwise. */ - // TODO: When this class is rewritten, the class should be responsible for saving - // the configuration rather than deferring this responsibility to its clients. - // It looks like there is code duplication here. public boolean save() { boolean success = false; @@ -285,7 +244,7 @@ public class HashDbXML { String useForIngest = Boolean.toString(set.getUseForIngest()); String showInboxMessages = Boolean.toString(set.getShowInboxMessages()); List paths = Collections.singletonList(set.getDatabasePath()); - String type = KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD.toString(); + String type = KnownFilesType.KNOWN_BAD.toString(); Element setEl = doc.createElement(SET_EL); setEl.setAttribute(SET_NAME_ATTR, set.getDisplayName()); @@ -303,12 +262,12 @@ public class HashDbXML { rootEl.appendChild(setEl); } - // TODO: Remove all the multiple database paths stuff, it was a mistake. + // TODO: Remove all the multiple database paths stuff. if(nsrlSet != null) { String useForIngest = Boolean.toString(nsrlSet.getUseForIngest()); String showInboxMessages = Boolean.toString(nsrlSet.getShowInboxMessages()); List paths = Collections.singletonList(nsrlSet.getDatabasePath()); - String type = KNOWN_FILES_HASH_SET_TYPE.NSRL.toString(); + String type = KnownFilesType.NSRL.toString(); Element setEl = doc.createElement(SET_EL); setEl.setAttribute(SET_NAME_ATTR, nsrlSet.getDisplayName()); @@ -326,8 +285,7 @@ public class HashDbXML { rootEl.appendChild(setEl); } - // TODO: Does this have any use? - String calcValue = Boolean.toString(calculate); + String calcValue = Boolean.toString(alwaysCalculateHashes); Element setCalc = doc.createElement(SET_CALC); setCalc.setAttribute(SET_VALUE, calcValue); rootEl.appendChild(setCalc); @@ -366,7 +324,8 @@ public class HashDbXML { Boolean showInboxMessagesBool = Boolean.parseBoolean(showInboxMessages); List paths = new ArrayList<>(); - // TODO: Remove all the multiple database paths stuff, it was a mistake. + // TODO: Remove all the multiple database paths stuff. + // RJCTODO: Rework this to do a search a bit differently, or simply indicate the file is missing... NodeList pathsNList = setEl.getElementsByTagName(PATH_EL); final int numPaths = pathsNList.getLength(); for (int j = 0; j < numPaths; ++j) { @@ -413,10 +372,10 @@ public class HashDbXML { logger.log(Level.WARNING, "No paths were set for hash_set at index {0}. Removing the database.", i); } else { - KNOWN_FILES_HASH_SET_TYPE typeDBType = KNOWN_FILES_HASH_SET_TYPE.valueOf(type); + KnownFilesType typeDBType = KnownFilesType.valueOf(type); try { - HashDb db = importHashDatabase(name, paths.get(0), useForIngestBool, showInboxMessagesBool, typeDBType); - if (typeDBType == KNOWN_FILES_HASH_SET_TYPE.NSRL) { + HashDb db = HashDb.openHashDatabase(name, paths.get(0), useForIngestBool, showInboxMessagesBool, typeDBType); + if (typeDBType == KnownFilesType.NSRL) { setNSRLSet(db); } else { @@ -438,7 +397,7 @@ public class HashDbXML { for(int i=0; i= length) { this.INDEXING_PROGBAR.setValue(100); this.setModal(false); From 7971872940cec74501be7a754e98f2ab5b633021 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 5 Nov 2013 22:22:34 -0500 Subject: [PATCH 27/30] Getting the advanced config UI for hash databases to work --- .../AddContentToHashDbAction.java | 4 +- .../autopsy/hashdatabase/Bundle.properties | 44 +- .../HashDatabaseOptionsPanelController.java | 8 +- .../autopsy/hashdatabase/HashDb.java | 7 +- .../HashDbCreateDatabaseDialog.java | 6 +- .../HashDbImportDatabaseDialog.java | 12 +- .../hashdatabase/HashDbIngestModule.java | 78 +- .../hashdatabase/HashDbSimplePanel.java | 20 +- ...l.form => HashSetsConfigurationPanel.form} | 44 +- ...l.java => HashSetsConfigurationPanel.java} | 808 ++++++++---------- .../{HashDbXML.java => HashSetsManager.java} | 284 +++--- .../autopsy/hashdatabase/IndexStatus.java | 7 +- .../autopsy/hashdatabase/ModalNoButtons.java | 6 +- 13 files changed, 618 insertions(+), 710 deletions(-) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashDbManagementPanel.form => HashSetsConfigurationPanel.form} (89%) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashDbManagementPanel.java => HashSetsConfigurationPanel.java} (58%) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashDbXML.java => HashSetsManager.java} (70%) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index 7f01819fdd..8056c176c5 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -104,9 +104,9 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente // Get the current set of updateable hash databases and add each // one as a menu item. - List hashDatabases = HashDbXML.getInstance().getKnownBadSets(); + List hashDatabases = HashSetsManager.getInstance().getKnownBadHashSets(); if (!hashDatabases.isEmpty()) { - for (final HashDb database : HashDbXML.getInstance().getUpdateableHashSets()) { + for (final HashDb database : HashSetsManager.getInstance().getUpdateableHashSets()) { JMenuItem databaseItem = add(database.getDisplayName()); databaseItem.addActionListener(new ActionListener() { @Override diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index 822541f5fa..4efbb6dca4 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -25,27 +25,6 @@ HashDbSearchPanel.cancelButton.text=Cancel HashDbSimplePanel.calcHashesButton.text=Calculate hashes even if no hash database is selected HashDbSimplePanel.nsrlDbLabel.text=NSRL Database: HashDbSimplePanel.nsrlDbLabelVal.text=- -HashDbManagementPanel.hashDbIndexStatusLabel.text=No database selected -HashDbManagementPanel.jLabel2.text=Name: -HashDbManagementPanel.showInboxMessagesCheckBox.text=Enable sending messages to inbox during ingest -HashDbManagementPanel.useForIngestCheckbox.text=Enable for ingest -HashDbManagementPanel.indexButton.text=Index -HashDbManagementPanel.indexLabel.text=Index Status: -HashDbManagementPanel.optionsLabel.text=Options -HashDbManagementPanel.jLabel4.text=Location: -HashDbManagementPanel.jLabel6.text=Type: -HashDbManagementPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. -HashDbManagementPanel.hashDbTypeLabel.text=No database selected -HashDbManagementPanel.typeLabel.text=Type: -HashDbManagementPanel.deleteButton.text=Delete Database -HashDbManagementPanel.importButton.text=Import Database -HashDbManagementPanel.hashDbNameLabel.text=No database selected -HashDbManagementPanel.nameLabel.text=Name: -HashDbManagementPanel.jButton3.text=Import Database -HashDbManagementPanel.locationLabel.text=Location: -HashDbManagementPanel.hashDbLocationLabel.text=No database selected -HashDbManagementPanel.informationLabel.text=Information -HashDbManagementPanel.hashDatabasesLabel.text=Hash Databases: OpenIDE-Module-Short-Description=Hash Database Ingest Module and hash db tools ModalNoButtons.CURRENTLYON_LABEL.text=Currently Indexing x of y ModalNoButtons.GO_GET_COFFEE_LABEL.text=Hash databases are currently being indexed, this may take some time. @@ -73,4 +52,25 @@ HashDbCreateDatabaseDialog.okButton.text=OK HashDbCreateDatabaseDialog.useForIngestCheckbox.text=Enable for ingest HashDbCreateDatabaseDialog.jLabel1.text=Display name of database: HashDbCreateDatabaseDialog.databaseNameTextField.text= -HashDbManagementPanel.importButton1.text=New Database +HashSetsConfigurationPanel.importButton1.text=New Database +HashSetsConfigurationPanel.jButton3.text=Import Database +HashSetsConfigurationPanel.jLabel6.text=Type: +HashSetsConfigurationPanel.jLabel4.text=Location: +HashSetsConfigurationPanel.jLabel2.text=Name: +HashSetsConfigurationPanel.hashDbTypeLabel.text=No database selected +HashSetsConfigurationPanel.deleteButton.text=Delete Database +HashSetsConfigurationPanel.hashDbIndexStatusLabel.text=No database selected +HashSetsConfigurationPanel.indexLabel.text=Index Status: +HashSetsConfigurationPanel.indexButton.text=Index +HashSetsConfigurationPanel.locationLabel.text=Location: +HashSetsConfigurationPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. +HashSetsConfigurationPanel.hashDbLocationLabel.text=No database selected +HashSetsConfigurationPanel.typeLabel.text=Type: +HashSetsConfigurationPanel.hashDatabasesLabel.text=Hash Databases: +HashSetsConfigurationPanel.importButton.text=Import Database +HashSetsConfigurationPanel.hashDbNameLabel.text=No database selected +HashSetsConfigurationPanel.nameLabel.text=Name: +HashSetsConfigurationPanel.informationLabel.text=Information +HashSetsConfigurationPanel.optionsLabel.text=Options +HashSetsConfigurationPanel.useForIngestCheckbox.text=Enable for ingest +HashSetsConfigurationPanel.showInboxMessagesCheckBox.text=Enable sending messages to inbox during ingest diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java index 7b81b5619f..8523116156 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java @@ -36,7 +36,7 @@ id = "HashDatabase") @org.openide.util.NbBundle.Messages({"OptionsCategory_Name_HashDatabase=Hash Database", "OptionsCategory_Keywords_HashDatabase=Hash Database"}) public final class HashDatabaseOptionsPanelController extends OptionsPanelController { - private HashDbManagementPanel panel; + private HashSetsConfigurationPanel panel; private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private boolean changed; @@ -55,7 +55,7 @@ public final class HashDatabaseOptionsPanelController extends OptionsPanelContro @Override public void cancel() { // Reset the XML on cancel - HashDbXML.getInstance().reload(); + HashSetsManager.getInstance().loadLastSavedConfiguration(); } @Override @@ -88,9 +88,9 @@ public final class HashDatabaseOptionsPanelController extends OptionsPanelContro pcs.removePropertyChangeListener(l); } - private HashDbManagementPanel getPanel() { + private HashSetsConfigurationPanel getPanel() { if (panel == null) { - panel = new HashDbManagementPanel(); + panel = new HashSetsConfigurationPanel(); } return panel; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index 024ea46764..27078e012e 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -64,7 +64,12 @@ public class HashDb implements Comparable { * @throws TskCoreException */ public static HashDb openHashDatabase(String hashSetName, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType knownType) throws TskCoreException { - return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); + if (knownType == HashDb.KnownFilesType.NSRL) { + return new HashDb(SleuthkitJNI.openNSRLDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); + } + else { + return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); + } } /** diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index 86d01b8def..1a69551f0b 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -58,8 +58,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } super.approveSelection(); } - }; - + }; initComponents(); customizeComponents(); } @@ -75,9 +74,12 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { HashDb doDialog() { newHashDb = 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 newHashDb; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index 42e8af23a8..8dc8e459ed 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -216,10 +216,6 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { }// //GEN-END:initComponents private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed - File currentDir = new File(databasePathTextField.getText()); - if (currentDir.exists()) { - fileChooser.setCurrentDirectory(currentDir); - } if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { File databaseFile = fileChooser.getSelectedFile(); try { @@ -256,7 +252,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { JOptionPane.showMessageDialog(this, "Database display name cannot be empty."); return; } - + File file = new File(databasePathTextField.getText()); if (!file.exists()) { JOptionPane.showMessageDialog(this, "Selected database does not exist."); @@ -282,7 +278,11 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { } try { - selectedHashDb = HashDb.openHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + selectedHashDb = HashDb.openHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + + +// if (!selectedHashDb.hasTextLookupIndexOnly()) + } catch (TskCoreException ex) { Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Failed to open hash database at " + filePath, ex); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java index a39292889d..7fb3650df8 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2013 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.PipelineContext; @@ -68,7 +67,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { static long calctime = 0; static long lookuptime = 0; private Map knownBadSets = new HashMap<>(); - private HashDbManagementPanel panel; + private HashSetsConfigurationPanel panel; private final Hash hasher = new Hash(); private HashDbIngestModule() { @@ -82,26 +81,41 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { return instance; } + @Override + public String getName() { + return MODULE_NAME; + } + + @Override + public String getDescription() { + return MODULE_DESCRIPTION; + } + + @Override + public String getVersion() { + return MODULE_VERSION; + } + @Override public void init(IngestModuleInit initContext) { services = IngestServices.getDefault(); this.skCase = Case.getCurrentCase().getSleuthkitCase(); try { - HashDbXML hdbxml = HashDbXML.getInstance(); + HashSetsManager hdbxml = HashSetsManager.getInstance(); nsrlSet = null; knownBadSets.clear(); nsrlIsSet = false; knownBadIsSet = false; calcHashesIsSet = hdbxml.shouldAlwaysCalculateHashes(); - HashDb nsrl = hdbxml.getNSRLSet(); + HashDb nsrl = hdbxml.getNSRLHashSet(); if (nsrl != null && nsrl.getUseForIngest() && IndexStatus.isIngestible(nsrl.getStatus())) { nsrlIsSet = true; this.nsrlSet = nsrl; nsrlPointer = skCase.setNSRLDatabase(nsrl.getDatabasePath()); } - for (HashDb db : hdbxml.getKnownBadSets()) { + for (HashDb db : hdbxml.getKnownBadHashSets()) { IndexStatus status = db.getStatus(); if (db.getUseForIngest() && IndexStatus.isIngestible(status)) { knownBadIsSet = true; @@ -144,51 +158,13 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { detailsSb.append(""); services.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this, "Hash Lookup Results", detailsSb.toString())); - clearHashDatabaseHandles(); } } - - private void clearHashDatabaseHandles() { - try { - HashDbXML.getInstance().closeHashDatabases(); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error clearing hash database handles. ", ex); - } - this.nsrlIsSet = false; - this.knownBadIsSet = false; - } - /** - * notification from manager to stop processing due to some interruption - * (user, error, exception) - */ @Override public void stop() { - clearHashDatabaseHandles(); } - - /** - * get specific name of the module should be unique across modules, a - * user-friendly name of the module shown in GUI - * - * @return The name of this Ingest Module - */ - @Override - public String getName() { - return MODULE_NAME; - } - - @Override - public String getDescription() { - return MODULE_DESCRIPTION; - } - - @Override - public String getVersion() { - return MODULE_VERSION; - } - - + @Override public ProcessResult process(PipelineContextpipelineContext, AbstractFile file) { //skip unalloc @@ -217,7 +193,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { @Override public javax.swing.JPanel getSimpleConfiguration(String context) { - HashDbXML.getInstance().reload(); + HashSetsManager.getInstance().loadLastSavedConfiguration(); return new HashDbSimplePanel(); } @@ -233,16 +209,16 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { getPanel().store(); } - private HashDbManagementPanel getPanel() { + private HashSetsConfigurationPanel getPanel() { if (panel == null) { - panel = new HashDbManagementPanel(); + panel = new HashSetsConfigurationPanel(); } return panel; } @Override public void saveSimpleConfiguration() { - HashDbXML.getInstance().save(); + HashSetsManager.getInstance().save(); } private void processBadFile(AbstractFile abstractFile, String md5Hash, String hashSetName, boolean showInboxMessage) { @@ -378,8 +354,8 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { public ArrayList getKnownBadSetNames() { ArrayList knownBadSetNames = new ArrayList<>(); - HashDbXML hdbxml = HashDbXML.getInstance(); - for (HashDb db : hdbxml.getKnownBadSets()) { + HashSetsManager hdbxml = HashSetsManager.getInstance(); + for (HashDb db : hdbxml.getKnownBadHashSets()) { knownBadSetNames.add(db.getDisplayName()); } return knownBadSetNames; diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java index 81c2adac37..c065211ebe 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java @@ -43,10 +43,10 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } private void reloadCalc() { - final HashDbXML xmlHandle = HashDbXML.getInstance(); - final HashDb nsrlDb = xmlHandle.getNSRLSet(); + final HashSetsManager xmlHandle = HashSetsManager.getInstance(); + final HashDb nsrlDb = xmlHandle.getNSRLHashSet(); final boolean nsrlUsed = nsrlDb != null && nsrlDb.getUseForIngest()== true && nsrlDb.hasLookupIndex(); - final List knowns = xmlHandle.getKnownBadSets(); + final List knowns = xmlHandle.getKnownBadHashSets(); final boolean knownExists = !knowns.isEmpty(); boolean knownUsed = false; if (knownExists) { @@ -70,7 +70,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } private void customizeComponents() { - final HashDbXML xmlHandle = HashDbXML.getInstance(); + final HashSetsManager xmlHandle = HashSetsManager.getInstance(); calcHashesButton.addActionListener( new ActionListener() { @Override @@ -104,7 +104,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } private void reloadSets() { - nsrl = HashDbXML.getInstance().getNSRLSet(); + nsrl = HashSetsManager.getInstance().getNSRLHashSet(); if (nsrl == null || nsrl.getUseForIngest() == false) { nsrlDbLabelVal.setText("Disabled"); @@ -199,7 +199,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { private class HashTableModel extends AbstractTableModel { - private HashDbXML xmlHandle = HashDbXML.getInstance(); + private HashSetsManager xmlHandle = HashSetsManager.getInstance(); private void resync() { fireTableDataChanged(); @@ -207,7 +207,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { @Override public int getRowCount() { - int size = xmlHandle.getKnownBadSets().size(); + int size = xmlHandle.getKnownBadHashSets().size(); return size == 0 ? 1 : size; } @@ -218,14 +218,14 @@ public class HashDbSimplePanel extends javax.swing.JPanel { @Override public Object getValueAt(int rowIndex, int columnIndex) { - if (xmlHandle.getKnownBadSets().isEmpty()) { + if (xmlHandle.getKnownBadHashSets().isEmpty()) { if (columnIndex == 0) { return ""; } else { return "Disabled"; } } else { - HashDb db = xmlHandle.getKnownBadSets().get(rowIndex); + HashDb db = xmlHandle.getKnownBadHashSets().get(rowIndex); if (columnIndex == 0) { return db.getUseForIngest(); } else { @@ -242,7 +242,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if(columnIndex == 0){ - HashDb db = xmlHandle.getKnownBadSets().get(rowIndex); + HashDb db = xmlHandle.getKnownBadHashSets().get(rowIndex); IndexStatus status = IndexStatus.NO_INDEX; try { status = db.getStatus(); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.form similarity index 89% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.form index 5530d19c33..a476718dd9 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.form @@ -5,21 +5,21 @@ - + - + - + @@ -29,7 +29,7 @@ - + @@ -190,7 +190,7 @@ - + @@ -230,7 +230,7 @@ - + @@ -252,7 +252,7 @@ - + @@ -271,70 +271,70 @@ - + - + - + - + - + - + - + - + - + - + @@ -345,7 +345,7 @@ - + @@ -355,7 +355,7 @@ - + @@ -365,14 +365,14 @@ - + - + @@ -386,7 +386,7 @@ - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java similarity index 58% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java index 43afd118c1..8de8c7a85b 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.hashdatabase; import java.awt.Color; @@ -27,9 +26,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; @@ -42,117 +39,313 @@ import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellRenderer; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; +import static org.sleuthkit.autopsy.hashdatabase.IndexStatus.NO_INDEX; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.TskCoreException; -final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsPanel { - - private HashSetTableModel hashSetTableModel; - private static final Logger logger = Logger.getLogger(HashDbManagementPanel.class.getName()); - private boolean ingestRunning = false; - - - //keep track of dbs being indexed, since HashDb objects are reloaded, - //we cannot rely on their status - private final MapindexingState = new HashMap(); - - HashDbManagementPanel() { - this.hashSetTableModel = new HashSetTableModel(); - initComponents(); - customizeComponents(); +/** + * Instances of this class provide a UI for managing the hash sets configuration. + */ +final class HashSetsConfigurationPanel extends javax.swing.JPanel implements OptionsPanel { + private HashSetsManager hashSetManager = HashSetsManager.getInstance(); + private HashSetTableModel hashSetTableModel = new HashSetTableModel(); + HashSetsConfigurationPanel() { + initComponents(); + customizeComponents(); } private void customizeComponents() { - setName("Hash Database Configuration"); + setName("Hash Set Configuration"); this.ingestWarningLabel.setVisible(false); this.hashSetTable.setModel(hashSetTableModel); this.hashSetTable.setTableHeader(null); hashSetTable.getParent().setBackground(hashSetTable.getBackground()); hashSetTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); hashSetTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - @Override public void valueChanged(ListSelectionEvent e) { - ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource(); - if (!listSelectionModel.isSelectionEmpty()) { - int index = listSelectionModel.getMinSelectionIndex(); - listSelectionModel.setSelectionInterval(index, index); - HashDbXML loader = HashDbXML.getInstance(); - HashDb current = loader.getAllSets().get(index); - initUI(current); - } else { - initUI(null); + if (!e.getValueIsAdjusting()) { + updateComponents(); } } }); } - private void initUI(HashDb db) { + private void updateComponents() { + HashDb db = ((HashSetTable)hashSetTable).getSelection(); + if (db == null) { + hashDbLocationLabel.setText("No database selected"); + hashDbNameLabel.setText("No database selected"); + hashDbIndexStatusLabel.setText("No database selected"); + hashDbTypeLabel.setText("No database selected"); + } + else { + this.hashDbLocationLabel.setToolTipText(db.getDatabasePath()); + if (db.getDatabasePath().length() > 50){ + String shortenedPath = db.getDatabasePath(); + 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)); + hashDbLocationLabel.setText(shortenedPath); + } + else { + hashDbLocationLabel.setText(db.getDatabasePath()); + } + hashDbNameLabel.setText(db.getDisplayName()); + hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); + } + updateStatusComponents(db); + boolean ingestRunning = IngestManager.getDefault().isIngestRunning(); boolean useForIngestEnabled = db != null && !ingestRunning; boolean useForIngestSelected = db != null && db.getUseForIngest(); boolean showInboxMessagesEnabled = db != null && !ingestRunning && useForIngestSelected && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD); boolean showInboxMessagesSelected = db != null && db.getShowInboxMessages(); boolean deleteButtonEnabled = db != null && !ingestRunning; boolean importButtonEnabled = !ingestRunning; - if (db == null) { - setButtonFromIndexStatus(this.indexButton, this.hashDbIndexStatusLabel, IndexStatus.NO_INDEX); - this.hashDbLocationLabel.setText("No database selected"); - this.hashDbNameLabel.setText("No database selected"); - this.hashDbIndexStatusLabel.setText("No database selected"); - this.hashDbTypeLabel.setText("No database selected"); - } else { - //check if dn in indexing state - String dbName = db.getDisplayName(); - IndexStatus status = IndexStatus.NO_INDEX; + useForIngestCheckbox.setSelected(useForIngestSelected); + useForIngestCheckbox.setEnabled(useForIngestEnabled); + showInboxMessagesCheckBox.setSelected(showInboxMessagesSelected); + showInboxMessagesCheckBox.setEnabled(showInboxMessagesEnabled); + deleteButton.setEnabled(deleteButtonEnabled); + importButton.setEnabled(importButtonEnabled); + optionsLabel.setEnabled(useForIngestEnabled || showInboxMessagesEnabled); + optionsSeparator.setEnabled(useForIngestEnabled || showInboxMessagesEnabled); + ingestWarningLabel.setVisible(ingestRunning); + importButton.setEnabled(!ingestRunning); // RJCTODO: What about the other buttons? + } + + void updateStatusComponents(HashDb hashDb) { + if (hashDb == null) { + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.black); + indexButton.setEnabled(false); + } + else { + IndexStatus status = IndexStatus.UNKNOWN; try { - status = db.getStatus(); + status = hashDb.getStatus(); } catch (TskCoreException ex) { - // RJCTODO + // RJCTODO: Need a status unknown? + // Logger.getLogger(HashDbIngestModule.class.getName()) + } + + hashDbIndexStatusLabel.setText(status.message()); + switch (status) { + case NO_INDEX: + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.red); + indexButton.setEnabled(true); + break; + case INDEXING: + indexButton.setText("Indexing"); + hashDbIndexStatusLabel.setForeground(Color.black); + indexButton.setEnabled(false); + break; + case UNKNOWN: + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.red); + indexButton.setEnabled(false); + case INDEXED: + case INDEX_ONLY: + default: + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.black); + indexButton.setEnabled(false); + break; } - Boolean state = indexingState.get(dbName); - if (state != null && state.equals(Boolean.TRUE) ) { - status = IndexStatus.INDEXING; - } - - setButtonFromIndexStatus(this.indexButton, this.hashDbIndexStatusLabel, status); - String shortenPath = db.getDatabasePath(); - this.hashDbLocationLabel.setToolTipText(shortenPath); - if(shortenPath.length() > 50){ - shortenPath = shortenPath.substring(0, 10 + shortenPath.substring(10).indexOf(File.separator) + 1) + "..." + - shortenPath.substring((shortenPath.length() - 20) + shortenPath.substring(shortenPath.length() - 20).indexOf(File.separator)); - } - this.hashDbLocationLabel.setText(shortenPath); - this.hashDbNameLabel.setText(db.getDisplayName()); - this.hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); } - this.useForIngestCheckbox.setSelected(useForIngestSelected); - this.useForIngestCheckbox.setEnabled(useForIngestEnabled); - this.showInboxMessagesCheckBox.setSelected(showInboxMessagesSelected); - this.showInboxMessagesCheckBox.setEnabled(showInboxMessagesEnabled); - this.deleteButton.setEnabled(deleteButtonEnabled); - this.importButton.setEnabled(importButtonEnabled); - this.optionsLabel.setEnabled(useForIngestEnabled || showInboxMessagesEnabled); - this.optionsSeparator.setEnabled(useForIngestEnabled || showInboxMessagesEnabled); + + if (IngestManager.getDefault().isIngestRunning()) { + indexButton.setEnabled(false); + } + } + + @Override + public void load() { + hashSetTable.clearSelection(); + hashSetTableModel.refresh(); +// updateComponents(null); + } + + @Override + public void store() { + //Checking for for any unindexed databases + List unindexed = new ArrayList<>(); + for (HashDb hashSet : hashSetManager.getAllHashSets()) { + if (!hashSet.hasLookupIndex()) { + unindexed.add(hashSet); + } + } + + // RJCTODO:Whaaaaat? + //If unindexed ones are found, show a popup box that will either index them, or remove them. + if (unindexed.size() == 1){ + showInvalidIndex(false, unindexed); + } + else if (unindexed.size() > 1){ + showInvalidIndex(true, unindexed); + } + + hashSetManager.save(); } /** - * Sets the current state of ingest. - * Don't allow any changes if ingest is running. - * @param running Whether ingest is running or not. + * 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); + } + hashSetTableModel.refresh(); + } + + /** + * Displays the popup box that tells user that some of his databases are unindexed, along with solutions. + * This method is related to ModalNoButtons, to be removed at a later date. + * @param plural Whether or not there are multiple unindexed databases + * @param unindexed The list of unindexed databases. Can be of size 1. */ - private void setIngestStatus(boolean running) { - ingestRunning = running; - ingestWarningLabel.setVisible(running); - importButton.setEnabled(!running); - - int selection = getSelection(); - if(selection != -1) { - initUI(HashDbXML.getInstance().getAllSets().get(selection)); + private void showInvalidIndex(boolean plural, List unindexed){ + String total = ""; + String message; + for(HashDb hdb : unindexed){ + total+= "\n" + hdb.getDisplayName(); + } + if(plural){ + message = "The following databases are not indexed, would you like to index them now? \n " + total; + } + else{ + message = "The following database is not indexed, would you like to index it now? \n" + total; + } + int res = JOptionPane.showConfirmDialog(this, message, "Unindexed databases", JOptionPane.YES_NO_OPTION); + if(res == JOptionPane.YES_OPTION){ + ModalNoButtons indexingDialog = new ModalNoButtons(this, new Frame(),unindexed); + indexingDialog.setLocationRelativeTo(null); + indexingDialog.setVisible(true); + indexingDialog.setModal(true); + hashSetTableModel.refresh(); + } + if(res == JOptionPane.NO_OPTION){ + JOptionPane.showMessageDialog(this, "All unindexed databases will be removed the list"); + removeThese(unindexed); } } + boolean valid() { + // TODO check whether form is consistent and complete + return true; + } + + /** + * This class implements a table for displaying configured hash sets. + */ + private class HashSetTable extends JTable { + @Override + public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { + // Use the hash set name as the cell text. + JComponent cellRenderer = (JComponent)super.prepareRenderer(renderer, row, column); + cellRenderer.setToolTipText((String)getValueAt(row, column)); + + // Give the user a visual indication of any hash sets with a hash + // database that needs to be indexed by displaying the hash set name + // in red. + if (hashSetTableModel.indexExists(row)){ + cellRenderer.setForeground(Color.black); + } + else{ + cellRenderer.setForeground(Color.red); + } + + return cellRenderer; + } + + public HashDb getSelection() { + return hashSetTableModel.getHashSetAt(getSelectionModel().getMinSelectionIndex()); + } + + public void setSelection(int index) { + if (index >= 0 && index < hashSetTable.getRowCount()) { + getSelectionModel().setSelectionInterval(index, index); + } + } + + public void selectRowByName(String name) { + setSelection(hashSetTableModel.getIndexByName(name)); + } + } + + /** + * This class implements the table model for the table used to display + * configured hash sets. + */ + private class HashSetTableModel extends AbstractTableModel { + List hashSets = HashSetsManager.getInstance().getAllHashSets(); + + @Override + public int getColumnCount() { + return 1; + } + + @Override + public int getRowCount() { + return hashSets.size(); + } + + @Override + public String getColumnName(int column) { + return "Name"; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return hashSets.get(rowIndex).getDisplayName(); + } + + private boolean indexExists(int rowIndex){ + return hashSets.get(rowIndex).hasLookupIndex(); + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + throw new UnsupportedOperationException("Editing of cells is not supported"); + } + + @Override + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + + HashDb getHashSetAt(int index) { + if (!hashSets.isEmpty() && index >= 0 && index < hashSets.size()) { + return hashSets.get(index); + } + else { + return null; + } + } + + int getIndexByName(String name) { + for (int i = 0; i < hashSets.size(); ++i) { + if (hashSets.get(i).getDisplayName().equals(name)) { + return i; + } + } + return -1; + } + + void refresh() { + hashSets = HashSetsManager.getInstance().getAllHashSets(); + fireTableDataChanged(); + } + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -188,20 +381,20 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP optionsSeparator = new javax.swing.JSeparator(); importButton1 = new javax.swing.JButton(); - org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.jLabel2.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jLabel2.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.jLabel4.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jLabel4.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.jLabel6.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jLabel6.text")); // NOI18N jButton3.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.jButton3.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jButton3.text")); // NOI18N setMinimumSize(new java.awt.Dimension(700, 500)); setPreferredSize(new java.awt.Dimension(700, 500)); ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/warning16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.ingestWarningLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.ingestWarningLabel.text")); // NOI18N hashSetTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { @@ -221,7 +414,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP jScrollPane1.setViewportView(hashSetTable); deleteButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/delete16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.deleteButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.deleteButton.text")); // NOI18N deleteButton.setMaximumSize(new java.awt.Dimension(140, 25)); deleteButton.setMinimumSize(new java.awt.Dimension(140, 25)); deleteButton.setPreferredSize(new java.awt.Dimension(140, 25)); @@ -232,7 +425,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP }); importButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/import16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(importButton, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.importButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(importButton, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.importButton.text")); // NOI18N importButton.setMaximumSize(new java.awt.Dimension(140, 25)); importButton.setMinimumSize(new java.awt.Dimension(140, 25)); importButton.setPreferredSize(new java.awt.Dimension(140, 25)); @@ -242,25 +435,25 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP } }); - org.openide.awt.Mnemonics.setLocalizedText(hashDatabasesLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.hashDatabasesLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDatabasesLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDatabasesLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.nameLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.nameLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbNameLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.hashDbNameLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbNameLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbNameLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbLocationLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.hashDbLocationLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbLocationLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbLocationLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(locationLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.locationLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(locationLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.locationLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(typeLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.typeLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(typeLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.typeLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbTypeLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.hashDbTypeLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbTypeLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbTypeLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbIndexStatusLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.hashDbIndexStatusLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbIndexStatusLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbIndexStatusLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(indexLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.indexLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(indexLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.indexLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(indexButton, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.indexButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(indexButton, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.indexButton.text")); // NOI18N indexButton.setEnabled(false); indexButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -268,26 +461,26 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP } }); - org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.useForIngestCheckbox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.useForIngestCheckbox.text")); // NOI18N useForIngestCheckbox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { useForIngestCheckboxActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(showInboxMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.showInboxMessagesCheckBox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(showInboxMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.showInboxMessagesCheckBox.text")); // NOI18N showInboxMessagesCheckBox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showInboxMessagesCheckBoxActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(informationLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.informationLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(informationLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.informationLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.optionsLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.optionsLabel.text")); // NOI18N importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/new16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.importButton1.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.importButton1.text")); // NOI18N importButton1.setMaximumSize(new java.awt.Dimension(140, 25)); importButton1.setMinimumSize(new java.awt.Dimension(140, 25)); importButton1.setPreferredSize(new java.awt.Dimension(140, 25)); @@ -401,228 +594,88 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP }// //GEN-END:initComponents private void indexButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexButtonActionPerformed - int selected = getSelection(); - final HashDb current = HashDbXML.getInstance().getAllSets().get(selected); - current.addPropertyChangeListener(new PropertyChangeListener() { - - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) { - //update tracking of indexing status - indexingState.put((String)evt.getNewValue(), Boolean.FALSE); - IndexStatus status = IndexStatus.NO_INDEX; - try { - status = current.getStatus(); + final HashDb hashDbToBeIndexed = ((HashSetTable)hashSetTable).getSelection(); + if (hashDbToBeIndexed != null) { + // Add a listener for the INDEXING_DONE event. The listener will update + // the UI. + hashDbToBeIndexed.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) { + HashDb selectedHashDb = ((HashSetTable)hashSetTable).getSelection(); + if (selectedHashDb != null && hashDbToBeIndexed != null && hashDbToBeIndexed.equals(selectedHashDb)) { + updateStatusComponents(selectedHashDb); + } } - catch (TskCoreException ex) { - // RJCTODO - } - setButtonFromIndexStatus(indexButton, hashDbIndexStatusLabel, status); - resync(); - } - } + } + }); - }); - indexingState.put(current.getDisplayName(), Boolean.TRUE); - ModalNoButtons singleMNB = new ModalNoButtons(this, new Frame(), current); //Modal reference, to be removed later - singleMNB.setLocationRelativeTo(null); - singleMNB.setVisible(true); - singleMNB.setModal(true); //End Modal reference - indexingState.put(current.getDisplayName(), Boolean.FALSE); - IndexStatus status = IndexStatus.NO_INDEX; - try { - status = current.getStatus(); + // Display a modal dialog box to kick off the indexing on a worker thread + // and try to persuade the user to wait for the indexing task to finish. + // TODO: This defeats the purpose of doing the indexing on a worker thread. + // The user may also cancel the dialog and change the hash sets configuration. + // That should be fine, as long as the indexing DB is not deleted, which + // shu;d be able to be controlled. + ModalNoButtons indexDialog = new ModalNoButtons(this, new Frame(), hashDbToBeIndexed); + indexDialog.setLocationRelativeTo(null); + indexDialog.setVisible(true); + indexDialog.setModal(true); } - catch (TskCoreException ex) { - // RJCTODO - } - setButtonFromIndexStatus(indexButton, this.hashDbIndexStatusLabel, status); }//GEN-LAST:event_indexButtonActionPerformed private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed - 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) { - - int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getInstance(); - if (xmlHandle.getNSRLSet() != null) { - if (selected == 0) { - HashDbXML.getInstance().removeNSRLSet(); - } else { - HashDbXML.getInstance().removeKnownBadSetAt(selected - 1); - } - } else { - HashDbXML.getInstance().removeKnownBadSetAt(selected); + 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) { + HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); + if (hashDb != null) { + hashSetManager.removeHashSet(hashDb); + hashSetTableModel.refresh(); } - hashSetTableModel.resync(); } }//GEN-LAST:event_deleteButtonActionPerformed private void hashSetTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_hashSetTableKeyPressed if (evt.getKeyCode() == KeyEvent.VK_DELETE) { - int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getInstance(); - if (xmlHandle.getNSRLSet() != null) { - if (selected == 0) { - HashDbXML.getInstance().removeNSRLSet(); - } else { - HashDbXML.getInstance().removeKnownBadSetAt(selected - 1); - } - } else { - HashDbXML.getInstance().removeKnownBadSetAt(selected); + HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); + if (hashDb != null) { + hashSetManager.removeHashSet(hashDb); + hashSetTableModel.refresh(); } - } - hashSetTableModel.resync(); + } }//GEN-LAST:event_hashSetTableKeyPressed private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed - int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getInstance(); - if (xmlHandle.getNSRLSet() != null) { - if (selected == 0) { - HashDb current = HashDbXML.getInstance().getNSRLSet(); - current.setUseForIngest(useForIngestCheckbox.isSelected()); - HashDbXML.getInstance().setNSRLSet(current); - } else { - HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected - 1); - current.setUseForIngest(useForIngestCheckbox.isSelected()); - HashDbXML.getInstance().addKnownBadSet(selected - 1, current); - this.showInboxMessagesCheckBox.setEnabled(useForIngestCheckbox.isSelected()); - } - } else { - HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected); - current.setUseForIngest(useForIngestCheckbox.isSelected()); - HashDbXML.getInstance().addKnownBadSet(selected, current); - this.showInboxMessagesCheckBox.setEnabled(useForIngestCheckbox.isSelected()); + HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); + if (hashDb != null) { + hashDb.setUseForIngest(useForIngestCheckbox.isSelected()); + showInboxMessagesCheckBox.setEnabled(useForIngestCheckbox.isSelected()); } }//GEN-LAST:event_useForIngestCheckboxActionPerformed private void showInboxMessagesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showInboxMessagesCheckBoxActionPerformed - int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getInstance(); - if (xmlHandle.getNSRLSet() != null) { - if (selected == 0) { - HashDb current = HashDbXML.getInstance().getNSRLSet(); - current.setShowInboxMessages(showInboxMessagesCheckBox.isSelected()); - HashDbXML.getInstance().setNSRLSet(current); - } else { - HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected - 1); - current.setShowInboxMessages(showInboxMessagesCheckBox.isSelected()); - HashDbXML.getInstance().addKnownBadSet(selected - 1, current); - } - } else { - HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected); - current.setShowInboxMessages(showInboxMessagesCheckBox.isSelected()); - HashDbXML.getInstance().addKnownBadSet(selected, current); + HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); + if (hashDb != null) { + hashDb.setShowInboxMessages(showInboxMessagesCheckBox.isSelected()); } }//GEN-LAST:event_showInboxMessagesCheckBoxActionPerformed private void importButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importButtonActionPerformed - importHashSet(evt); + HashDb hashDb = new HashDbImportDatabaseDialog().doDialog(); + if (hashDb != null) { + hashSetManager.addHashSet(hashDb); + hashSetTableModel.refresh(); + ((HashSetTable)hashSetTable).selectRowByName(hashDb.getDisplayName()); + } }//GEN-LAST:event_importButtonActionPerformed private void importButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importButton1ActionPerformed - createHashSet(evt); + HashDb hashDb = new HashDbCreateDatabaseDialog().doDialog(); + if (null != hashDb) { + hashSetManager.addHashSet(hashDb); + hashSetTableModel.refresh(); + ((HashSetTable)hashSetTable).selectRowByName(hashDb.getDisplayName()); + } }//GEN-LAST:event_importButton1ActionPerformed - - @Override - public void load() { - hashSetTable.clearSelection(); // Deselect all rows - HashDbXML.getInstance().reload(); // Reload XML - initUI(null); // Update the UI - hashSetTableModel.resync(); // resync the table - setIngestStatus(IngestManager.getDefault().isIngestRunning()); // check if ingest is running - } - - @Override - /** - * Saves the HashDb's current state. - * This version of store is modified heavily to make use of the ModalNoButtons class. - * The only call that matters is the final HashDbXML.getCurrent().save() - */ - public void store() { - //Checking for for any unindexed databases - List unindexed = new ArrayList(); - for(int i = 0; i < hashSetTableModel.getRowCount(); i++){ - if(! hashSetTableModel.indexExists(i)){ - unindexed.add(hashSetTableModel.getDBAt(i)); - } - } - //If unindexed ones are found, show a popup box that will either index them, or remove them. - if (unindexed.size() == 1){ - showInvalidIndex(false, unindexed); - } - else if (unindexed.size() > 1){ - showInvalidIndex(true, unindexed); - } - HashDbXML.getInstance().save(); - - } - - - /** - * 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) { - HashDbXML xmlHandle = HashDbXML.getInstance(); - for (HashDb hdb : toRemove) { - for (int i = 0; i < hashSetTableModel.getRowCount(); i++) { - if (hashSetTableModel.getDBAt(i).equals(hdb)) { - if (xmlHandle.getNSRLSet() != null) { - if (i == 0) { - HashDbXML.getInstance().removeNSRLSet(); - } else { - HashDbXML.getInstance().removeKnownBadSetAt(i - 1); - } - } else { - HashDbXML.getInstance().removeKnownBadSetAt(i); - } - hashSetTableModel.resync(); - } - } - } - } - - /** - * Displays the popup box that tells user that some of his databases are unindexed, along with solutions. - * This method is related to ModalNoButtons, to be removed at a later date. - * @param plural Whether or not there are multiple unindexed databases - * @param unindexed The list of unindexed databases. Can be of size 1. - */ - private void showInvalidIndex(boolean plural, List unindexed){ - String total = ""; - String message; - for(HashDb hdb : unindexed){ - total+= "\n" + hdb.getDisplayName(); - } - if(plural){ - message = "The following databases are not indexed, would you like to index them now? \n " + total; - } - else{ - message = "The following database is not indexed, would you like to index it now? \n" + total; - } - int res = JOptionPane.showConfirmDialog(this, message, "Unindexed databases", JOptionPane.YES_NO_OPTION); - if(res == JOptionPane.YES_OPTION){ - ModalNoButtons indexingDialog = new ModalNoButtons(this, new Frame(),unindexed); - indexingDialog.setLocationRelativeTo(null); - indexingDialog.setVisible(true); - indexingDialog.setModal(true); - hashSetTableModel.resync(); - } - if(res == JOptionPane.NO_OPTION){ - JOptionPane.showMessageDialog(this, "All unindexed databases will be removed the list"); - removeThese(unindexed); - } - } - - boolean valid() { - // TODO check whether form is consistent and complete - return true; - } + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton deleteButton; private javax.swing.JLabel hashDatabasesLabel; @@ -651,173 +704,4 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private javax.swing.JLabel typeLabel; private javax.swing.JCheckBox useForIngestCheckbox; // End of variables declaration//GEN-END:variables - - private void importHashSet(java.awt.event.ActionEvent evt) { - HashDb hashDb = new HashDbImportDatabaseDialog().doDialog(); - if (hashDb != null) { - HashDbXML.getInstance().addSet(hashDb); - hashSetTableModel.selectRowByName(hashDb.getDisplayName()); - } - resync(); - } - - private void createHashSet(java.awt.event.ActionEvent evt) { - HashDb hashDb = new HashDbCreateDatabaseDialog().doDialog(); - if (null != hashDb) { - HashDbXML.getInstance().addSet(hashDb); - hashSetTableModel.selectRowByName(hashDb.getDisplayName()); - } - resync(); - } - - /** - * The visual display of hash databases loaded. - */ - private class HashSetTable extends JTable { - @Override - public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { - Component c = super.prepareRenderer(renderer, row, column); - JComponent jc = (JComponent) c; - String valueText = (String) getValueAt(row, column); - jc.setToolTipText(valueText); - - //Letting the user know which DBs need to be indexed - if(hashSetTableModel.indexExists(row)){ - c.setForeground(Color.black); - } - else{ - c.setForeground(Color.red); - } - return c; - } - } - - - private class HashSetTableModel extends AbstractTableModel { - - private HashDbXML xmlHandle = HashDbXML.getInstance(); - - @Override - public int getColumnCount() { - return 1; - } - - @Override - public int getRowCount() { - return xmlHandle.getAllSets().size(); - } - - @Override - public String getColumnName(int column) { - return "Name"; - } - - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - if(xmlHandle.getNSRLSet() == null) { - return getDBAt(rowIndex).getDisplayName(); - } else { - return rowIndex == 0 ? getDBAt(rowIndex).getDisplayName() + " (NSRL)" : getDBAt(rowIndex).getDisplayName(); - } - } - - //Internal function for determining whether a companion -md5.idx file exists - private boolean indexExists(int rowIndex){ - return getDBAt(rowIndex).hasLookupIndex(); - } - - //Internal function for getting the DB at a certain index. Used as-is, as well as by dispatch from getValueAt() and indexExists() - private HashDb getDBAt(int rowIndex){ - if (xmlHandle.getNSRLSet() != null) { - if(rowIndex == 0) { - return xmlHandle.getNSRLSet(); - } else { - return xmlHandle.getKnownBadSets().get(rowIndex-1); - } - } else { - return xmlHandle.getKnownBadSets().get(rowIndex); - } - } - - // Selects the row with the given name - private void selectRowByName(String name) { - HashDb NSRL = xmlHandle.getNSRLSet(); - List bad = xmlHandle.getKnownBadSets(); - if(NSRL != null) { - if(NSRL.getDisplayName().equals(name)) { - setSelection(0); - } else { - for(int i=0; i getColumnClass(int c) { - return getValueAt(0, c).getClass(); - } - - void resync() { - fireTableDataChanged(); - } - } - - static void setButtonFromIndexStatus(JButton theButton, JLabel theLabel, IndexStatus status) { - theLabel.setText(status.message()); - switch (status) { - case NO_INDEX: - theButton.setText("Index"); - theLabel.setForeground(Color.red); - theButton.setEnabled(true); - break; - case INDEXING: - theButton.setText("Indexing"); - theLabel.setForeground(Color.black); - theButton.setEnabled(false); - break; - default: - theButton.setText("Index"); - theLabel.setForeground(Color.black); - theButton.setEnabled(false); - } - if (IngestManager.getDefault().isIngestRunning()) { - theButton.setEnabled(false); - } - } - - private int getSelection() { - return hashSetTable.getSelectionModel().getMinSelectionIndex(); - } - - private void setSelection(int index) { - if(index >= 0 && index < hashSetTable.getRowCount()) { - hashSetTable.getSelectionModel().setSelectionInterval(index, index); - } - } - void resync() { - int index = getSelection(); - this.hashSetTableModel.resync(); - setSelection(index); - } - } \ No newline at end of file diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsManager.java similarity index 70% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsManager.java index e333e0c1f7..a763184527 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsManager.java @@ -45,7 +45,7 @@ import org.w3c.dom.NodeList; * that serve as hash sets for the identification of known files, known good files, * and known bad files. */ -public class HashDbXML { +public class HashSetsManager { private static final String ROOT_EL = "hash_sets"; private static final String SET_EL = "hash_set"; private static final String SET_NAME_ATTR = "name"; @@ -59,105 +59,115 @@ public class HashDbXML { 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(HashDbXML.class.getName()); - private static HashDbXML instance; - private List knownBadSets = new ArrayList<>(); - private HashDb nsrlSet; - private boolean alwaysCalculateHashes; + private static final Logger logger = Logger.getLogger(HashSetsManager.class.getName()); + private static HashSetsManager instance; private String xmlFile = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME; - + private List knownBadHashSets = new ArrayList<>(); + private HashDb nsrlHashSet; + private boolean alwaysCalculateHashes; + /** * Gets the singleton instance of this class. */ - public static synchronized HashDbXML getInstance() { + public static synchronized HashSetsManager getInstance() { if (instance == null) { - instance = new HashDbXML(); - instance.reload(); + instance = new HashSetsManager(); } return instance; } - private HashDbXML() { + private HashSetsManager() { + if (hashSetsConfigurationFileExists()) { + readHashSetsConfigurationFromDisk(); + } } /** - * Adds a hash database to the hash set configuration. - */ - public void addSet(HashDb set) { - if (set.getKnownFilesType() == HashDb.KnownFilesType.NSRL) { - setNSRLSet(set); - } - else { - addKnownBadSet(set); - } - } - - /** - * Sets the configured National Software Reference Library (NSRL) known - * files hash set. Does not save the configuration. - */ - public void setNSRLSet(HashDb set) { - this.nsrlSet = set; - } - - /** - * Gets the configured National Software Reference Library (NSRL) known files hash set. - * @return A HashDb object representing the hash set or null if an NSRL set - * has not been added to the configuration. - */ - public HashDb getNSRLSet() { - return nsrlSet; - } - - /** - * Removes the configured National Software Reference Library (NSRL) known - * files hash set. Does not save the configuration. - */ - public void removeNSRLSet() { - this.nsrlSet = null; - } - - /** - * Adds a known bad files hash set to the configuration. Does not save the + * Adds a hash set to the configuration as the designated National Software + * Reference Library (NSRL) hash set. Assumes that the hash set previously + * designated as NSRL set, if any, is not being indexed. Does not save the * configuration. */ - public void addKnownBadSet(HashDb set) { - knownBadSets.add(set); + public void setNSRLHashSet(HashDb set) { + if (nsrlHashSet != null) { + // RJCTODO: When the closeHashDatabase() API exists, close the existing database + } + nsrlHashSet = set; } - - /** - * Adds a known bad files hash set to the configuration. The set is added to - * the internal known bad sets collection at the index specified by the - * caller. Note that this method does not save the configuration. + + /** + * Gets the hash set from the configuration, if any, that is designated as + * the National Software Reference Library (NSRL) hash set. + * @return A HashDb object representing the hash set or null. */ - public void addKnownBadSet(int index, HashDb set) { - knownBadSets.add(index, set); + public HashDb getNSRLHashSet() { + return nsrlHashSet; } + + /** + * Removes the hash set designated as the National Software Reference + * Library (NSRL) hash set from the configuration. Does not save the + * configuration. + */ + public void removeNSRLHashSet() { + if (nsrlHashSet != null) { + // RJCTODO: When the closeHashDatabase() API exists, close the existing database + } + nsrlHashSet = null; + } + + /** + * Adds a hash set to the configuration as a known bad files hash set. Does + * not check for duplication of sets and does not save the configuration. + */ + public void addKnownBadHashSet(HashDb set) { + knownBadHashSets.add(set); + } /** * Gets the configured known bad files hash sets. - * @return A list, possibly empty, of HashDb objects representing the hash - * sets. + * @return A list, possibly empty, of HashDb objects. */ - public List getKnownBadSets() { - return Collections.unmodifiableList(knownBadSets); + public List getKnownBadHashSets() { + return Collections.unmodifiableList(knownBadHashSets); } - /** - * Removes the known bad files hash set from the internal known bad files - * hash sets collection at the specified index. Does not save the configuration. + /** + * Adds a hash set to the configuration. If the hash set is designated as + * the National Software Reference Library (NSRL) hash set, it is assumed + * the the hash set previously designated as the NSRL set, if any, is not + * being indexed. Does not check for duplication of sets and does not save + * the configuration. */ - public void removeKnownBadSetAt(int index) { - knownBadSets.remove(index); + public void addHashSet(HashDb hashSet) { + if (hashSet.getKnownFilesType() == HashDb.KnownFilesType.NSRL) { + setNSRLHashSet(hashSet); + } + else { + addKnownBadHashSet(hashSet); + } } - + + /** + * Removes a hash set from the hash sets configuration. + */ + public void removeHashSet(HashDb hashSetToRemove) { + if (nsrlHashSet != null && nsrlHashSet.equals(hashSetToRemove)) { + removeNSRLHashSet(); + } + else { + knownBadHashSets.remove(hashSetToRemove); + // RJCTODO: Close HashDb + } + } + /** * Gets the configured known files hash sets that accept updates. * @return A list, possibly empty, of HashDb objects. */ public List getUpdateableHashSets() { ArrayList updateableDbs = new ArrayList<>(); - for (HashDb db : knownBadSets) { + for (HashDb db : knownBadHashSets) { try { if (db.isUpdateable()) { updateableDbs.add(db); @@ -171,38 +181,55 @@ public class HashDbXML { } /** - * Gets all of the configured known files hash sets. + * Gets all of the configured hash sets. * @return A list, possibly empty, of HashDb objects representing the hash * sets. */ - public List getAllSets() { + public List getAllHashSets() { List hashDbs = new ArrayList<>(); - if (nsrlSet != null) { - hashDbs.add(nsrlSet); + if (nsrlHashSet != null) { + hashDbs.add(nsrlHashSet); } - hashDbs.addAll(knownBadSets); + hashDbs.addAll(knownBadHashSets); return Collections.unmodifiableList(hashDbs); } + /** Gets the configured hash set, if any, with a given name. + * @return A HashDb object or null. + */ + public HashDb getHashSetByName(String name) { + if (nsrlHashSet != null && nsrlHashSet.getDisplayName().equals(name)) { + return nsrlHashSet; + } + + for (HashDb hashSet : knownBadHashSets) { + if (hashSet.getDisplayName().equals(name)) { + return hashSet; + } + } + + return null; + } + +// public HashDb getHashSetAt(int index) + + // RJCTODO: Get rid of this /** - * Reloads the configuration file if it exists, creates it otherwise. + * Adds a hash set to the configuration as a known bad files hash set. The + * set is added to the internal known bad sets collection at the index + * specified by the caller. Does not save the configuration. */ - public void reload() { - // TODO: This does not look like it is correct. Revisit when time permits. - boolean created = false; - - nsrlSet = null; - knownBadSets.clear(); - - if (!setsFileExists()) { - save(); - created = true; - } + public void addKnownBadSet(int index, HashDb set) { + knownBadHashSets.add(index, set); + } - load(); - if (!created) { - save(); - } + // RJCTODO: Get rid of this + /** + * Removes the known bad files hash set from the internal known bad files + * hash sets collection at the specified index. Does not save the configuration. + */ + public void removeKnownBadSetAt(int index) { + knownBadHashSets.remove(index); } /** @@ -222,12 +249,39 @@ public class HashDbXML { } /** - * Saves the known files hash sets configuration to disk. Note that the - * configuration is only saved on demand to support cancellation of - * configuration panels and dialogs. + * Saves the hash sets configuration. Note that the configuration is only + * saved on demand to support cancellation of configuration panels. * @return True on success, false otherwise. */ public boolean save() { + return writeHashSetConfigurationToDisk(); + } + + /** + * Restores the last saved hash sets configuration. This supports + * cancellation of configuration panels. + */ + public void loadLastSavedConfiguration() { + try { + SleuthkitJNI.closeHashDatabases(); + } + catch (TskCoreException ex) { + // RJCTODO: Log + } + + nsrlHashSet = null; + knownBadHashSets.clear(); + if (hashSetsConfigurationFileExists()) { + readHashSetsConfigurationFromDisk(); + } + } + + private boolean hashSetsConfigurationFileExists() { + File f = new File(xmlFile); + return f.exists() && f.canRead() && f.canWrite(); + } + + private boolean writeHashSetConfigurationToDisk() { boolean success = false; DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); @@ -240,7 +294,7 @@ public class HashDbXML { doc.appendChild(rootEl); // TODO: Remove all the multiple database paths stuff, it was a mistake. - for (HashDb set : knownBadSets) { + for (HashDb set : knownBadHashSets) { String useForIngest = Boolean.toString(set.getUseForIngest()); String showInboxMessages = Boolean.toString(set.getShowInboxMessages()); List paths = Collections.singletonList(set.getDatabasePath()); @@ -263,14 +317,14 @@ public class HashDbXML { } // TODO: Remove all the multiple database paths stuff. - if(nsrlSet != null) { - String useForIngest = Boolean.toString(nsrlSet.getUseForIngest()); - String showInboxMessages = Boolean.toString(nsrlSet.getShowInboxMessages()); - List paths = Collections.singletonList(nsrlSet.getDatabasePath()); + if(nsrlHashSet != null) { + String useForIngest = Boolean.toString(nsrlHashSet.getUseForIngest()); + String showInboxMessages = Boolean.toString(nsrlHashSet.getShowInboxMessages()); + List paths = Collections.singletonList(nsrlHashSet.getDatabasePath()); String type = KnownFilesType.NSRL.toString(); Element setEl = doc.createElement(SET_EL); - setEl.setAttribute(SET_NAME_ATTR, nsrlSet.getDisplayName()); + setEl.setAttribute(SET_NAME_ATTR, nsrlHashSet.getDisplayName()); setEl.setAttribute(SET_TYPE_ATTR, type); setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, useForIngest); setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, showInboxMessages); @@ -290,16 +344,16 @@ public class HashDbXML { setCalc.setAttribute(SET_VALUE, calcValue); rootEl.appendChild(setCalc); - success = XMLUtil.saveDoc(HashDbXML.class, xmlFile, ENCODING, doc); + success = XMLUtil.saveDoc(HashSetsManager.class, xmlFile, ENCODING, doc); } catch (ParserConfigurationException e) { logger.log(Level.SEVERE, "Error saving hash sets: can't initialize parser.", e); } - return success; + return success; } - - private boolean load() { - final Document doc = XMLUtil.loadDoc(HashDbXML.class, xmlFile, XSDFILE); + + private boolean readHashSetsConfigurationFromDisk() { + final Document doc = XMLUtil.loadDoc(HashSetsManager.class, xmlFile, XSDFILE); if (doc == null) { return false; } @@ -376,14 +430,14 @@ public class HashDbXML { try { HashDb db = HashDb.openHashDatabase(name, paths.get(0), useForIngestBool, showInboxMessagesBool, typeDBType); if (typeDBType == KnownFilesType.NSRL) { - setNSRLSet(db); + setNSRLHashSet(db); } else { - addKnownBadSet(db); + addKnownBadHashSet(db); } } catch (TskCoreException ex) { - Logger.getLogger(HashDbXML.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); + Logger.getLogger(HashSetsManager.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); JOptionPane.showMessageDialog(null, "Unable to open " + paths.get(0) + " hash database.", "Open Hash Database Error", JOptionPane.ERROR_MESSAGE); } } @@ -434,21 +488,5 @@ public class HashDbXML { } return filePath; - } - - private boolean setsFileExists() { - File f = new File(xmlFile); - return f.exists() && f.canRead() && f.canWrite(); } - - /** - * Closes all open hash databases. - * @throws TskCoreException - */ - // TODO: Think about whether this should be exposed, and if so, where it should be exposed. - // The ability to add to hash databases implies that the databases should generally not be closed - // until removal or application exit. - void closeHashDatabases() throws TskCoreException { - SleuthkitJNI.closeHashDatabases(); - } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java index 9867257b68..c48ecdab9b 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java @@ -42,8 +42,11 @@ enum IndexStatus { /** * The index is generated. */ - INDEXED("Indexed"); - + INDEXED("Indexed"), + /** + * An error occurred while determining status. + */ + UNKNOWN("Error determining status"); private String message; /** diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java index 0828b14adc..2ff7930c0a 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java @@ -42,7 +42,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen List unindexed; HashDb toIndex; - HashDbManagementPanel hdbmp; + HashSetsConfigurationPanel hdbmp; int length = 0; int currentcount = 1; String currentDb = ""; @@ -53,7 +53,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed the list of unindexed databases to index. */ - ModalNoButtons(HashDbManagementPanel hdbmp, java.awt.Frame parent, List unindexed) { + ModalNoButtons(HashSetsConfigurationPanel hdbmp, java.awt.Frame parent, List unindexed) { super(parent, "Indexing databases", true); this.unindexed = unindexed; this.toIndex = null; @@ -68,7 +68,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed The unindexed database to index. */ - ModalNoButtons(HashDbManagementPanel hdbmp, java.awt.Frame parent, HashDb unindexed){ + ModalNoButtons(HashSetsConfigurationPanel hdbmp, java.awt.Frame parent, HashDb unindexed){ super(parent, "Indexing database", true); this.unindexed = null; this.toIndex = unindexed; From 64c7ea9b4327aafca8b04275f6c89dc1c7cf7057 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 5 Nov 2013 22:41:50 -0500 Subject: [PATCH 28/30] Fixed erroneous case fall through --- .../autopsy/hashdatabase/HashSetsConfigurationPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java index 8de8c7a85b..decf6fc47e 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java @@ -27,9 +27,7 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.util.ArrayList; import java.util.List; -import javax.swing.JButton; import javax.swing.JComponent; -import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; @@ -145,7 +143,9 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt indexButton.setText("Index"); hashDbIndexStatusLabel.setForeground(Color.red); indexButton.setEnabled(false); + break; case INDEXED: + // TODO: Restore ability to re-index an indexed case INDEX_ONLY: default: indexButton.setText("Index"); From a8f33373ab47e378e5d9bbee6b2f125a2fec7a11 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 6 Nov 2013 12:58:06 -0500 Subject: [PATCH 29/30] Completed adaptation of hash db UI/module to new hash db API --- .../AddContentToHashDbAction.java | 4 +- .../autopsy/hashdatabase/Bundle.properties | 52 +-- .../HashDatabaseOptionsPanelController.java | 8 +- ...ationPanel.form => HashDbConfigPanel.form} | 44 +-- ...ationPanel.java => HashDbConfigPanel.java} | 54 +-- .../hashdatabase/HashDbIngestModule.java | 366 ++++++++---------- ...ashSetsManager.java => HashDbManager.java} | 18 +- ...anel.form => HashDbSimpleConfigPanel.form} | 8 +- ...anel.java => HashDbSimpleConfigPanel.java} | 22 +- .../autopsy/hashdatabase/ModalNoButtons.java | 6 +- 10 files changed, 277 insertions(+), 305 deletions(-) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashSetsConfigurationPanel.form => HashDbConfigPanel.form} (88%) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashSetsConfigurationPanel.java => HashDbConfigPanel.java} (91%) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashSetsManager.java => HashDbManager.java} (94%) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashDbSimplePanel.form => HashDbSimpleConfigPanel.form} (89%) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashDbSimplePanel.java => HashDbSimpleConfigPanel.java} (92%) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index 8056c176c5..bf1c776357 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -104,9 +104,9 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente // Get the current set of updateable hash databases and add each // one as a menu item. - List hashDatabases = HashSetsManager.getInstance().getKnownBadHashSets(); + List hashDatabases = HashDbManager.getInstance().getKnownBadHashSets(); if (!hashDatabases.isEmpty()) { - for (final HashDb database : HashSetsManager.getInstance().getUpdateableHashSets()) { + for (final HashDb database : HashDbManager.getInstance().getUpdateableHashSets()) { JMenuItem databaseItem = add(database.getDisplayName()); databaseItem.addActionListener(new ActionListener() { @Override diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index 4efbb6dca4..0d0a92c58d 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -8,7 +8,6 @@ HashDbSimplePanel.knownLabel.text=NSRL Database: HashDbSimplePanel.notableLabel.text=Known Bad Database(s): HashDbSimplePanel.knownValLabel.text=- HashDbSimplePanel.notableValLabel.text=- -HashDbSimplePanel.jLabel1.text=Enable known bad databases for ingest: HashDbSearchPanel.hashTable.columnModel.title0=MD5 Hashes HashDbSearchPanel.hashTable.columnModel.title3=Title 4 HashDbSearchPanel.hashTable.columnModel.title2=Title 3 @@ -22,9 +21,6 @@ HashDbSearchPanel.titleLabel.text=Search for files with the following MD5 hash(e HashDbSearchPanel.errorField.text=Error: Not all files have been hashed. HashDbSearchPanel.saveBox.text=Remember Hashes HashDbSearchPanel.cancelButton.text=Cancel -HashDbSimplePanel.calcHashesButton.text=Calculate hashes even if no hash database is selected -HashDbSimplePanel.nsrlDbLabel.text=NSRL Database: -HashDbSimplePanel.nsrlDbLabelVal.text=- OpenIDE-Module-Short-Description=Hash Database Ingest Module and hash db tools ModalNoButtons.CURRENTLYON_LABEL.text=Currently Indexing x of y ModalNoButtons.GO_GET_COFFEE_LABEL.text=Hash databases are currently being indexed, this may take some time. @@ -52,25 +48,29 @@ HashDbCreateDatabaseDialog.okButton.text=OK HashDbCreateDatabaseDialog.useForIngestCheckbox.text=Enable for ingest HashDbCreateDatabaseDialog.jLabel1.text=Display name of database: HashDbCreateDatabaseDialog.databaseNameTextField.text= -HashSetsConfigurationPanel.importButton1.text=New Database -HashSetsConfigurationPanel.jButton3.text=Import Database -HashSetsConfigurationPanel.jLabel6.text=Type: -HashSetsConfigurationPanel.jLabel4.text=Location: -HashSetsConfigurationPanel.jLabel2.text=Name: -HashSetsConfigurationPanel.hashDbTypeLabel.text=No database selected -HashSetsConfigurationPanel.deleteButton.text=Delete Database -HashSetsConfigurationPanel.hashDbIndexStatusLabel.text=No database selected -HashSetsConfigurationPanel.indexLabel.text=Index Status: -HashSetsConfigurationPanel.indexButton.text=Index -HashSetsConfigurationPanel.locationLabel.text=Location: -HashSetsConfigurationPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. -HashSetsConfigurationPanel.hashDbLocationLabel.text=No database selected -HashSetsConfigurationPanel.typeLabel.text=Type: -HashSetsConfigurationPanel.hashDatabasesLabel.text=Hash Databases: -HashSetsConfigurationPanel.importButton.text=Import Database -HashSetsConfigurationPanel.hashDbNameLabel.text=No database selected -HashSetsConfigurationPanel.nameLabel.text=Name: -HashSetsConfigurationPanel.informationLabel.text=Information -HashSetsConfigurationPanel.optionsLabel.text=Options -HashSetsConfigurationPanel.useForIngestCheckbox.text=Enable for ingest -HashSetsConfigurationPanel.showInboxMessagesCheckBox.text=Enable sending messages to inbox during ingest +HashDbConfigPanel.nameLabel.text=Name: +HashDbConfigPanel.hashDbNameLabel.text=No database selected +HashDbConfigPanel.deleteButton.text=Delete Database +HashDbConfigPanel.importButton.text=Import Database +HashDbConfigPanel.hashDatabasesLabel.text=Hash Databases: +HashDbConfigPanel.hashDbLocationLabel.text=No database selected +HashDbConfigPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. +HashDbConfigPanel.jButton3.text=Import Database +HashDbConfigPanel.jLabel6.text=Type: +HashDbConfigPanel.jLabel4.text=Location: +HashDbConfigPanel.jLabel2.text=Name: +HashDbConfigPanel.importButton1.text=New Database +HashDbConfigPanel.optionsLabel.text=Options +HashDbConfigPanel.typeLabel.text=Type: +HashDbConfigPanel.locationLabel.text=Location: +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.nsrlDbLabelVal.text=- +HashDbSimpleConfigPanel.calcHashesButton.text=Calculate hashes even if no hash database is selected +HashDbSimpleConfigPanel.jLabel1.text=Enable known bad databases for ingest: +HashDbSimpleConfigPanel.nsrlDbLabel.text=NSRL Database: diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java index 8523116156..3e8fa443aa 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java @@ -36,7 +36,7 @@ id = "HashDatabase") @org.openide.util.NbBundle.Messages({"OptionsCategory_Name_HashDatabase=Hash Database", "OptionsCategory_Keywords_HashDatabase=Hash Database"}) public final class HashDatabaseOptionsPanelController extends OptionsPanelController { - private HashSetsConfigurationPanel panel; + private HashDbConfigPanel panel; private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private boolean changed; @@ -55,7 +55,7 @@ public final class HashDatabaseOptionsPanelController extends OptionsPanelContro @Override public void cancel() { // Reset the XML on cancel - HashSetsManager.getInstance().loadLastSavedConfiguration(); + HashDbManager.getInstance().loadLastSavedConfiguration(); } @Override @@ -88,9 +88,9 @@ public final class HashDatabaseOptionsPanelController extends OptionsPanelContro pcs.removePropertyChangeListener(l); } - private HashSetsConfigurationPanel getPanel() { + private HashDbConfigPanel getPanel() { if (panel == null) { - panel = new HashSetsConfigurationPanel(); + panel = new HashDbConfigPanel(); } return panel; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form similarity index 88% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.form rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form index a476718dd9..9b1d50cc52 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form @@ -5,21 +5,21 @@ - + - + - + @@ -29,7 +29,7 @@ - + @@ -190,7 +190,7 @@ - + @@ -230,7 +230,7 @@ - + @@ -252,7 +252,7 @@ - + @@ -271,70 +271,70 @@ - + - + - + - + - + - + - + - + - + - + @@ -345,7 +345,7 @@ - + @@ -355,7 +355,7 @@ - + @@ -365,14 +365,14 @@ - + - + @@ -386,7 +386,7 @@ - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java similarity index 91% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java index decf6fc47e..85e5a178f5 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java @@ -44,11 +44,11 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this class provide a UI for managing the hash sets configuration. */ -final class HashSetsConfigurationPanel extends javax.swing.JPanel implements OptionsPanel { - private HashSetsManager hashSetManager = HashSetsManager.getInstance(); +final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel { + private HashDbManager hashSetManager = HashDbManager.getInstance(); private HashSetTableModel hashSetTableModel = new HashSetTableModel(); - HashSetsConfigurationPanel() { + HashDbConfigPanel() { initComponents(); customizeComponents(); } @@ -281,7 +281,7 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt * configured hash sets. */ private class HashSetTableModel extends AbstractTableModel { - List hashSets = HashSetsManager.getInstance().getAllHashSets(); + List hashSets = HashDbManager.getInstance().getAllHashSets(); @Override public int getColumnCount() { @@ -341,7 +341,7 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt } void refresh() { - hashSets = HashSetsManager.getInstance().getAllHashSets(); + hashSets = HashDbManager.getInstance().getAllHashSets(); fireTableDataChanged(); } } @@ -381,20 +381,20 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt optionsSeparator = new javax.swing.JSeparator(); importButton1 = new javax.swing.JButton(); - org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jLabel2.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jLabel2.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jLabel4.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jLabel4.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jLabel6.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jLabel6.text")); // NOI18N jButton3.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jButton3.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jButton3.text")); // NOI18N setMinimumSize(new java.awt.Dimension(700, 500)); setPreferredSize(new java.awt.Dimension(700, 500)); ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/warning16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.ingestWarningLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.ingestWarningLabel.text")); // NOI18N hashSetTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { @@ -414,7 +414,7 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt jScrollPane1.setViewportView(hashSetTable); deleteButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/delete16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.deleteButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.deleteButton.text")); // NOI18N deleteButton.setMaximumSize(new java.awt.Dimension(140, 25)); deleteButton.setMinimumSize(new java.awt.Dimension(140, 25)); deleteButton.setPreferredSize(new java.awt.Dimension(140, 25)); @@ -425,7 +425,7 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt }); importButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/import16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(importButton, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.importButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(importButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.importButton.text")); // NOI18N importButton.setMaximumSize(new java.awt.Dimension(140, 25)); importButton.setMinimumSize(new java.awt.Dimension(140, 25)); importButton.setPreferredSize(new java.awt.Dimension(140, 25)); @@ -435,25 +435,25 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt } }); - org.openide.awt.Mnemonics.setLocalizedText(hashDatabasesLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDatabasesLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDatabasesLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDatabasesLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.nameLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.nameLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbNameLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbNameLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbNameLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDbNameLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbLocationLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbLocationLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbLocationLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDbLocationLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(locationLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.locationLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(locationLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.locationLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(typeLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.typeLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(typeLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.typeLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbTypeLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbTypeLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbTypeLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDbTypeLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbIndexStatusLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbIndexStatusLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbIndexStatusLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDbIndexStatusLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(indexLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.indexLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(indexLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.indexLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(indexButton, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.indexButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(indexButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.indexButton.text")); // NOI18N indexButton.setEnabled(false); indexButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -461,26 +461,26 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt } }); - org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.useForIngestCheckbox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.useForIngestCheckbox.text")); // NOI18N useForIngestCheckbox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { useForIngestCheckboxActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(showInboxMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.showInboxMessagesCheckBox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(showInboxMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.showInboxMessagesCheckBox.text")); // NOI18N showInboxMessagesCheckBox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showInboxMessagesCheckBoxActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(informationLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.informationLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(informationLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.informationLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.optionsLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.optionsLabel.text")); // NOI18N importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/new16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.importButton1.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.importButton1.text")); // NOI18N importButton1.setMaximumSize(new java.awt.Dimension(140, 25)); importButton1.setMinimumSize(new java.awt.Dimension(140, 25)); importButton1.setPreferredSize(new java.awt.Dimension(140, 25)); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java index 7fb3650df8..18b6a3914e 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java @@ -48,30 +48,24 @@ import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskException; public class HashDbIngestModule extends IngestModuleAbstractFile { - private static HashDbIngestModule instance = null; public final static String MODULE_NAME = "Hash Lookup"; public final static String MODULE_DESCRIPTION = "Identifies known and notables files using supplied hash databases, such as a standard NSRL database."; final public static String MODULE_VERSION = "1.0"; private static final Logger logger = Logger.getLogger(HashDbIngestModule.class.getName()); + private HashDbConfigPanel panel; private IngestServices services; private SleuthkitCase skCase; private static int messageId = 0; - private int knownBadCount; - // Whether or not to do hash lookups (only set to true if there are dbs set) - private boolean nsrlIsSet; - private boolean knownBadIsSet; + private int knownBadCount = 0; private boolean calcHashesIsSet; - private HashDb nsrlSet; - private int nsrlPointer; + private HashDb nsrlHashSet; + private ArrayList knownBadHashSets = new ArrayList<>(); static long calctime = 0; static long lookuptime = 0; - private Map knownBadSets = new HashMap<>(); - private HashSetsConfigurationPanel panel; private final Hash hasher = new Hash(); private HashDbIngestModule() { - knownBadCount = 0; } public static synchronized HashDbIngestModule getDefault() { @@ -95,76 +89,78 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { public String getVersion() { return MODULE_VERSION; } + + @Override + public boolean hasSimpleConfiguration() { + return true; + } + + @Override + public javax.swing.JPanel getSimpleConfiguration(String context) { + return new HashDbSimpleConfigPanel(); + } + + @Override + public void saveSimpleConfiguration() { + HashDbManager.getInstance().save(); + } + + @Override + public boolean hasAdvancedConfiguration() { + return true; + } + + @Override + public javax.swing.JPanel getAdvancedConfiguration(String context) { + if (panel == null) { + panel = new HashDbConfigPanel(); + } + panel.load(); + return panel; + } + + @Override + public void saveAdvancedConfiguration() { + if (panel != null) { + panel.store(); + } + } + @Override public void init(IngestModuleInit initContext) { services = IngestServices.getDefault(); - this.skCase = Case.getCurrentCase().getSleuthkitCase(); - try { - HashSetsManager hdbxml = HashSetsManager.getInstance(); - nsrlSet = null; - knownBadSets.clear(); - nsrlIsSet = false; - knownBadIsSet = false; - calcHashesIsSet = hdbxml.shouldAlwaysCalculateHashes(); + skCase = Case.getCurrentCase().getSleuthkitCase(); + HashDbManager hashDbManager = HashDbManager.getInstance(); - HashDb nsrl = hdbxml.getNSRLHashSet(); - if (nsrl != null && nsrl.getUseForIngest() && IndexStatus.isIngestible(nsrl.getStatus())) { - nsrlIsSet = true; - this.nsrlSet = nsrl; - nsrlPointer = skCase.setNSRLDatabase(nsrl.getDatabasePath()); - } + nsrlHashSet = null; + knownBadHashSets.clear(); + calcHashesIsSet = hashDbManager.shouldAlwaysCalculateHashes(); - for (HashDb db : hdbxml.getKnownBadHashSets()) { - IndexStatus status = db.getStatus(); - if (db.getUseForIngest() && IndexStatus.isIngestible(status)) { - knownBadIsSet = true; - int ret = skCase.addKnownBadDatabase(db.getDatabasePath()); - knownBadSets.put(ret, db); - } - } + HashDb nsrl = hashDbManager.getNSRLHashSet(); + if (nsrl != null && nsrl.getUseForIngest() && nsrl.hasLookupIndex()) { + nsrlHashSet = nsrl; + } - if (!nsrlIsSet) { - this.services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No NSRL database set", "Known file search will not be executed.")); - } - if (!knownBadIsSet) { - this.services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No known bad database set", "Known bad file search will not be executed.")); + for (HashDb db : hashDbManager.getKnownBadHashSets()) { + if (db.getUseForIngest() && db.hasLookupIndex()) { + knownBadHashSets.add(db); } + } - } catch (TskException ex) { - logger.log(Level.SEVERE, "Setting NSRL and Known database failed", ex); - this.services.postMessage(IngestMessage.createErrorMessage(++messageId, this, "Error Configuring Hash Databases", "Setting NSRL and Known database failed.")); + if (nsrlHashSet == null) { + services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No NSRL database set", "Known file search will not be executed.")); + } + if (knownBadHashSets.isEmpty()) { + services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No known bad database set", "Known bad file search will not be executed.")); } } @Override - public void complete() { - if ((knownBadIsSet) || (nsrlIsSet)) { - StringBuilder detailsSb = new StringBuilder(); - //details - detailsSb.append(""); - - detailsSb.append(""); - detailsSb.append(""); - - detailsSb.append("\n"); - detailsSb.append("\n"); - detailsSb.append("
Known bads found:").append(knownBadCount).append("
Total Calculation Time").append(calctime).append("
Total Lookup Time").append(lookuptime).append("
"); - - detailsSb.append("

Databases Used:

\n
    "); - for (HashDb db : knownBadSets.values()) { - detailsSb.append("
  • ").append(db.getDisplayName()).append("
  • \n"); - } - - detailsSb.append("
"); - services.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this, "Hash Lookup Results", detailsSb.toString())); - } + public boolean hasBackgroundJobsRunning() { + return false; } - - @Override - public void stop() { - } - + @Override public ProcessResult process(PipelineContextpipelineContext, AbstractFile file) { //skip unalloc @@ -174,51 +170,87 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { return processFile(file); } - - - @Override - public boolean hasBackgroundJobsRunning() { - return false; - } - - @Override - public boolean hasSimpleConfiguration() { - return true; - } - - @Override - public boolean hasAdvancedConfiguration() { - return true; - } - - @Override - public javax.swing.JPanel getSimpleConfiguration(String context) { - HashSetsManager.getInstance().loadLastSavedConfiguration(); - return new HashDbSimplePanel(); - } - - @Override - public javax.swing.JPanel getAdvancedConfiguration(String context) { - //return HashDbManagementPanel.getDefault(); - getPanel().load(); - return getPanel(); - } - - @Override - public void saveAdvancedConfiguration() { - getPanel().store(); - } - - private HashSetsConfigurationPanel getPanel() { - if (panel == null) { - panel = new HashSetsConfigurationPanel(); + + private ProcessResult processFile(AbstractFile file) { + // bail out if we have no hashes set + if ((nsrlHashSet == null) && (knownBadHashSets.isEmpty()) && (calcHashesIsSet == false)) { + return ProcessResult.OK; } - return panel; - } - @Override - public void saveSimpleConfiguration() { - HashSetsManager.getInstance().save(); + // calc hash value + String name = file.getName(); + String md5Hash = file.getMd5Hash(); + if (md5Hash == null || md5Hash.isEmpty()) { + try { + long calcstart = System.currentTimeMillis(); + md5Hash = hasher.calculateMd5(file); + calctime += (System.currentTimeMillis() - calcstart); + } catch (IOException ex) { + logger.log(Level.WARNING, "Error calculating hash of file " + name, ex); + services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Read Error: " + name, + "Error encountered while calculating the hash value for " + name + ".")); + return ProcessResult.ERROR; + } + } + + // look up in known bad first + TskData.FileKnown status = TskData.FileKnown.UKNOWN; + boolean foundBad = false; + ProcessResult ret = ProcessResult.OK; + for (HashDb db : knownBadHashSets) { + try { + long lookupstart = System.currentTimeMillis(); + status = db.lookUp(file); + lookuptime += (System.currentTimeMillis() - lookupstart); + } catch (TskException ex) { + logger.log(Level.WARNING, "Couldn't lookup known bad hash for file " + name + " - see sleuthkit log for details", ex); + services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, + "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.getDisplayName(); + processBadFile(file, md5Hash, hashSetName, db.getShowInboxMessages()); + } + } + + // only do NSRL if we didn't find a known bad + if (!foundBad && nsrlHashSet != null) { + try { + long lookupstart = System.currentTimeMillis(); + status = nsrlHashSet.lookUp(file); + lookuptime += (System.currentTimeMillis() - lookupstart); + } catch (TskException ex) { + logger.log(Level.WARNING, "Couldn't lookup NSRL hash for file " + name + " - see sleuthkit log for details", ex); + services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, + "Error encountered while looking up NSRL hash value for " + name + ".")); + ret = ProcessResult.ERROR; + } + + if (status.equals(TskData.FileKnown.KNOWN)) { + try { + skCase.setKnown(file, TskData.FileKnown.KNOWN); + } 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 (NSRL) state for " + name + ".")); + ret = ProcessResult.ERROR; + } + } + } + + return ret; } private void processBadFile(AbstractFile abstractFile, String md5Hash, String hashSetName, boolean showInboxMessage) { @@ -264,101 +296,41 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { } } + + @Override + public void complete() { + if ((!knownBadHashSets.isEmpty()) || (nsrlHashSet != null)) { + StringBuilder detailsSb = new StringBuilder(); + //details + detailsSb.append(""); - private ProcessResult processFile(AbstractFile file) { - // bail out if we have no hashes set - if ((nsrlIsSet == false) && (knownBadIsSet == false) && (calcHashesIsSet == false)) { - return ProcessResult.OK; - } + detailsSb.append(""); + detailsSb.append(""); - // calc hash value - String name = file.getName(); - String md5Hash = file.getMd5Hash(); - if (md5Hash == null || md5Hash.isEmpty()) { - try { - long calcstart = System.currentTimeMillis(); - md5Hash = hasher.calculateMd5(file); - calctime += (System.currentTimeMillis() - calcstart); - } catch (IOException ex) { - logger.log(Level.WARNING, "Error calculating hash of file " + name, ex); - services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Read Error: " + name, - "Error encountered while calculating the hash value for " + name + ".")); - return ProcessResult.ERROR; - } - } + detailsSb.append("\n"); + detailsSb.append("\n"); + detailsSb.append("
Known bads found:").append(knownBadCount).append("
Total Calculation Time").append(calctime).append("
Total Lookup Time").append(lookuptime).append("
"); - - // look up in known bad first - TskData.FileKnown status = TskData.FileKnown.UKNOWN; - boolean foundBad = false; - ProcessResult ret = ProcessResult.OK; - - if (knownBadIsSet) { - for (Map.Entry entry : knownBadSets.entrySet()) { - - try { - long lookupstart = System.currentTimeMillis(); - status = skCase.knownBadLookupMd5(md5Hash, entry.getKey()); - lookuptime += (System.currentTimeMillis() - lookupstart); - } catch (TskException ex) { - logger.log(Level.WARNING, "Couldn't lookup known bad hash for file " + name + " - see sleuthkit log for details", ex); - services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, - "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 = entry.getValue().getDisplayName(); - processBadFile(file, md5Hash, hashSetName, entry.getValue().getShowInboxMessages()); - } - } - } - - // only do NSRL if we didn't find a known bad - if (!foundBad && nsrlIsSet) { - try { - long lookupstart = System.currentTimeMillis(); - status = skCase.nsrlLookupMd5(md5Hash); - lookuptime += (System.currentTimeMillis() - lookupstart); - } catch (TskException ex) { - logger.log(Level.WARNING, "Couldn't lookup NSRL hash for file " + name + " - see sleuthkit log for details", ex); - services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, - "Error encountered while looking up NSRL hash value for " + name + ".")); - ret = ProcessResult.ERROR; + detailsSb.append("

Databases Used:

\n
    "); + for (HashDb db : knownBadHashSets) { + detailsSb.append("
  • ").append(db.getDisplayName()).append("
  • \n"); } - if (status.equals(TskData.FileKnown.KNOWN)) { - try { - skCase.setKnown(file, TskData.FileKnown.KNOWN); - } 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 (NSRL) state for " + name + ".")); - ret = ProcessResult.ERROR; - } - } + detailsSb.append("
"); + services.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this, "Hash Lookup Results", detailsSb.toString())); } - - return ret; } - public ArrayList getKnownBadSetNames() { - ArrayList knownBadSetNames = new ArrayList<>(); - HashSetsManager hdbxml = HashSetsManager.getInstance(); - for (HashDb db : hdbxml.getKnownBadHashSets()) { - knownBadSetNames.add(db.getDisplayName()); - } - return knownBadSetNames; + @Override + public void stop() { } - + +// public ArrayList getKnownBadSetNames() { +// ArrayList knownBadSetNames = new ArrayList<>(); +// HashDbManager hdbxml = HashDbManager.getInstance(); +// for (HashDb db : hdbxml.getKnownBadHashSets()) { +// knownBadSetNames.add(db.getDisplayName()); +// } +// return knownBadSetNames; +// } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java similarity index 94% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsManager.java rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java index a763184527..a041fd19a1 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsManager.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java @@ -45,7 +45,7 @@ import org.w3c.dom.NodeList; * that serve as hash sets for the identification of known files, known good files, * and known bad files. */ -public class HashSetsManager { +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"; @@ -59,8 +59,8 @@ public class HashSetsManager { 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(HashSetsManager.class.getName()); - private static HashSetsManager instance; + private static final Logger logger = Logger.getLogger(HashDbManager.class.getName()); + private static HashDbManager instance; private String xmlFile = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME; private List knownBadHashSets = new ArrayList<>(); private HashDb nsrlHashSet; @@ -69,14 +69,14 @@ public class HashSetsManager { /** * Gets the singleton instance of this class. */ - public static synchronized HashSetsManager getInstance() { + public static synchronized HashDbManager getInstance() { if (instance == null) { - instance = new HashSetsManager(); + instance = new HashDbManager(); } return instance; } - private HashSetsManager() { + private HashDbManager() { if (hashSetsConfigurationFileExists()) { readHashSetsConfigurationFromDisk(); } @@ -344,7 +344,7 @@ public class HashSetsManager { setCalc.setAttribute(SET_VALUE, calcValue); rootEl.appendChild(setCalc); - success = XMLUtil.saveDoc(HashSetsManager.class, xmlFile, ENCODING, doc); + success = XMLUtil.saveDoc(HashDbManager.class, xmlFile, ENCODING, doc); } catch (ParserConfigurationException e) { logger.log(Level.SEVERE, "Error saving hash sets: can't initialize parser.", e); @@ -353,7 +353,7 @@ public class HashSetsManager { } private boolean readHashSetsConfigurationFromDisk() { - final Document doc = XMLUtil.loadDoc(HashSetsManager.class, xmlFile, XSDFILE); + final Document doc = XMLUtil.loadDoc(HashDbManager.class, xmlFile, XSDFILE); if (doc == null) { return false; } @@ -437,7 +437,7 @@ public class HashSetsManager { } } catch (TskCoreException ex) { - Logger.getLogger(HashSetsManager.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); JOptionPane.showMessageDialog(null, "Unable to open " + paths.get(0) + " hash database.", "Open Hash Database Error", JOptionPane.ERROR_MESSAGE); } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.form similarity index 89% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.form rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.form index dc1fc4d1c0..3ad95c5229 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.form @@ -85,28 +85,28 @@ - + - + - + - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java similarity index 92% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java index c065211ebe..f33040b36b 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java @@ -32,18 +32,18 @@ import org.sleuthkit.datamodel.TskCoreException; * Instances of this class are used as a file ingest module configuration panel * by the known files hash set lookup file ingest module. */ -public class HashDbSimplePanel extends javax.swing.JPanel { +public class HashDbSimpleConfigPanel extends javax.swing.JPanel { private HashTableModel knownBadTableModel; private HashDb nsrl; - public HashDbSimplePanel() { + public HashDbSimpleConfigPanel() { knownBadTableModel = new HashTableModel(); initComponents(); customizeComponents(); } private void reloadCalc() { - final HashSetsManager xmlHandle = HashSetsManager.getInstance(); + final HashDbManager xmlHandle = HashDbManager.getInstance(); final HashDb nsrlDb = xmlHandle.getNSRLHashSet(); final boolean nsrlUsed = nsrlDb != null && nsrlDb.getUseForIngest()== true && nsrlDb.hasLookupIndex(); final List knowns = xmlHandle.getKnownBadHashSets(); @@ -70,7 +70,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } private void customizeComponents() { - final HashSetsManager xmlHandle = HashSetsManager.getInstance(); + final HashDbManager xmlHandle = HashDbManager.getInstance(); calcHashesButton.addActionListener( new ActionListener() { @Override @@ -104,7 +104,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } private void reloadSets() { - nsrl = HashSetsManager.getInstance().getNSRLHashSet(); + nsrl = HashDbManager.getInstance().getNSRLHashSet(); if (nsrl == null || nsrl.getUseForIngest() == false) { nsrlDbLabelVal.setText("Disabled"); @@ -144,13 +144,13 @@ public class HashDbSimplePanel extends javax.swing.JPanel { notableHashTable.setShowVerticalLines(false); jScrollPane1.setViewportView(notableHashTable); - jLabel1.setText(org.openide.util.NbBundle.getMessage(HashDbSimplePanel.class, "HashDbSimplePanel.jLabel1.text")); // NOI18N + jLabel1.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.jLabel1.text")); // NOI18N - nsrlDbLabel.setText(org.openide.util.NbBundle.getMessage(HashDbSimplePanel.class, "HashDbSimplePanel.nsrlDbLabel.text")); // NOI18N + nsrlDbLabel.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.nsrlDbLabel.text")); // NOI18N - calcHashesButton.setText(org.openide.util.NbBundle.getMessage(HashDbSimplePanel.class, "HashDbSimplePanel.calcHashesButton.text")); // NOI18N + calcHashesButton.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.calcHashesButton.text")); // NOI18N - nsrlDbLabelVal.setText(org.openide.util.NbBundle.getMessage(HashDbSimplePanel.class, "HashDbSimplePanel.nsrlDbLabelVal.text")); // NOI18N + nsrlDbLabelVal.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.nsrlDbLabelVal.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -199,7 +199,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { private class HashTableModel extends AbstractTableModel { - private HashSetsManager xmlHandle = HashSetsManager.getInstance(); + private HashDbManager xmlHandle = HashDbManager.getInstance(); private void resync() { fireTableDataChanged(); @@ -253,7 +253,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { if(((Boolean) getValueAt(rowIndex, columnIndex)) || IndexStatus.isIngestible(status)) { db.setUseForIngest((Boolean) aValue); } else { - JOptionPane.showMessageDialog(HashDbSimplePanel.this, "Databases must be indexed before they can be used for ingest"); + JOptionPane.showMessageDialog(HashDbSimpleConfigPanel.this, "Databases must be indexed before they can be used for ingest"); } reloadSets(); } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java index 2ff7930c0a..61e55c07b3 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java @@ -42,7 +42,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen List unindexed; HashDb toIndex; - HashSetsConfigurationPanel hdbmp; + HashDbConfigPanel hdbmp; int length = 0; int currentcount = 1; String currentDb = ""; @@ -53,7 +53,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed the list of unindexed databases to index. */ - ModalNoButtons(HashSetsConfigurationPanel hdbmp, java.awt.Frame parent, List unindexed) { + ModalNoButtons(HashDbConfigPanel hdbmp, java.awt.Frame parent, List unindexed) { super(parent, "Indexing databases", true); this.unindexed = unindexed; this.toIndex = null; @@ -68,7 +68,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed The unindexed database to index. */ - ModalNoButtons(HashSetsConfigurationPanel hdbmp, java.awt.Frame parent, HashDb unindexed){ + ModalNoButtons(HashDbConfigPanel hdbmp, java.awt.Frame parent, HashDb unindexed){ super(parent, "Indexing database", true); this.unindexed = null; this.toIndex = unindexed; From e78f49ee33a5a3d04c5a00fae155ed33e4249d43 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 6 Nov 2013 15:44:26 -0500 Subject: [PATCH 30/30] Assorted fixes to new hash database capabilities --- .../autopsy/hashdatabase/Bundle.properties | 6 +- .../autopsy/hashdatabase/HashDb.java | 9 +- .../hashdatabase/HashDbConfigPanel.form | 30 +- .../hashdatabase/HashDbConfigPanel.java | 291 ++++++++++-------- 4 files changed, 179 insertions(+), 157 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index 0d0a92c58d..c079f5c2c3 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -50,8 +50,6 @@ HashDbCreateDatabaseDialog.jLabel1.text=Display name of database: HashDbCreateDatabaseDialog.databaseNameTextField.text= HashDbConfigPanel.nameLabel.text=Name: HashDbConfigPanel.hashDbNameLabel.text=No database selected -HashDbConfigPanel.deleteButton.text=Delete Database -HashDbConfigPanel.importButton.text=Import Database HashDbConfigPanel.hashDatabasesLabel.text=Hash Databases: HashDbConfigPanel.hashDbLocationLabel.text=No database selected HashDbConfigPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. @@ -59,7 +57,6 @@ HashDbConfigPanel.jButton3.text=Import Database HashDbConfigPanel.jLabel6.text=Type: HashDbConfigPanel.jLabel4.text=Location: HashDbConfigPanel.jLabel2.text=Name: -HashDbConfigPanel.importButton1.text=New Database HashDbConfigPanel.optionsLabel.text=Options HashDbConfigPanel.typeLabel.text=Type: HashDbConfigPanel.locationLabel.text=Location: @@ -74,3 +71,6 @@ HashDbSimpleConfigPanel.nsrlDbLabelVal.text=- HashDbSimpleConfigPanel.calcHashesButton.text=Calculate hashes even if no hash database is selected HashDbSimpleConfigPanel.jLabel1.text=Enable known bad databases for ingest: HashDbSimpleConfigPanel.nsrlDbLabel.text=NSRL Database: +HashDbConfigPanel.newDatabaseButton.text=New Database +HashDbConfigPanel.importDatabaseButton.text=Import Database +HashDbConfigPanel.deleteDatabaseButton.text=Delete Database diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index 27078e012e..251a3e07cc 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -64,12 +64,7 @@ public class HashDb implements Comparable { * @throws TskCoreException */ public static HashDb openHashDatabase(String hashSetName, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType knownType) throws TskCoreException { - if (knownType == HashDb.KnownFilesType.NSRL) { - return new HashDb(SleuthkitJNI.openNSRLDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); - } - else { - return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); - } + return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); } /** @@ -258,7 +253,7 @@ public class HashDb implements Comparable { progress = ProgressHandleFactory.createHandle("Indexing " + displayName); progress.start(); progress.switchToIndeterminate(); - SleuthkitJNI.createLookupIndexForHashDatabase(handle); + SleuthkitJNI.createLookupIndexForHashDatabase(handle); // RJCTODO: There is nobody to catch, fix this. return null; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form index 9b1d50cc52..1d841ad64a 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form @@ -109,11 +109,11 @@ - + - + - + @@ -173,11 +173,11 @@ - - + + - + @@ -224,13 +224,13 @@ - + - + @@ -243,16 +243,16 @@ - + - + - + @@ -265,7 +265,7 @@ - + @@ -380,13 +380,13 @@ - + - + @@ -399,7 +399,7 @@ - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java index 85e5a178f5..e24ac3a7a1 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java @@ -50,7 +50,8 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel HashDbConfigPanel() { initComponents(); - customizeComponents(); + customizeComponents(); + updateComponentsForNoSelection(); } private void customizeComponents() { @@ -67,104 +68,126 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel updateComponents(); } } - }); + }); } private void updateComponents() { HashDb db = ((HashSetTable)hashSetTable).getSelection(); - if (db == null) { - hashDbLocationLabel.setText("No database selected"); - hashDbNameLabel.setText("No database selected"); - hashDbIndexStatusLabel.setText("No database selected"); - hashDbTypeLabel.setText("No database selected"); + if (db != null) { + updateComponentsForSelection(db); } else { - this.hashDbLocationLabel.setToolTipText(db.getDatabasePath()); - if (db.getDatabasePath().length() > 50){ - String shortenedPath = db.getDatabasePath(); - 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)); - hashDbLocationLabel.setText(shortenedPath); - } - else { - hashDbLocationLabel.setText(db.getDatabasePath()); - } - hashDbNameLabel.setText(db.getDisplayName()); - hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); - } - updateStatusComponents(db); - boolean ingestRunning = IngestManager.getDefault().isIngestRunning(); - boolean useForIngestEnabled = db != null && !ingestRunning; - boolean useForIngestSelected = db != null && db.getUseForIngest(); - boolean showInboxMessagesEnabled = db != null && !ingestRunning && useForIngestSelected && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD); - boolean showInboxMessagesSelected = db != null && db.getShowInboxMessages(); - boolean deleteButtonEnabled = db != null && !ingestRunning; - boolean importButtonEnabled = !ingestRunning; - useForIngestCheckbox.setSelected(useForIngestSelected); - useForIngestCheckbox.setEnabled(useForIngestEnabled); - showInboxMessagesCheckBox.setSelected(showInboxMessagesSelected); - showInboxMessagesCheckBox.setEnabled(showInboxMessagesEnabled); - deleteButton.setEnabled(deleteButtonEnabled); - importButton.setEnabled(importButtonEnabled); - optionsLabel.setEnabled(useForIngestEnabled || showInboxMessagesEnabled); - optionsSeparator.setEnabled(useForIngestEnabled || showInboxMessagesEnabled); - ingestWarningLabel.setVisible(ingestRunning); - importButton.setEnabled(!ingestRunning); // RJCTODO: What about the other buttons? + updateComponentsForNoSelection(); + } } - void updateStatusComponents(HashDb hashDb) { - if (hashDb == null) { - indexButton.setText("Index"); - hashDbIndexStatusLabel.setForeground(Color.black); - indexButton.setEnabled(false); + private void updateComponentsForNoSelection() { + boolean ingestIsRunning = IngestManager.getDefault().isIngestRunning(); + + // Update labels. + hashDbLocationLabel.setText("No database selected"); + hashDbNameLabel.setText("No database selected"); + hashDbIndexStatusLabel.setText("No database selected"); + hashDbTypeLabel.setText("No database selected"); + + // Update indexing components. + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.black); + indexButton.setEnabled(false); + + // Update ingest options. + useForIngestCheckbox.setSelected(false); + useForIngestCheckbox.setEnabled(false); + showInboxMessagesCheckBox.setSelected(false); + showInboxMessagesCheckBox.setEnabled(false); + optionsLabel.setEnabled(false); + optionsSeparator.setEnabled(false); + + // Update database action buttons. + newDatabaseButton.setEnabled(!ingestIsRunning); + importDatabaseButton.setEnabled(!ingestIsRunning); + deleteDatabaseButton.setEnabled(false); + + // Update ingest in progress warning label. + ingestWarningLabel.setVisible(ingestIsRunning); + } + + private void updateComponentsForSelection(HashDb db) { + boolean ingestIsRunning = IngestManager.getDefault().isIngestRunning(); + + // Update labels. + hashDbLocationLabel.setToolTipText(db.getDatabasePath()); + if (db.getDatabasePath().length() > 50){ + String shortenedPath = db.getDatabasePath(); + 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)); + hashDbLocationLabel.setText(shortenedPath); } else { - IndexStatus status = IndexStatus.UNKNOWN; - try { - status = hashDb.getStatus(); - } - catch (TskCoreException ex) { - // RJCTODO: Need a status unknown? - // Logger.getLogger(HashDbIngestModule.class.getName()) - } - - hashDbIndexStatusLabel.setText(status.message()); - switch (status) { - case NO_INDEX: - indexButton.setText("Index"); - hashDbIndexStatusLabel.setForeground(Color.red); - indexButton.setEnabled(true); - break; - case INDEXING: - indexButton.setText("Indexing"); - hashDbIndexStatusLabel.setForeground(Color.black); - indexButton.setEnabled(false); - break; - case UNKNOWN: - indexButton.setText("Index"); - hashDbIndexStatusLabel.setForeground(Color.red); - indexButton.setEnabled(false); - break; - case INDEXED: - // TODO: Restore ability to re-index an indexed - case INDEX_ONLY: - default: - indexButton.setText("Index"); - hashDbIndexStatusLabel.setForeground(Color.black); - indexButton.setEnabled(false); - break; - } + hashDbLocationLabel.setText(db.getDatabasePath()); } - - if (IngestManager.getDefault().isIngestRunning()) { + hashDbNameLabel.setText(db.getDisplayName()); + hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); + + // Update indexing components. + IndexStatus status = IndexStatus.UNKNOWN; + try { + status = db.getStatus(); + } + catch (TskCoreException ex) { + // RJCTODO + // Logger.getLogger(HashDbIngestModule.class.getName()) + } + hashDbIndexStatusLabel.setText(status.message()); + switch (status) { + case NO_INDEX: + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.red); + indexButton.setEnabled(true); + break; + case INDEXING: + indexButton.setText("Indexing"); + hashDbIndexStatusLabel.setForeground(Color.black); + indexButton.setEnabled(false); + break; + case UNKNOWN: + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.red); + indexButton.setEnabled(false); + break; + case INDEXED: + // TODO: Restore ability to re-index an indexed database. + case INDEX_ONLY: + default: + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.black); + indexButton.setEnabled(false); + break; + } + 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)); + + // Update database action buttons. + deleteDatabaseButton.setEnabled(!ingestIsRunning); + importDatabaseButton.setEnabled(!ingestIsRunning); + importDatabaseButton.setEnabled(!ingestIsRunning); + + // Update ingest in progress warning label. + ingestWarningLabel.setVisible(ingestIsRunning); } @Override public void load() { hashSetTable.clearSelection(); - hashSetTableModel.refresh(); -// updateComponents(null); + hashSetTableModel.refreshModel(); } @Override @@ -176,8 +199,7 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel unindexed.add(hashSet); } } - - // RJCTODO:Whaaaaat? + //If unindexed ones are found, show a popup box that will either index them, or remove them. if (unindexed.size() == 1){ showInvalidIndex(false, unindexed); @@ -185,7 +207,7 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel else if (unindexed.size() > 1){ showInvalidIndex(true, unindexed); } - + hashSetManager.save(); } @@ -198,7 +220,7 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel for (HashDb hashDb : toRemove) { hashSetManager.removeHashSet(hashDb); } - hashSetTableModel.refresh(); + hashSetTableModel.refreshModel(); } /** @@ -225,7 +247,7 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel indexingDialog.setLocationRelativeTo(null); indexingDialog.setVisible(true); indexingDialog.setModal(true); - hashSetTableModel.refresh(); + hashSetTableModel.refreshModel(); } if(res == JOptionPane.NO_OPTION){ JOptionPane.showMessageDialog(this, "All unindexed databases will be removed the list"); @@ -340,9 +362,13 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel return -1; } - void refresh() { + void refreshModel() { hashSets = HashDbManager.getInstance().getAllHashSets(); - fireTableDataChanged(); + refreshDisplay(); + } + + void refreshDisplay() { + fireTableDataChanged(); } } @@ -361,8 +387,8 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel ingestWarningLabel = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); hashSetTable = new HashSetTable(); - deleteButton = new javax.swing.JButton(); - importButton = new javax.swing.JButton(); + deleteDatabaseButton = new javax.swing.JButton(); + importDatabaseButton = new javax.swing.JButton(); hashDatabasesLabel = new javax.swing.JLabel(); nameLabel = new javax.swing.JLabel(); hashDbNameLabel = new javax.swing.JLabel(); @@ -379,7 +405,7 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel optionsLabel = new javax.swing.JLabel(); informationSeparator = new javax.swing.JSeparator(); optionsSeparator = new javax.swing.JSeparator(); - importButton1 = new javax.swing.JButton(); + newDatabaseButton = new javax.swing.JButton(); org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jLabel2.text")); // NOI18N @@ -413,25 +439,25 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel }); jScrollPane1.setViewportView(hashSetTable); - deleteButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/delete16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.deleteButton.text")); // NOI18N - deleteButton.setMaximumSize(new java.awt.Dimension(140, 25)); - deleteButton.setMinimumSize(new java.awt.Dimension(140, 25)); - deleteButton.setPreferredSize(new java.awt.Dimension(140, 25)); - deleteButton.addActionListener(new java.awt.event.ActionListener() { + deleteDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/delete16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteDatabaseButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.deleteDatabaseButton.text")); // NOI18N + deleteDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25)); + deleteDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25)); + deleteDatabaseButton.setPreferredSize(new java.awt.Dimension(140, 25)); + deleteDatabaseButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - deleteButtonActionPerformed(evt); + deleteDatabaseButtonActionPerformed(evt); } }); - importButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/import16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(importButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.importButton.text")); // NOI18N - importButton.setMaximumSize(new java.awt.Dimension(140, 25)); - importButton.setMinimumSize(new java.awt.Dimension(140, 25)); - importButton.setPreferredSize(new java.awt.Dimension(140, 25)); - importButton.addActionListener(new java.awt.event.ActionListener() { + importDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/import16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(importDatabaseButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.importDatabaseButton.text")); // NOI18N + importDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25)); + importDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25)); + importDatabaseButton.setPreferredSize(new java.awt.Dimension(140, 25)); + importDatabaseButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - importButtonActionPerformed(evt); + importDatabaseButtonActionPerformed(evt); } }); @@ -479,14 +505,14 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.optionsLabel.text")); // NOI18N - importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/new16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.importButton1.text")); // NOI18N - importButton1.setMaximumSize(new java.awt.Dimension(140, 25)); - importButton1.setMinimumSize(new java.awt.Dimension(140, 25)); - importButton1.setPreferredSize(new java.awt.Dimension(140, 25)); - importButton1.addActionListener(new java.awt.event.ActionListener() { + 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() { public void actionPerformed(java.awt.event.ActionEvent evt) { - importButton1ActionPerformed(evt); + newDatabaseButtonActionPerformed(evt); } }); @@ -534,10 +560,10 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel .addComponent(showInboxMessagesCheckBox) .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE))))) .addGroup(layout.createSequentialGroup() - .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(newDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(importButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) + .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)) .addContainerGap(40, Short.MAX_VALUE)) ); layout.setVerticalGroup( @@ -585,10 +611,10 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 391, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(importButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .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)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) ); }// //GEN-END:initComponents @@ -604,8 +630,9 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) { HashDb selectedHashDb = ((HashSetTable)hashSetTable).getSelection(); if (selectedHashDb != null && hashDbToBeIndexed != null && hashDbToBeIndexed.equals(selectedHashDb)) { - updateStatusComponents(selectedHashDb); + updateComponents(); } + hashSetTableModel.refreshDisplay(); } } }); @@ -623,22 +650,22 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel } }//GEN-LAST:event_indexButtonActionPerformed - private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed + 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) { HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); if (hashDb != null) { hashSetManager.removeHashSet(hashDb); - hashSetTableModel.refresh(); + hashSetTableModel.refreshModel(); } } - }//GEN-LAST:event_deleteButtonActionPerformed + }//GEN-LAST:event_deleteDatabaseButtonActionPerformed private void hashSetTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_hashSetTableKeyPressed if (evt.getKeyCode() == KeyEvent.VK_DELETE) { HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); if (hashDb != null) { hashSetManager.removeHashSet(hashDb); - hashSetTableModel.refresh(); + hashSetTableModel.refreshModel(); } } }//GEN-LAST:event_hashSetTableKeyPressed @@ -658,34 +685,33 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel } }//GEN-LAST:event_showInboxMessagesCheckBoxActionPerformed - private void importButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importButtonActionPerformed + private void importDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importDatabaseButtonActionPerformed HashDb hashDb = new HashDbImportDatabaseDialog().doDialog(); if (hashDb != null) { hashSetManager.addHashSet(hashDb); - hashSetTableModel.refresh(); + hashSetTableModel.refreshModel(); ((HashSetTable)hashSetTable).selectRowByName(hashDb.getDisplayName()); } - }//GEN-LAST:event_importButtonActionPerformed + }//GEN-LAST:event_importDatabaseButtonActionPerformed - private void importButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importButton1ActionPerformed + private void newDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newDatabaseButtonActionPerformed HashDb hashDb = new HashDbCreateDatabaseDialog().doDialog(); if (null != hashDb) { hashSetManager.addHashSet(hashDb); - hashSetTableModel.refresh(); + hashSetTableModel.refreshModel(); ((HashSetTable)hashSetTable).selectRowByName(hashDb.getDisplayName()); } - }//GEN-LAST:event_importButton1ActionPerformed + }//GEN-LAST:event_newDatabaseButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton deleteButton; + private javax.swing.JButton deleteDatabaseButton; private javax.swing.JLabel hashDatabasesLabel; private javax.swing.JLabel hashDbIndexStatusLabel; private javax.swing.JLabel hashDbLocationLabel; private javax.swing.JLabel hashDbNameLabel; private javax.swing.JLabel hashDbTypeLabel; private javax.swing.JTable hashSetTable; - private javax.swing.JButton importButton; - private javax.swing.JButton importButton1; + private javax.swing.JButton importDatabaseButton; private javax.swing.JButton indexButton; private javax.swing.JLabel indexLabel; private javax.swing.JLabel informationLabel; @@ -698,6 +724,7 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel 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;