Merge branch 'develop-rc1' into develop

This commit is contained in:
Brian Carrier 2013-12-03 10:15:22 -05:00
commit e68262fd7c
15 changed files with 1420 additions and 1069 deletions

View File

@ -95,5 +95,9 @@
<package>org.sleuthkit.autopsy.hashdatabase</package>
</public-packages>
</data>
<spellchecker-wordlist xmlns="http://www.netbeans.org/ns/spellchecker-wordlist/1">
<word>openide</word>
<word>org</word>
</spellchecker-wordlist>
</configuration>
</project>
</project>

View File

@ -24,7 +24,6 @@ import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
@ -35,124 +34,128 @@ import org.sleuthkit.autopsy.ingest.IngestConfigurator;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException;
import static org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
/**
* Instances of this Action allow users to content to a hash database.
* Instances of this Action allow users to content to a hash database.
*/
public class AddContentToHashDbAction extends AbstractAction implements Presenter.Popup {
// This class is a singleton to support multi-selection of nodes, since
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
// node in the array returns a reference to the same action object from Node.getActions(boolean).
final class AddContentToHashDbAction extends AbstractAction implements Presenter.Popup {
private static AddContentToHashDbAction instance;
private static String SINGLE_SELECTION_NAME = "Add file to hash database";
private static String MULTIPLE_SELECTION_NAME = "Add files to hash database";
private String menuText;
/**
* AddContentToHashDbAction is a singleton to support multi-selection of nodes, since
* org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action from a node
* if every node in the nodes array returns a reference to the same action object from
* Node.getActions(boolean).
*/
public static synchronized AddContentToHashDbAction getInstance() {
if (null == instance) {
instance = new AddContentToHashDbAction();
}
instance.setEnabled(true);
instance.putValue(Action.NAME, SINGLE_SELECTION_NAME);
instance.menuText = SINGLE_SELECTION_NAME;
// Disable the action if file ingest is in progress.
IngestConfigurator ingestConfigurator = Lookup.getDefault().lookup(IngestConfigurator.class);
if (null != ingestConfigurator && ingestConfigurator.isIngestRunning()) {
instance.setEnabled(false);
}
// Set the name of the action based on the selected content and disable the action if there is
// selected content without an MD5 hash.
Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
if (selectedFiles.size() > 1) {
instance.putValue(Action.NAME, MULTIPLE_SELECTION_NAME);
instance.menuText = MULTIPLE_SELECTION_NAME;
}
if (selectedFiles.isEmpty()) {
instance.setEnabled(false);
}
else {
for (AbstractFile file : selectedFiles) {
if (null == file.getMd5Hash()) {
instance.setEnabled(false);
break;
}
}
}
}
return instance;
}
private AddContentToHashDbAction() {
super(SINGLE_SELECTION_NAME);
}
@Override
public JMenuItem getPopupPresenter() {
return new AddContentToHashDbMenu(menuText);
return new AddContentToHashDbMenu();
}
@Override
public void actionPerformed(ActionEvent event) {
}
private class AddContentToHashDbMenu extends JMenu {
AddContentToHashDbMenu(String menuText) {
super(menuText);
// Instances of this class are used to implement the a pop up menu for this
// action.
private final class AddContentToHashDbMenu extends JMenu {
private final static String SINGLE_SELECTION_NAME = "Add file to hash database";
private final static String MULTIPLE_SELECTION_NAME = "Add files to hash database";
AddContentToHashDbMenu() {
super(SINGLE_SELECTION_NAME);
// Disable the menu if file ingest is in progress.
IngestConfigurator ingestConfigurator = Lookup.getDefault().lookup(IngestConfigurator.class);
if (null != ingestConfigurator && ingestConfigurator.isIngestRunning()) {
setEnabled(false);
return;
}
// Get any AbstractFile objects from the lookup of the currently focused top component.
final Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
if (selectedFiles.isEmpty()) {
setEnabled(false);
return;
}
else if (selectedFiles.size() > 1) {
setText(MULTIPLE_SELECTION_NAME);
}
// Disable the menu if hashes have not been calculated.
for (AbstractFile file : selectedFiles) {
if (null == file.getMd5Hash()) {
setEnabled(false);
return;
}
}
// Get the current set of updateable hash databases and add each
// one as a menu item.
List<HashDb> hashDatabases = HashDbManager.getInstance().getUpdateableHashSets();
// one to the menu as a separate menu item. Selecting a hash database
// adds the selected files to the selected database.
final List<HashDb> hashDatabases = HashDbManager.getInstance().getUpdateableHashSets();
if (!hashDatabases.isEmpty()) {
for (final HashDb database : hashDatabases) {
JMenuItem databaseItem = add(database.getHashSetName());
databaseItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
addContentToHashSet(database);
addFilesToHashSet(selectedFiles, database);
}
});
}
}
else {
JMenuItem empty = new JMenuItem("No hash databases");
JMenuItem empty = new JMenuItem("No hash databases configured");
empty.setEnabled(false);
add(empty);
}
// Add a "New Hash Set..." menu item.
// Add a "New Hash Set..." menu item. Selecting this item invokes a
// a hash database creation dialog and adds the selected files to the
// the new database.
addSeparator();
JMenuItem newHashSetItem = new JMenuItem("New Hash Set...");
JMenuItem newHashSetItem = new JMenuItem("Create database...");
newHashSetItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
HashDb hashDb = new HashDbCreateDatabaseDialog().doDialog();
HashDb hashDb = new HashDbCreateDatabaseDialog().getHashDatabase();
if (null != hashDb) {
HashDbManager hashSetManager = HashDbManager.getInstance();
hashSetManager.addHashSet(hashDb);
hashSetManager.save();
addContentToHashSet(hashDb);
HashDbManager.getInstance().save();
addFilesToHashSet(selectedFiles, hashDb);
}
}
});
add(newHashSetItem);
}
private void addContentToHashSet(HashDb hashSet) {
Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
for (AbstractFile file : selectedFiles) {
private void addFilesToHashSet(final Collection<? extends AbstractFile> files, HashDb hashSet) {
for (AbstractFile file : files) {
String md5Hash = file.getMd5Hash();
if (null != md5Hash) {
try {
hashSet.add(file);
hashSet.addHashes(file);
}
catch (TskCoreException ex) {
Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error adding to hash database", ex);
JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + " to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE);
JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + " to the hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE);
}
}
}
else {
JOptionPane.showMessageDialog(null, "Unable to add the " + (files.size() > 1 ? "files" : "file") + " to the hash database. Hashes have not been calculated. Please configure and run an appropriate ingest module.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE);
break;
}
}
}
}

View File

@ -22,26 +22,15 @@ HashDbSearchPanel.errorField.text=Error: Not all files have been hashed.
HashDbSearchPanel.saveBox.text=Remember Hashes
HashDbSearchPanel.cancelButton.text=Cancel
OpenIDE-Module-Short-Description=Hash Database Ingest Module and hash db tools
HashDbImportDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest
HashDbImportDatabaseDialog.useForIngestCheckbox.text=Enable for ingest
HashDbImportDatabaseDialog.jLabel1.text=Hash Set Name:
HashDbImportDatabaseDialog.databaseNameTextField.text=
HashDbImportDatabaseDialog.databasePathTextField.text=
HashDbImportDatabaseDialog.browseButton.text=Browse
HashDbImportDatabaseDialog.knownBadRadioButton.text=Known Bad
HashDbImportDatabaseDialog.jLabel2.text=Type of database:
HashDbImportDatabaseDialog.okButton.text=OK
HashDbImportDatabaseDialog.cancelButton.text=Cancel
HashDbCreateDatabaseDialog.jLabel2.text=Type of database:
HashDbCreateDatabaseDialog.jLabel2.text=Type:
HashDbCreateDatabaseDialog.knownBadRadioButton.text=Known Bad
HashDbCreateDatabaseDialog.browseButton.text=Browse
HashDbCreateDatabaseDialog.databasePathTextField.text=
HashDbCreateDatabaseDialog.cancelButton.text=Cancel
HashDbCreateDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest
HashDbCreateDatabaseDialog.okButton.text=OK
HashDbCreateDatabaseDialog.useForIngestCheckbox.text=Enable for ingest
HashDbCreateDatabaseDialog.jLabel1.text=Hash Set Name:
HashDbCreateDatabaseDialog.databaseNameTextField.text=
HashDbConfigPanel.nameLabel.text=Hash Set Name:
HashDbConfigPanel.hashDbNameLabel.text=No database selected
HashDbConfigPanel.hashDatabasesLabel.text=Hash Databases:
@ -58,11 +47,7 @@ HashDbConfigPanel.hashDbIndexStatusLabel.text=No database selected
HashDbConfigPanel.hashDbTypeLabel.text=No database selected
HashDbConfigPanel.indexButton.text=Index
HashDbConfigPanel.indexLabel.text=Index Status:
HashDbConfigPanel.showInboxMessagesCheckBox.text=Enable sending messages to inbox during ingest
HashDbConfigPanel.useForIngestCheckbox.text=Enable for ingest
HashDbConfigPanel.informationLabel.text=Information
HashDbSimpleConfigPanel.calcHashesButton.text=Calculate hashes even if no hash database is selected
HashDbConfigPanel.newDatabaseButton.text=New Database
HashDbConfigPanel.importDatabaseButton.text=Import Database
HashDbConfigPanel.deleteDatabaseButton.text=Delete Database
HashDbConfigPanel.indexPathLabelLabel.text=Index Path:
@ -75,4 +60,22 @@ ModalNoButtons.CANCEL_BUTTON.text=Cancel
HashDbSimpleConfigPanel.knownBadHashDbsLabel.text=Enable known bad databases for ingest:
HashDbSimpleConfigPanel.knownHashDbsLabel.text=Enable known hash databases for ingest:
HashDbImportDatabaseDialog.knownRadioButton.text=Known (NSRL or other)
HashDbCreateDatabaseDialog.knownRadioButton.text=Known (NSRL or other)
HashDbCreateDatabaseDialog.knownRadioButton.text=Known
HashDbCreateDatabaseDialog.jLabel1.text=Database Path:
HashDbCreateDatabaseDialog.saveAsButton.text=Save As...
HashDbCreateDatabaseDialog.hashSetNameTextField.text=
HashDbImportDatabaseDialog.jLabel3.text=Database Path:
HashDbCreateDatabaseDialog.searchDuringIngestCheckbox.text=Search during ingest
HashDbCreateDatabaseDialog.searchDuringIngestCheckbox.toolTipText=
HashDbCreateDatabaseDialog.sendIngestMessagesCheckbox.text=Send ingest messages
HashDbImportDatabaseDialog.searchDuringIngestCheckbox.text=Search during ingest
HashDbImportDatabaseDialog.sendIngestMessagesCheckbox.text=Send ingest messages
HashDbImportDatabaseDialog.hashSetNameTextField.text=
HashDbConfigPanel.createDatabaseButton.text=Create Database
HashDbImportDatabaseDialog.openButton.text=Open...
HashDbSimpleConfigPanel.alwaysCalcHashesCheckbox.text=Calculate hashes even if no hash database is selected
HashDbCreateDatabaseDialog.jLabel3.text=Hash Set Name:
HashDbCreateDatabaseDialog.okButton.text=OK
HashDbCreateDatabaseDialog.databasePathTextField.text=
HashDbConfigPanel.searchDuringIngestCheckbox.text=Search during ingest
HashDbConfigPanel.sendIngestMessagesCheckBox.text=Send ingest messages

View File

@ -1,287 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.hashdatabase;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.HashInfo;
import org.sleuthkit.datamodel.SleuthkitJNI;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/**
* Instances of this class represent hash databases used to classify files as
* known or know bad.
*/
public class HashDb {
/**
* Property change events published by hash database objects.
*/
public enum Event {
INDEXING_DONE
}
/**
* The classification to apply to files whose hashes are stored in the
* hash database.
*/
public enum KnownFilesType{
KNOWN("Known"),
KNOWN_BAD("Known Bad");
private String displayName;
private KnownFilesType(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return this.displayName;
}
}
private int handle;
private KnownFilesType knownFilesType;
private String databasePath;
private String indexPath;
private String hashSetName;
private boolean useForIngest;
private boolean sendHitMessages;
private boolean indexing;
private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
/**
* Opens an existing hash database.
* @param hashSetName Name used to represent the hash database in user interface components.
* @param selectedFilePath Full path to either a hash database file or a hash database index file.
* @param useForIngest A flag indicating whether or not the hash database should be used during ingest.
* @param sendHitMessages A flag indicating whether hash set hit messages should be sent to the application in box.
* @param knownFilesType The classification to apply to files whose hashes are stored in the hash database.
* @return A HashDb object representation of the new hash database.
* @throws TskCoreException
*/
public static HashDb openHashDatabase(String hashSetName, String selectedFilePath, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) throws TskCoreException {
int handle = SleuthkitJNI.openHashDatabase(selectedFilePath);
return new HashDb(handle, SleuthkitJNI.getHashDatabasePath(handle), SleuthkitJNI.getHashDatabaseIndexPath(handle), hashSetName, useForIngest, sendHitMessages, knownFilesType);
}
/**
* Creates a new hash database.
* @param hashSetName Hash set name used to represent the hash database in user interface components.
* @param databasePath Full path to the database file to be created. The file name component of the path must have a ".kdb" extension.
* @param useForIngest A flag indicating whether or not the data base should be used during the file ingest process.
* @param showInboxMessages A flag indicating whether messages indicating lookup hits should be sent to the application in box.
* @param hashSetType The type of hash set to associate with the database.
* @return A HashDb object representation of the opened hash database.
* @throws TskCoreException
*/
public static HashDb createHashDatabase(String hashSetName, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType knownFilesType) throws TskCoreException {
int handle = SleuthkitJNI.createHashDatabase(databasePath);
return new HashDb(handle, SleuthkitJNI.getHashDatabasePath(handle), SleuthkitJNI.getHashDatabaseIndexPath(handle), hashSetName, useForIngest, showInboxMessages, knownFilesType);
}
private HashDb(int handle, String databasePath, String indexPath, String name, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) {
this.databasePath = databasePath;
this.indexPath = indexPath;
this.hashSetName = name;
this.useForIngest = useForIngest;
this.sendHitMessages = sendHitMessages;
this.knownFilesType = knownFilesType;
this.handle = handle;
this.indexing = false;
}
/**
* Adds a listener for the events defined in HashDb.Event.
*/
public void addPropertyChangeListener(PropertyChangeListener pcl) {
propertyChangeSupport.addPropertyChangeListener(pcl);
}
/**
* Removes a listener for the events defined in HashDb.Event.
*/
public void removePropertyChangeListener(PropertyChangeListener pcl) {
propertyChangeSupport.removePropertyChangeListener(pcl);
}
public String getHashSetName() {
return hashSetName;
}
public String getDatabasePath() {
return databasePath;
}
public String getIndexPath() {
return indexPath;
}
public KnownFilesType getKnownFilesType() {
return knownFilesType;
}
public boolean getUseForIngest() {
return useForIngest;
}
void setUseForIngest(boolean useForIngest) {
this.useForIngest = useForIngest;
}
public boolean getShowInboxMessages() {
return sendHitMessages;
}
void setShowInboxMessages(boolean showInboxMessages) {
this.sendHitMessages = showInboxMessages;
}
public boolean hasLookupIndex() throws TskCoreException {
return SleuthkitJNI.hashDatabaseHasLookupIndex(handle);
}
public boolean canBeReindexed() throws TskCoreException {
return SleuthkitJNI.hashDatabaseCanBeReindexed(handle);
}
public boolean hasIndexOnly() throws TskCoreException {
return SleuthkitJNI.hashDatabaseHasLegacyLookupIndexOnly(handle);
}
/**
* Indicates whether the hash database accepts updates.
* @return True if the database accepts updates, false otherwise.
*/
public boolean isUpdateable() throws TskCoreException {
return SleuthkitJNI.isUpdateableHashDatabase(this.handle);
}
/**
* Adds hashes of content (if calculated) to the hash database.
* @param content The content for which the calculated hashes, if any, are to be added to the hash database.
* @throws TskCoreException
*/
public void add(Content content) throws TskCoreException {
add(content, null);
}
/**
* Adds hashes of content (if calculated) to the hash database.
* @param content The content for which the calculated hashes, if any, are to be added to the hash database.
* @param comment A comment to associate with the hashes, e.g., the name of the case in which the content was encountered.
* @throws TskCoreException
*/
public void add(Content content, String comment) throws TskCoreException {
// TODO: This only works for AbstractFiles at present. Change when Content
// can be queried for hashes.
assert content instanceof AbstractFile;
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile)content;
// TODO: Add support for SHA-1 and SHA-256 hashes.
if (null != file.getMd5Hash()) {
SleuthkitJNI.addToHashDatabase(file.getName(), file.getMd5Hash(), null, null, comment, handle);
}
}
}
public boolean lookUp(Content content) throws TskCoreException {
boolean result = false;
// TODO: This only works for AbstractFiles at present. Change when Content can be queried for hashes.
assert content instanceof AbstractFile;
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile)content;
// TODO: Add support for SHA-1 and SHA-256 hashes.
if (null != file.getMd5Hash()) {
result = SleuthkitJNI.lookupInHashDatabase(file.getMd5Hash(), handle);
}
}
return result;
}
public HashInfo lookUpVerbose(Content content) throws TskCoreException {
HashInfo result = null;
// TODO: This only works for AbstractFiles at present. Change when Content can be queried for hashes.
assert content instanceof AbstractFile;
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile)content;
// TODO: Add support for SHA-1 and SHA-256 hashes.
if (null != file.getMd5Hash()) {
result = SleuthkitJNI.lookupInHashDatabaseVerbose(file.getMd5Hash(), handle);
}
}
return result;
}
boolean isIndexing() {
return indexing;
}
// Tries to index the database (overwrites any existing index) using a
// SwingWorker.
void createIndex(boolean deleteIndexFile) {
CreateIndex creator = new CreateIndex(deleteIndexFile);
creator.execute();
}
private class CreateIndex extends SwingWorker<Object,Void> {
private ProgressHandle progress;
private boolean deleteIndexFile;
CreateIndex(boolean deleteIndexFile) {
this.deleteIndexFile = deleteIndexFile;
};
@Override
protected Object doInBackground() {
indexing = true;
progress = ProgressHandleFactory.createHandle("Indexing " + hashSetName);
progress.start();
progress.switchToIndeterminate();
try {
SleuthkitJNI.createLookupIndexForHashDatabase(handle, deleteIndexFile);
indexPath = SleuthkitJNI.getHashDatabaseIndexPath(handle);
}
catch (TskCoreException ex) {
Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error indexing hash database", ex);
JOptionPane.showMessageDialog(null, "Error indexing hash database for " + getHashSetName() + ".", "Hash Database Index Error", JOptionPane.ERROR_MESSAGE);
}
return null;
}
@Override
protected void done() {
indexing = false;
progress.finish();
propertyChangeSupport.firePropertyChange(Event.INDEXING_DONE.toString(), null, hashSetName);
}
}
public void close() throws TskCoreException {
SleuthkitJNI.closeHashDatabase(handle);
}
}

View File

@ -60,7 +60,6 @@
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hashDatabasesLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Component id="jScrollPane1" min="-2" pref="275" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
@ -74,13 +73,6 @@
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="nameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="53" max="-2" attributes="0"/>
<Component id="hashDbNameLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="useForIngestCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="showInboxMessagesCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="locationLabel" alignment="0" min="-2" max="-2" attributes="0"/>
@ -97,6 +89,21 @@
<Component id="hashDbIndexStatusLabel" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="nameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="53" max="-2" attributes="0"/>
<Component id="hashDbNameLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="searchDuringIngestCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
<Component id="sendIngestMessagesCheckBox" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
@ -106,12 +113,20 @@
</Group>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="newDatabaseButton" min="-2" pref="133" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="importDatabaseButton" min="-2" pref="133" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hashDatabasesLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="deleteDatabaseButton" alignment="0" pref="0" max="32767" attributes="0"/>
<Component id="createDatabaseButton" min="-2" pref="137" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="importDatabaseButton" min="-2" pref="133" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Component id="deleteDatabaseButton" alignment="0" min="-2" pref="133" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="24" max="-2" attributes="0"/>
</Group>
@ -165,9 +180,9 @@
<Component id="optionsSeparator" min="-2" pref="6" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="useForIngestCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="searchDuringIngestCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="showInboxMessagesCheckBox" min="-2" max="-2" attributes="0"/>
<Component id="sendIngestMessagesCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="ingestWarningLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
@ -177,7 +192,7 @@
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="importDatabaseButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="newDatabaseButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="createDatabaseButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="deleteDatabaseButton" min="-2" max="-2" attributes="0"/>
@ -345,24 +360,24 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="indexButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="useForIngestCheckbox">
<Component class="javax.swing.JCheckBox" name="searchDuringIngestCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.useForIngestCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.searchDuringIngestCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useForIngestCheckboxActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="searchDuringIngestCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="showInboxMessagesCheckBox">
<Component class="javax.swing.JCheckBox" name="sendIngestMessagesCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.showInboxMessagesCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.sendIngestMessagesCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showInboxMessagesCheckBoxActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="sendIngestMessagesCheckBoxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="informationLabel">
@ -383,13 +398,13 @@
</Component>
<Component class="javax.swing.JSeparator" name="optionsSeparator">
</Component>
<Component class="javax.swing.JButton" name="newDatabaseButton">
<Component class="javax.swing.JButton" name="createDatabaseButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/hashdatabase/new16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.newDatabaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbConfigPanel.createDatabaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[140, 25]"/>
@ -402,7 +417,7 @@
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="newDatabaseButtonActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="createDatabaseButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="indexPathLabelLabel">

View File

@ -40,13 +40,16 @@ import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb.KnownFilesType;
/**
* Instances of this class provide a comprehensive UI for managing the hash sets configuration.
*/
public final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel {
private static final String NO_SELECTION_TEXT = "No database selected";
private static final String ERROR_GETTING_INDEX_STATUS = "Error occurred getting status";
private static final String ERROR_GETTING_PATH_TEXT = "Error occurred getting path";
private static final String ERROR_GETTING_INDEX_STATUS_TEXT = "Error occurred getting status";
private static final String LEGACY_INDEX_FILE_EXTENSION = "-md5.idx";
private HashDbManager hashSetManager = HashDbManager.getInstance();
private HashSetTableModel hashSetTableModel = new HashSetTableModel();
@ -55,8 +58,19 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
initComponents();
customizeComponents();
updateComponentsForNoSelection();
// Listen to the ingest modules to refresh the enabled/disabled state of
// the components in sync with file ingest.
IngestManager.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (isFileIngestStatusChangeEvent(evt)) {
updateComponents();
}
}
});
}
private void customizeComponents() {
setName("Hash Set Configuration");
this.ingestWarningLabel.setVisible(false);
@ -100,16 +114,16 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
indexButton.setEnabled(false);
// Update ingest options.
useForIngestCheckbox.setSelected(false);
useForIngestCheckbox.setEnabled(false);
showInboxMessagesCheckBox.setSelected(false);
showInboxMessagesCheckBox.setEnabled(false);
searchDuringIngestCheckbox.setSelected(false);
searchDuringIngestCheckbox.setEnabled(false);
sendIngestMessagesCheckBox.setSelected(false);
sendIngestMessagesCheckBox.setEnabled(false);
optionsLabel.setEnabled(false);
optionsSeparator.setEnabled(false);
// Update database action buttons.
newDatabaseButton.setEnabled(!ingestIsRunning);
importDatabaseButton.setEnabled(!ingestIsRunning);
createDatabaseButton.setEnabled(true);
importDatabaseButton.setEnabled(true);
deleteDatabaseButton.setEnabled(false);
// Update ingest in progress warning label.
@ -122,8 +136,22 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
// Update descriptive labels.
hashDbNameLabel.setText(db.getHashSetName());
hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName());
hashDbLocationLabel.setText(shortenPath(db.getDatabasePath()));
indexPathLabel.setText(shortenPath(db.getIndexPath()));
try {
hashDbLocationLabel.setText(shortenPath(db.getDatabasePath()));
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting database path of " + db.getHashSetName() + " hash database", ex);
hashDbLocationLabel.setText(ERROR_GETTING_PATH_TEXT);
}
try {
indexPathLabel.setText(shortenPath(db.getIndexPath()));
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index path of " + db.getHashSetName() + " hash database", ex);
indexPathLabel.setText(ERROR_GETTING_PATH_TEXT);
}
// Update indexing components.
try {
@ -144,7 +172,7 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
hashDbIndexStatusLabel.setText("Indexed");
}
hashDbIndexStatusLabel.setForeground(Color.black);
if (db.canBeReindexed()) {
if (db.canBeReIndexed()) {
indexButton.setText("Re-Index");
indexButton.setEnabled(true);
}
@ -162,29 +190,29 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index state of hash database", ex);
hashDbIndexStatusLabel.setText(ERROR_GETTING_INDEX_STATUS);
hashDbIndexStatusLabel.setText(ERROR_GETTING_INDEX_STATUS_TEXT);
hashDbIndexStatusLabel.setForeground(Color.red);
indexButton.setText("Index");
indexButton.setEnabled(false);
}
// Diable the indexing button if ingest is in progress.
// Disable the indexing button if ingest is in progress.
if (ingestIsRunning) {
indexButton.setEnabled(false);
}
// Update ingest option components.
useForIngestCheckbox.setSelected(db.getUseForIngest());
useForIngestCheckbox.setEnabled(!ingestIsRunning);
showInboxMessagesCheckBox.setSelected(db.getShowInboxMessages());
showInboxMessagesCheckBox.setEnabled(!ingestIsRunning && db.getUseForIngest() && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD));
optionsLabel.setEnabled(!ingestIsRunning && db.getUseForIngest() && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD));
optionsSeparator.setEnabled(!ingestIsRunning && db.getUseForIngest() && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD));
searchDuringIngestCheckbox.setSelected(db.getSearchDuringIngest());
searchDuringIngestCheckbox.setEnabled(!ingestIsRunning);
sendIngestMessagesCheckBox.setSelected(db.getSendIngestMessages());
sendIngestMessagesCheckBox.setEnabled(!ingestIsRunning && db.getSearchDuringIngest() && db.getKnownFilesType().equals(KnownFilesType.KNOWN_BAD));
optionsLabel.setEnabled(!ingestIsRunning);
optionsSeparator.setEnabled(!ingestIsRunning);
// Update database action buttons.
createDatabaseButton.setEnabled(true);
importDatabaseButton.setEnabled(true);
deleteDatabaseButton.setEnabled(!ingestIsRunning);
importDatabaseButton.setEnabled(!ingestIsRunning);
importDatabaseButton.setEnabled(!ingestIsRunning);
// Update ingest in progress warning label.
ingestWarningLabel.setVisible(ingestIsRunning);
@ -198,6 +226,10 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
return shortenedPath;
}
private boolean isFileIngestStatusChangeEvent(PropertyChangeEvent evt) {
return evt.getPropertyName().equals(IngestManager.IngestModuleEvent.STARTED.toString()) || evt.getPropertyName().equals(IngestManager.IngestModuleEvent.COMPLETED.toString()) || evt.getPropertyName().equals(IngestManager.IngestModuleEvent.STOPPED.toString());
}
@Override
public void load() {
hashSetTable.clearSelection();
@ -230,18 +262,9 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
hashSetManager.save();
}
public void discard() {
HashDbManager.getInstance().loadLastSavedConfiguration();
}
/**
* Removes a list of HashDbs from the dialog panel that do not have a companion -md5.idx file.
* Occurs when user clicks "No" to the dialog popup box.
* @param toRemove a list of HashDbs that are unindexed
*/
void removeThese(List<HashDb> toRemove) {
for (HashDb hashDb : toRemove) {
hashSetManager.removeHashSet(hashDb);
hashSetManager.removeHashDatabase(hashDb);
}
hashSetTableModel.refreshModel();
}
@ -279,7 +302,6 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
}
boolean valid() {
// TODO check whether form is consistent and complete
return true;
}
@ -428,13 +450,13 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
hashDbIndexStatusLabel = new javax.swing.JLabel();
indexLabel = new javax.swing.JLabel();
indexButton = new javax.swing.JButton();
useForIngestCheckbox = new javax.swing.JCheckBox();
showInboxMessagesCheckBox = new javax.swing.JCheckBox();
searchDuringIngestCheckbox = new javax.swing.JCheckBox();
sendIngestMessagesCheckBox = new javax.swing.JCheckBox();
informationLabel = new javax.swing.JLabel();
optionsLabel = new javax.swing.JLabel();
informationSeparator = new javax.swing.JSeparator();
optionsSeparator = new javax.swing.JSeparator();
newDatabaseButton = new javax.swing.JButton();
createDatabaseButton = new javax.swing.JButton();
indexPathLabelLabel = new javax.swing.JLabel();
indexPathLabel = new javax.swing.JLabel();
@ -518,17 +540,17 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
}
});
org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.useForIngestCheckbox.text")); // NOI18N
useForIngestCheckbox.addActionListener(new java.awt.event.ActionListener() {
org.openide.awt.Mnemonics.setLocalizedText(searchDuringIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.searchDuringIngestCheckbox.text")); // NOI18N
searchDuringIngestCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
useForIngestCheckboxActionPerformed(evt);
searchDuringIngestCheckboxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(showInboxMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.showInboxMessagesCheckBox.text")); // NOI18N
showInboxMessagesCheckBox.addActionListener(new java.awt.event.ActionListener() {
org.openide.awt.Mnemonics.setLocalizedText(sendIngestMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.sendIngestMessagesCheckBox.text")); // NOI18N
sendIngestMessagesCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showInboxMessagesCheckBoxActionPerformed(evt);
sendIngestMessagesCheckBoxActionPerformed(evt);
}
});
@ -536,14 +558,14 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.optionsLabel.text")); // NOI18N
newDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/new16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(newDatabaseButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.newDatabaseButton.text")); // NOI18N
newDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25));
newDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25));
newDatabaseButton.setPreferredSize(new java.awt.Dimension(140, 25));
newDatabaseButton.addActionListener(new java.awt.event.ActionListener() {
createDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/new16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(createDatabaseButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.createDatabaseButton.text")); // NOI18N
createDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25));
createDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25));
createDatabaseButton.setPreferredSize(new java.awt.Dimension(140, 25));
createDatabaseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
newDatabaseButtonActionPerformed(evt);
createDatabaseButtonActionPerformed(evt);
}
});
@ -558,7 +580,6 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(hashDatabasesLabel)
.addGroup(layout.createSequentialGroup()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 275, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
@ -571,12 +592,6 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(nameLabel)
.addGap(53, 53, 53)
.addComponent(hashDbNameLabel))
.addComponent(useForIngestCheckbox)
.addComponent(showInboxMessagesCheckBox)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(locationLabel)
@ -589,16 +604,32 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
.addComponent(hashDbTypeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 241, Short.MAX_VALUE)
.addComponent(hashDbLocationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(indexPathLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(hashDbIndexStatusLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
.addComponent(hashDbIndexStatusLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(nameLabel)
.addGap(53, 53, 53)
.addComponent(hashDbNameLabel))
.addComponent(searchDuringIngestCheckbox)
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addComponent(sendIngestMessagesCheckBox)))
.addGap(0, 0, Short.MAX_VALUE))))
.addGroup(layout.createSequentialGroup()
.addComponent(optionsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(optionsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 324, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addGroup(layout.createSequentialGroup()
.addComponent(newDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(importDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(hashDatabasesLabel)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(deleteDatabaseButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addComponent(createDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 137, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(importDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGap(0, 0, Short.MAX_VALUE)))
.addGap(24, 24, 24))
);
layout.setVerticalGroup(
@ -641,9 +672,9 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
.addComponent(optionsLabel)
.addComponent(optionsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 6, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
.addComponent(useForIngestCheckbox)
.addComponent(searchDuringIngestCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(showInboxMessagesCheckBox)
.addComponent(sendIngestMessagesCheckBox)
.addGap(18, 18, 18)
.addComponent(ingestWarningLabel)
.addGap(0, 0, Short.MAX_VALUE))
@ -651,7 +682,7 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(importDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(newDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(createDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
@ -689,10 +720,10 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
}//GEN-LAST:event_indexButtonActionPerformed
private void deleteDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteDatabaseButtonActionPerformed
if (JOptionPane.showConfirmDialog(null, "This will remove the hash database entry globally (for all Cases). Do you want to proceed? ", "Deleting a Hash Database Entry", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) {
if (JOptionPane.showConfirmDialog(null, "This will remove the hash database for all cases. Do you want to proceed? ", "Delete Hash Database from Configuration", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) {
HashDb hashDb = ((HashSetTable)hashSetTable).getSelection();
if (hashDb != null) {
hashSetManager.removeHashSet(hashDb);
hashSetManager.removeHashDatabase(hashDb);
hashSetTableModel.refreshModel();
}
}
@ -702,46 +733,48 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
if (evt.getKeyCode() == KeyEvent.VK_DELETE) {
HashDb hashDb = ((HashSetTable)hashSetTable).getSelection();
if (hashDb != null) {
hashSetManager.removeHashSet(hashDb);
hashSetManager.removeHashDatabase(hashDb);
hashSetTableModel.refreshModel();
}
}
}//GEN-LAST:event_hashSetTableKeyPressed
private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed
private void searchDuringIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchDuringIngestCheckboxActionPerformed
HashDb hashDb = ((HashSetTable)hashSetTable).getSelection();
if (hashDb != null) {
hashDb.setUseForIngest(useForIngestCheckbox.isSelected());
showInboxMessagesCheckBox.setEnabled(useForIngestCheckbox.isSelected());
hashDb.setSearchDuringIngest(searchDuringIngestCheckbox.isSelected());
if (!searchDuringIngestCheckbox.isSelected()) {
sendIngestMessagesCheckBox.setSelected(false);
}
hashDb.setSendIngestMessages(sendIngestMessagesCheckBox.isSelected());
}
}//GEN-LAST:event_useForIngestCheckboxActionPerformed
}//GEN-LAST:event_searchDuringIngestCheckboxActionPerformed
private void showInboxMessagesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showInboxMessagesCheckBoxActionPerformed
private void sendIngestMessagesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sendIngestMessagesCheckBoxActionPerformed
HashDb hashDb = ((HashSetTable)hashSetTable).getSelection();
if (hashDb != null) {
hashDb.setShowInboxMessages(showInboxMessagesCheckBox.isSelected());
hashDb.setSendIngestMessages(sendIngestMessagesCheckBox.isSelected());
}
}//GEN-LAST:event_showInboxMessagesCheckBoxActionPerformed
}//GEN-LAST:event_sendIngestMessagesCheckBoxActionPerformed
private void importDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importDatabaseButtonActionPerformed
HashDb hashDb = new HashDbImportDatabaseDialog().doDialog();
if (hashDb != null) {
hashSetManager.addHashSet(hashDb);
HashDb hashDb = new HashDbImportDatabaseDialog().getHashDatabase();
if (null != hashDb) {
hashSetTableModel.refreshModel();
((HashSetTable)hashSetTable).selectRowByName(hashDb.getHashSetName());
}
}//GEN-LAST:event_importDatabaseButtonActionPerformed
private void newDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newDatabaseButtonActionPerformed
HashDb hashDb = new HashDbCreateDatabaseDialog().doDialog();
private void createDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createDatabaseButtonActionPerformed
HashDb hashDb = new HashDbCreateDatabaseDialog().getHashDatabase();
if (null != hashDb) {
hashSetManager.addHashSet(hashDb);
hashSetTableModel.refreshModel();
((HashSetTable)hashSetTable).selectRowByName(hashDb.getHashSetName());
}
}//GEN-LAST:event_newDatabaseButtonActionPerformed
}//GEN-LAST:event_createDatabaseButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton createDatabaseButton;
private javax.swing.JButton deleteDatabaseButton;
private javax.swing.JLabel hashDatabasesLabel;
private javax.swing.JLabel hashDbIndexStatusLabel;
@ -764,11 +797,10 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JLabel locationLabel;
private javax.swing.JLabel nameLabel;
private javax.swing.JButton newDatabaseButton;
private javax.swing.JLabel optionsLabel;
private javax.swing.JSeparator optionsSeparator;
private javax.swing.JCheckBox showInboxMessagesCheckBox;
private javax.swing.JCheckBox searchDuringIngestCheckbox;
private javax.swing.JCheckBox sendIngestMessagesCheckBox;
private javax.swing.JLabel typeLabel;
private javax.swing.JCheckBox useForIngestCheckbox;
// End of variables declaration//GEN-END:variables
}

View File

@ -32,43 +32,48 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="okButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="databasePathTextField" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="browseButton" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="databaseNameTextField" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
<Component id="sendIngestMessagesCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="searchDuringIngestCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="knownBadRadioButton" min="-2" max="-2" attributes="0"/>
<Component id="knownRadioButton" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="useForIngestCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="sendInboxMessagesCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="okButton" linkSize="2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" linkSize="2" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="knownRadioButton" min="-2" max="-2" attributes="0"/>
<Component id="knownBadRadioButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Group type="102" attributes="0">
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="databasePathTextField" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="jLabel3" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="hashSetNameTextField" min="-2" pref="272" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="saveAsButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="135" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</Group>
@ -77,45 +82,46 @@
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="hashSetNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="databasePathTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="saveAsButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="databaseNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace min="-2" pref="7" max="-2" attributes="0"/>
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="knownRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="knownBadRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="useForIngestCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="searchDuringIngestCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="sendInboxMessagesCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="sendIngestMessagesCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="okButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="okButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="okButton">
<Component class="javax.swing.JButton" name="saveAsButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbCreateDatabaseDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbCreateDatabaseDialog.saveAsButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okButtonActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="saveAsButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="cancelButton">
@ -128,23 +134,6 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="databasePathTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbCreateDatabaseDialog.databasePathTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="browseButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbCreateDatabaseDialog.browseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="knownRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
@ -179,10 +168,10 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="databaseNameTextField">
<Component class="javax.swing.JTextField" name="hashSetNameTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbCreateDatabaseDialog.databaseNameTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbCreateDatabaseDialog.hashSetNameTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -193,24 +182,52 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="useForIngestCheckbox">
<Component class="javax.swing.JCheckBox" name="searchDuringIngestCheckbox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbCreateDatabaseDialog.useForIngestCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbCreateDatabaseDialog.searchDuringIngestCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbCreateDatabaseDialog.searchDuringIngestCheckbox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useForIngestCheckboxActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="searchDuringIngestCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="sendInboxMessagesCheckbox">
<Component class="javax.swing.JCheckBox" name="sendIngestMessagesCheckbox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbCreateDatabaseDialog.sendInboxMessagesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbCreateDatabaseDialog.sendIngestMessagesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel3">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbCreateDatabaseDialog.jLabel3.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="databasePathTextField">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbCreateDatabaseDialog.databasePathTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="okButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbCreateDatabaseDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -27,31 +27,60 @@ import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.JFrame;
import org.apache.commons.io.FilenameUtils;
import org.sleuthkit.autopsy.hashdatabase.HashDb.KnownFilesType;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb.KnownFilesType;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDatabaseFileAlreadyExistsException;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.DuplicateHashSetNameException;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDatabaseAlreadyAddedException;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.IllegalHashDatabaseFileNameExtensionException;
final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
private JFileChooser fileChooser;
/**
* Instances of this class allow a user to create a new hash database and
* add it to the set of hash databases used to classify files as unknown, known
* or known bad.
*/
final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
private static final String DEFAULT_FILE_NAME = "hashset";
private JFileChooser fileChooser = null;
private HashDb newHashDb = null;
/**
* Displays a dialog that allows a user to create a new hash database and
* add it to the set of hash databases used to classify files as unknown, known
* or known bad.
*/
HashDbCreateDatabaseDialog() {
super(new javax.swing.JFrame(), "Create Hash Database", true);
setResizable(false);
super(new JFrame(), "Create Hash Database", true);
initFileChooser();
initComponents();
display();
}
/**
* Get the hash database created by the user, if any.
* @return A HashDb object or null.
*/
HashDb getHashDatabase() {
return newHashDb;
}
private void initFileChooser() {
fileChooser = new JFileChooser() {
@Override
public void approveSelection() {
File selectedFile = getSelectedFile();
if (!FilenameUtils.getExtension(selectedFile.getName()).equalsIgnoreCase("kdb")) {
if (JOptionPane.showConfirmDialog(this, "The file must have a .kdb extension.", "File Name Error", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) {
if (!FilenameUtils.getExtension(selectedFile.getName()).equalsIgnoreCase(HashDbManager.getHashDatabaseFileExtension())) {
if (JOptionPane.showConfirmDialog(this, "The hash database file must have a ." + HashDbManager.getHashDatabaseFileExtension() + " extension.", "File Name Error", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) {
cancelSelection();
}
return;
}
if (selectedFile.exists()) {
int r = JOptionPane.showConfirmDialog(this, "A file with this name already exists. Please enter a new filename.", "Existing File", JOptionPane.OK_CANCEL_OPTION);
if (r == JOptionPane.CANCEL_OPTION) {
if (JOptionPane.showConfirmDialog(this, "A file with this name already exists. Please choose a new file name.", "File Already Exists Error", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) {
cancelSelection();
}
return;
@ -59,30 +88,17 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
super.approveSelection();
}
};
initComponents();
customizeComponents();
}
void customizeComponents() {
fileChooser.setDragEnabled(false);
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
String[] EXTENSION = new String[] { "txt", "kdb", "idx", "hash", "Hash", "hsh"};
FileNameExtensionFilter filter = new FileNameExtensionFilter("Hash Database File", EXTENSION);
fileChooser.setFileFilter(filter);
fileChooser.setMultiSelectionEnabled(false);
fileChooser.setDragEnabled(false);
fileChooser.setMultiSelectionEnabled(false);
}
HashDb doDialog() {
newHashDb = null;
// Center and display the dialog.
private void display() {
Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2);
this.setVisible(true);
return newHashDb;
setVisible(true);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
@ -93,24 +109,25 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
private void initComponents() {
buttonGroup1 = new javax.swing.ButtonGroup();
okButton = new javax.swing.JButton();
saveAsButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
databasePathTextField = new javax.swing.JTextField();
browseButton = new javax.swing.JButton();
knownRadioButton = new javax.swing.JRadioButton();
knownBadRadioButton = new javax.swing.JRadioButton();
jLabel1 = new javax.swing.JLabel();
databaseNameTextField = new javax.swing.JTextField();
hashSetNameTextField = new javax.swing.JTextField();
jLabel2 = new javax.swing.JLabel();
useForIngestCheckbox = new javax.swing.JCheckBox();
sendInboxMessagesCheckbox = new javax.swing.JCheckBox();
searchDuringIngestCheckbox = new javax.swing.JCheckBox();
sendIngestMessagesCheckbox = new javax.swing.JCheckBox();
jLabel3 = new javax.swing.JLabel();
databasePathTextField = new javax.swing.JTextField();
okButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.okButton.text")); // NOI18N
okButton.addActionListener(new java.awt.event.ActionListener() {
org.openide.awt.Mnemonics.setLocalizedText(saveAsButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.saveAsButton.text")); // NOI18N
saveAsButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt);
saveAsButtonActionPerformed(evt);
}
});
@ -121,15 +138,6 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
}
});
databasePathTextField.setText(org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.databasePathTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.browseButton.text")); // NOI18N
browseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
browseButtonActionPerformed(evt);
}
});
buttonGroup1.add(knownRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(knownRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.knownRadioButton.text")); // NOI18N
knownRadioButton.addActionListener(new java.awt.event.ActionListener() {
@ -149,20 +157,33 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.jLabel1.text")); // NOI18N
databaseNameTextField.setText(org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.databaseNameTextField.text")); // NOI18N
hashSetNameTextField.setText(org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.hashSetNameTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.jLabel2.text")); // NOI18N
useForIngestCheckbox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.useForIngestCheckbox.text")); // NOI18N
useForIngestCheckbox.addActionListener(new java.awt.event.ActionListener() {
searchDuringIngestCheckbox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(searchDuringIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.searchDuringIngestCheckbox.text")); // NOI18N
searchDuringIngestCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.searchDuringIngestCheckbox.toolTipText")); // NOI18N
searchDuringIngestCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
useForIngestCheckboxActionPerformed(evt);
searchDuringIngestCheckboxActionPerformed(evt);
}
});
sendInboxMessagesCheckbox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(sendInboxMessagesCheckbox, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.sendInboxMessagesCheckbox.text")); // NOI18N
sendIngestMessagesCheckbox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(sendIngestMessagesCheckbox, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.sendIngestMessagesCheckbox.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.jLabel3.text")); // NOI18N
databasePathTextField.setEditable(false);
databasePathTextField.setText(org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.databasePathTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.okButton.text")); // NOI18N
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
@ -174,142 +195,175 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addComponent(sendIngestMessagesCheckbox))
.addComponent(searchDuringIngestCheckbox))
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(okButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton))
.addComponent(jLabel2)
.addGroup(layout.createSequentialGroup()
.addComponent(databasePathTextField)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(browseButton))
.addGap(20, 20, 20)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(knownRadioButton)
.addComponent(knownBadRadioButton)))
.addGroup(layout.createSequentialGroup()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(databaseNameTextField))
.addGroup(layout.createSequentialGroup()
.addComponent(jLabel2)
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(knownBadRadioButton)
.addComponent(knownRadioButton))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(useForIngestCheckbox)
.addComponent(sendInboxMessagesCheckbox))
.addGap(0, 135, Short.MAX_VALUE))))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addGroup(layout.createSequentialGroup()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(databasePathTextField))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(jLabel3)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 272, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(saveAsButton)))
.addContainerGap())))
);
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, okButton});
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addGap(2, 2, 2)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel3)
.addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(databasePathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(browseButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
.addComponent(databaseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(saveAsButton)
.addComponent(jLabel1))
.addGap(7, 7, 7)
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(knownRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(knownBadRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(useForIngestCheckbox)
.addComponent(searchDuringIngestCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(sendInboxMessagesCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(sendIngestMessagesCheckbox)
.addGap(3, 3, 3)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(okButton)
.addComponent(cancelButton))
.addContainerGap())
.addComponent(cancelButton)
.addComponent(okButton))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
try {
fileChooser.setSelectedFile(new File("hash.kdb"));
if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
File databaseFile = fileChooser.getSelectedFile();
databasePathTextField.setText(databaseFile.getCanonicalPath());
databaseNameTextField.setText(FilenameUtils.removeExtension(databaseFile.getName()));
if (databaseNameTextField.getText().toLowerCase().contains("nsrl")) {
knownRadioButton.setSelected(true);
knownRadioButtonActionPerformed(null);
}
}
}
catch (IOException ex) {
Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, "Couldn't get selected file path.", ex);
}
}//GEN-LAST:event_browseButtonActionPerformed
private void knownRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownRadioButtonActionPerformed
sendInboxMessagesCheckbox.setSelected(false);
sendInboxMessagesCheckbox.setEnabled(false);
searchDuringIngestCheckbox.setSelected(true);
sendIngestMessagesCheckbox.setSelected(false);
sendIngestMessagesCheckbox.setEnabled(false);
}//GEN-LAST:event_knownRadioButtonActionPerformed
private void knownBadRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownBadRadioButtonActionPerformed
sendInboxMessagesCheckbox.setSelected(true);
sendInboxMessagesCheckbox.setEnabled(true);
searchDuringIngestCheckbox.setSelected(true);
sendIngestMessagesCheckbox.setSelected(true);
sendIngestMessagesCheckbox.setEnabled(true);
}//GEN-LAST:event_knownBadRadioButtonActionPerformed
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
this.dispose();
dispose();
}//GEN-LAST:event_cancelButtonActionPerformed
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
if(databasePathTextField.getText().isEmpty()) {
JOptionPane.showMessageDialog(this, "Database path cannot be empty");
return;
}
if(databaseNameTextField.getText().isEmpty()) {
JOptionPane.showMessageDialog(this, "Database name cannot be empty");
return;
private void saveAsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveAsButtonActionPerformed
try {
StringBuilder path = new StringBuilder();
if (!hashSetNameTextField.getText().isEmpty()) {
path.append(hashSetNameTextField.getText());
}
else {
path.append(DEFAULT_FILE_NAME);
}
path.append(".").append(HashDbManager.getHashDatabaseFileExtension());
fileChooser.setSelectedFile(new File(path.toString()));
if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
File databaseFile = fileChooser.getSelectedFile();
databasePathTextField.setText(databaseFile.getCanonicalPath());
}
}
catch (IOException ex) {
Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, "Couldn't get selected file path.", ex);
}
}//GEN-LAST:event_saveAsButtonActionPerformed
private void searchDuringIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchDuringIngestCheckboxActionPerformed
sendIngestMessagesCheckbox.setEnabled(searchDuringIngestCheckbox.isSelected());
if (!searchDuringIngestCheckbox.isSelected()) {
sendIngestMessagesCheckbox.setSelected(false);
}
}//GEN-LAST:event_searchDuringIngestCheckboxActionPerformed
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
// Note that the error handlers in this method call return without disposing of the
// dialog to allow the user to try again, if desired.
if (hashSetNameTextField.getText().isEmpty()) {
JOptionPane.showMessageDialog(this, "A hash set name must be entered.", "Create Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
}
if (databasePathTextField.getText().isEmpty()) {
JOptionPane.showMessageDialog(this, "A database path must be entered.", "Create Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
}
KnownFilesType type;
if(knownRadioButton.isSelected()) {
if (knownRadioButton.isSelected()) {
type = KnownFilesType.KNOWN;
} else {
}
else {
type = KnownFilesType.KNOWN_BAD;
}
String errorMessage = "Hash database creation error";
try
{
newHashDb = HashDb.createHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type);
newHashDb = HashDbManager.getInstance().addNewHashDatabase(hashSetNameTextField.getText(), fileChooser.getSelectedFile().getCanonicalPath(), searchDuringIngestCheckbox.isSelected(), sendIngestMessagesCheckbox.isSelected(), type);
}
catch (IOException ex) {
Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex);
JOptionPane.showMessageDialog(this, "Cannot create a hash database file at the selected location.", "Create Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
}
catch (HashDatabaseFileAlreadyExistsException | DuplicateHashSetNameException | HashDatabaseAlreadyAddedException | IllegalHashDatabaseFileNameExtensionException ex) {
Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex);
JOptionPane.showMessageDialog(this, ex.getMessage(), "Create Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.SEVERE, "Hash database creation error", ex);
JOptionPane.showMessageDialog(this, "Failed to create hash database.");
Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.SEVERE, errorMessage, ex);
JOptionPane.showMessageDialog(this, "Failed to create the hash database.", "Create Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
}
this.dispose();
dispose();
}//GEN-LAST:event_okButtonActionPerformed
private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed
}//GEN-LAST:event_useForIngestCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton browseButton;
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JButton cancelButton;
private javax.swing.JTextField databaseNameTextField;
private javax.swing.JTextField databasePathTextField;
private javax.swing.JTextField hashSetNameTextField;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JRadioButton knownBadRadioButton;
private javax.swing.JRadioButton knownRadioButton;
private javax.swing.JButton okButton;
private javax.swing.JCheckBox sendInboxMessagesCheckbox;
private javax.swing.JCheckBox useForIngestCheckbox;
private javax.swing.JButton saveAsButton;
private javax.swing.JCheckBox searchDuringIngestCheckbox;
private javax.swing.JCheckBox sendIngestMessagesCheckbox;
// End of variables declaration//GEN-END:variables
}

View File

@ -30,47 +30,50 @@
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="okButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
<Component id="sendIngestMessagesCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="databasePathTextField" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="browseButton" min="-2" max="-2" attributes="0"/>
<Component id="searchDuringIngestCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Component id="okButton" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" linkSize="1" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="19" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="knownRadioButton" min="-2" max="-2" attributes="0"/>
<Component id="knownBadRadioButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace min="0" pref="307" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="databaseNameTextField" max="32767" attributes="0"/>
<Component id="hashSetNameTextField" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="jLabel3" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="databasePathTextField" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="knownBadRadioButton" min="-2" max="-2" attributes="0"/>
<Component id="knownRadioButton" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="useForIngestCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="sendInboxMessagesCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="135" max="32767" attributes="0"/>
<Component id="openButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -79,30 +82,38 @@
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="openButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="databasePathTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="databaseNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="hashSetNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="knownRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="knownBadRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="useForIngestCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="sendInboxMessagesCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="okButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace pref="119" max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="okButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="knownRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="knownBadRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="13" max="-2" attributes="0"/>
<Component id="searchDuringIngestCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="sendIngestMessagesCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -130,19 +141,20 @@
</Component>
<Component class="javax.swing.JTextField" name="databasePathTextField">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbImportDatabaseDialog.databasePathTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="browseButton">
<Component class="javax.swing.JButton" name="openButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbImportDatabaseDialog.browseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbImportDatabaseDialog.openButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="knownRadioButton">
@ -179,10 +191,10 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="databaseNameTextField">
<Component class="javax.swing.JTextField" name="hashSetNameTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbImportDatabaseDialog.databaseNameTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbImportDatabaseDialog.hashSetNameTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -193,22 +205,29 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="useForIngestCheckbox">
<Component class="javax.swing.JCheckBox" name="searchDuringIngestCheckbox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbImportDatabaseDialog.useForIngestCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbImportDatabaseDialog.searchDuringIngestCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useForIngestCheckboxActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="searchDuringIngestCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="sendInboxMessagesCheckbox">
<Component class="javax.swing.JCheckBox" name="sendIngestMessagesCheckbox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbImportDatabaseDialog.sendInboxMessagesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbImportDatabaseDialog.sendIngestMessagesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel3">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbImportDatabaseDialog.jLabel3.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>

View File

@ -27,44 +27,69 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.sleuthkit.autopsy.hashdatabase.HashDb.KnownFilesType;
import javax.swing.JFrame;
import org.sleuthkit.datamodel.TskCoreException;
import org.apache.commons.io.FilenameUtils;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb.KnownFilesType;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDatabaseDoesNotExistException;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.DuplicateHashSetNameException;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDatabaseAlreadyAddedException;
/**
* Instances of this class allow a user to select a hash database for import.
* Instances of this class allow a user to select an existing hash database and
* add it to the set of hash databases used to classify files as unknown, known,
* or known bad.
*/
final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
private JFileChooser fileChooser = new JFileChooser();
private HashDb selectedHashDb;
HashDbImportDatabaseDialog() {
super(new javax.swing.JFrame(), "Import Hash Database", true);
setResizable(false);
initComponents();
customizeComponents();
}
void customizeComponents() {
private JFileChooser fileChooser = new JFileChooser();
private String selectedFilePath = "";
private HashDb selectedHashDb = null;
/**
* Displays a dialog that allows a user to select an existing hash database
* and add it to the set of hash databases used to classify files as unknown,
* known, or known bad.
*/
HashDbImportDatabaseDialog() {
super(new JFrame(), "Import Hash Database", true);
initFileChooser();
initComponents();
display();
}
/**
* Get the hash database imported by the user, if any.
* @return A HashDb object or null.
*/
HashDb getHashDatabase() {
return selectedHashDb;
}
private void initFileChooser() {
fileChooser.setDragEnabled(false);
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
String[] EXTENSION = new String[] { "txt", "kdb", "idx", "hash", "Hash", "hsh"};
FileNameExtensionFilter filter = new FileNameExtensionFilter("Hash Database File", EXTENSION);
fileChooser.setFileFilter(filter);
fileChooser.setMultiSelectionEnabled(false);
}
HashDb doDialog() {
selectedHashDb = null;
// Center and display the dialog.
Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2);
this.setVisible(true);
return selectedHashDb;
fileChooser.setMultiSelectionEnabled(false);
}
private void display() {
Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2);
setVisible(true);
}
private static String shortenPath(String path) {
String shortenedPath = path;
if (shortenedPath.length() > 50){
shortenedPath = shortenedPath.substring(0, 10 + shortenedPath.substring(10).indexOf(File.separator) + 1) + "..." + shortenedPath.substring((shortenedPath.length() - 20) + shortenedPath.substring(shortenedPath.length() - 20).indexOf(File.separator));
}
return shortenedPath;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
@ -78,14 +103,15 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
okButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
databasePathTextField = new javax.swing.JTextField();
browseButton = new javax.swing.JButton();
openButton = new javax.swing.JButton();
knownRadioButton = new javax.swing.JRadioButton();
knownBadRadioButton = new javax.swing.JRadioButton();
jLabel1 = new javax.swing.JLabel();
databaseNameTextField = new javax.swing.JTextField();
hashSetNameTextField = new javax.swing.JTextField();
jLabel2 = new javax.swing.JLabel();
useForIngestCheckbox = new javax.swing.JCheckBox();
sendInboxMessagesCheckbox = new javax.swing.JCheckBox();
searchDuringIngestCheckbox = new javax.swing.JCheckBox();
sendIngestMessagesCheckbox = new javax.swing.JCheckBox();
jLabel3 = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
@ -103,12 +129,13 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
}
});
databasePathTextField.setEditable(false);
databasePathTextField.setText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.databasePathTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.browseButton.text")); // NOI18N
browseButton.addActionListener(new java.awt.event.ActionListener() {
org.openide.awt.Mnemonics.setLocalizedText(openButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.openButton.text")); // NOI18N
openButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
browseButtonActionPerformed(evt);
openButtonActionPerformed(evt);
}
});
@ -131,20 +158,22 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.jLabel1.text")); // NOI18N
databaseNameTextField.setText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.databaseNameTextField.text")); // NOI18N
hashSetNameTextField.setText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.hashSetNameTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.jLabel2.text")); // NOI18N
useForIngestCheckbox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.useForIngestCheckbox.text")); // NOI18N
useForIngestCheckbox.addActionListener(new java.awt.event.ActionListener() {
searchDuringIngestCheckbox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(searchDuringIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.searchDuringIngestCheckbox.text")); // NOI18N
searchDuringIngestCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
useForIngestCheckboxActionPerformed(evt);
searchDuringIngestCheckboxActionPerformed(evt);
}
});
sendInboxMessagesCheckbox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(sendInboxMessagesCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.sendInboxMessagesCheckbox.text")); // NOI18N
sendIngestMessagesCheckbox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(sendIngestMessagesCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.sendIngestMessagesCheckbox.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.jLabel3.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
@ -156,90 +185,104 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(okButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton))
.addGroup(layout.createSequentialGroup()
.addComponent(databasePathTextField)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(browseButton))
.addGap(21, 21, 21)
.addComponent(sendIngestMessagesCheckbox))
.addComponent(searchDuringIngestCheckbox))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(okButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel2)
.addGroup(layout.createSequentialGroup()
.addGap(19, 19, 19)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(knownRadioButton)
.addComponent(knownBadRadioButton))))
.addGap(0, 307, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(databaseNameTextField))
.addGroup(layout.createSequentialGroup()
.addComponent(jLabel2)
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(knownBadRadioButton)
.addComponent(knownRadioButton))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(useForIngestCheckbox)
.addComponent(sendInboxMessagesCheckbox))
.addGap(0, 135, Short.MAX_VALUE))))
.addComponent(hashSetNameTextField))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(jLabel3)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(databasePathTextField)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(openButton)))
.addContainerGap())
);
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, okButton});
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(openButton)
.addComponent(databasePathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(browseButton))
.addComponent(jLabel3))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
.addComponent(databaseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(knownRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(knownBadRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(useForIngestCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(sendInboxMessagesCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(okButton)
.addComponent(cancelButton))
.addContainerGap())
.addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 119, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(okButton)
.addComponent(cancelButton))
.addContainerGap())
.addGroup(layout.createSequentialGroup()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(knownRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(knownBadRadioButton)
.addGap(13, 13, 13)
.addComponent(searchDuringIngestCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(sendIngestMessagesCheckbox)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
File databaseFile = fileChooser.getSelectedFile();
try {
databasePathTextField.setText(databaseFile.getCanonicalPath());
databaseNameTextField.setText(FilenameUtils.removeExtension(databaseFile.getName()));
if (databaseNameTextField.getText().toLowerCase().contains("nsrl")) {
selectedFilePath = databaseFile.getCanonicalPath();
databasePathTextField.setText(shortenPath(selectedFilePath));
hashSetNameTextField.setText(FilenameUtils.removeExtension(databaseFile.getName()));
if (hashSetNameTextField.getText().toLowerCase().contains("nsrl")) {
knownRadioButton.setSelected(true);
knownRadioButtonActionPerformed(null);
}
}
catch (IOException ex) {
Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Failed to get path of selected database", ex);
JOptionPane.showMessageDialog(this, "Failed to get the path of the selected database.");
}
}
}//GEN-LAST:event_browseButtonActionPerformed
}//GEN-LAST:event_openButtonActionPerformed
private void knownRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownRadioButtonActionPerformed
sendInboxMessagesCheckbox.setSelected(false);
sendInboxMessagesCheckbox.setEnabled(false);
searchDuringIngestCheckbox.setSelected(true);
sendIngestMessagesCheckbox.setSelected(false);
sendIngestMessagesCheckbox.setEnabled(false);
}//GEN-LAST:event_knownRadioButtonActionPerformed
private void knownBadRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownBadRadioButtonActionPerformed
sendInboxMessagesCheckbox.setSelected(true);
sendInboxMessagesCheckbox.setEnabled(true);
searchDuringIngestCheckbox.setSelected(true);
sendIngestMessagesCheckbox.setSelected(true);
sendIngestMessagesCheckbox.setEnabled(true);
}//GEN-LAST:event_knownBadRadioButtonActionPerformed
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
@ -247,32 +290,24 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
}//GEN-LAST:event_cancelButtonActionPerformed
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
if(databasePathTextField.getText().isEmpty()) {
JOptionPane.showMessageDialog(this, "Hash database file path cannot be empty.");
// Note that the error handlers in this method call return without disposing of the
// dialog to allow the user to try again, if desired.
if(hashSetNameTextField.getText().isEmpty()) {
JOptionPane.showMessageDialog(this, "A hash set name must be entered.", "Import Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
}
if(databaseNameTextField.getText().isEmpty()) {
JOptionPane.showMessageDialog(this, "Hash set name cannot be empty.");
if(selectedFilePath.isEmpty()) {
JOptionPane.showMessageDialog(this, "A hash database file path must be selected.", "Import Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
}
File file = new File(databasePathTextField.getText());
}
File file = new File(selectedFilePath);
if (!file.exists()) {
JOptionPane.showMessageDialog(this, "Selected hash database does not exist.");
JOptionPane.showMessageDialog(this, "The selected hash database does not exist.", "Import Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
}
String filePath;
try {
filePath = file.getCanonicalPath();
}
catch (IOException ex) {
Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Failed to get path of selected database", ex);
JOptionPane.showMessageDialog(this, "Failed to get path of selected database.");
return;
}
KnownFilesType type;
if (knownRadioButton.isSelected()) {
type = KnownFilesType.KNOWN;
@ -281,33 +316,44 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
type = KnownFilesType.KNOWN_BAD;
}
String errorMessage = "Failed to open hash database at " + selectedFilePath + ".";
try {
selectedHashDb = HashDb.openHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type);
selectedHashDb = HashDbManager.getInstance().addExistingHashDatabase(hashSetNameTextField.getText(), selectedFilePath, searchDuringIngestCheckbox.isSelected(), sendIngestMessagesCheckbox.isSelected(), type);
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Failed to open hash database at " + filePath, ex);
JOptionPane.showMessageDialog(this, "Failed to import selected database.\nPlease verify that the selected file is a hash database.");
catch (HashDatabaseDoesNotExistException | DuplicateHashSetNameException | HashDatabaseAlreadyAddedException ex) {
Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex);
JOptionPane.showMessageDialog(this, ex.getMessage(), "Import Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
}
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.SEVERE, errorMessage, ex);
JOptionPane.showMessageDialog(this, errorMessage, "Import Hash Database Error", JOptionPane.ERROR_MESSAGE);
return;
}
this.dispose();
dispose();
}//GEN-LAST:event_okButtonActionPerformed
private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed
}//GEN-LAST:event_useForIngestCheckboxActionPerformed
private void searchDuringIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchDuringIngestCheckboxActionPerformed
sendIngestMessagesCheckbox.setEnabled(searchDuringIngestCheckbox.isSelected());
if (!searchDuringIngestCheckbox.isSelected()) {
sendIngestMessagesCheckbox.setSelected(false);
}
}//GEN-LAST:event_searchDuringIngestCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton browseButton;
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JButton cancelButton;
private javax.swing.JTextField databaseNameTextField;
private javax.swing.JTextField databasePathTextField;
private javax.swing.JTextField hashSetNameTextField;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JRadioButton knownBadRadioButton;
private javax.swing.JRadioButton knownRadioButton;
private javax.swing.JButton okButton;
private javax.swing.JCheckBox sendInboxMessagesCheckbox;
private javax.swing.JCheckBox useForIngestCheckbox;
private javax.swing.JButton openButton;
private javax.swing.JCheckBox searchDuringIngestCheckbox;
private javax.swing.JCheckBox sendIngestMessagesCheckbox;
// End of variables declaration//GEN-END:variables
}

View File

@ -42,6 +42,7 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
public class HashDbIngestModule extends IngestModuleAbstractFile {
private static HashDbIngestModule instance = null;
@ -138,9 +139,9 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
skCase = Case.getCurrentCase().getSleuthkitCase();
HashDbManager hashDbManager = HashDbManager.getInstance();
getHashSetsUsableForIngest(hashDbManager.getKnownBadHashSets(), knownBadHashSets);
getHashSetsUsableForIngest(hashDbManager.getKnownHashSets(), knownHashSets);
calcHashesIsSet = hashDbManager.shouldAlwaysCalculateHashes();
getHashSetsUsableForIngest(hashDbManager.getKnownBadFileHashSets(), knownBadHashSets);
getHashSetsUsableForIngest(hashDbManager.getKnownFileHashSets(), knownHashSets);
calcHashesIsSet = hashDbManager.getAlwaysCalculateHashes();
if (knownHashSets.isEmpty()) {
services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No known hash database set", "Known file search will not be executed."));
@ -155,14 +156,14 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
assert hashDbsForIngest != null;
hashDbsForIngest.clear();
for (HashDb db : hashDbs) {
if (db.getUseForIngest()) {
if (db.getSearchDuringIngest()) {
try {
if (db.hasLookupIndex()) {
hashDbsForIngest.add(db);
}
}
catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error get index status for hash database at " +db.getDatabasePath(), ex);
logger.log(Level.WARNING, "Error getting index status for " + db.getHashSetName() +" hash database", ex);
}
}
}
@ -206,14 +207,24 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
}
// look up in known bad first
TskData.FileKnown status = TskData.FileKnown.UNKNOWN;
boolean foundBad = false;
ProcessResult ret = ProcessResult.OK;
for (HashDb db : knownBadHashSets) {
try {
long lookupstart = System.currentTimeMillis();
if (db.lookUp(file)) {
status = TskData.FileKnown.BAD;
if (db.hasMd5HashOf(file)) {
foundBad = true;
knownBadCount += 1;
try {
skCase.setKnown(file, TskData.FileKnown.BAD);
} catch (TskException ex) {
logger.log(Level.WARNING, "Couldn't set known bad state for file " + name + " - see sleuthkit log for details", ex);
services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name,
"Error encountered while setting known bad state for " + name + "."));
ret = ProcessResult.ERROR;
}
String hashSetName = db.getHashSetName();
postHashSetHitToBlackboard(file, md5Hash, hashSetName, db.getSendIngestMessages());
}
lookuptime += (System.currentTimeMillis() - lookupstart);
} catch (TskException ex) {
@ -222,21 +233,6 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
"Error encountered while looking up known bad hash value for " + name + "."));
ret = ProcessResult.ERROR;
}
if (status.equals(TskData.FileKnown.BAD)) {
foundBad = true;
knownBadCount += 1;
try {
skCase.setKnown(file, TskData.FileKnown.BAD);
} catch (TskException ex) {
logger.log(Level.WARNING, "Couldn't set known bad state for file " + name + " - see sleuthkit log for details", ex);
services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name,
"Error encountered while setting known bad state for " + name + "."));
ret = ProcessResult.ERROR;
}
String hashSetName = db.getHashSetName();
processBadFile(file, md5Hash, hashSetName, db.getShowInboxMessages());
}
}
// If the file is not in the known bad sets, search for it in the known sets.
@ -246,8 +242,16 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
for (HashDb db : knownHashSets) {
try {
long lookupstart = System.currentTimeMillis();
if (db.lookUp(file)) {
status = TskData.FileKnown.KNOWN;
if (db.hasMd5HashOf(file)) {
try {
skCase.setKnown(file, TskData.FileKnown.KNOWN);
break;
} catch (TskException ex) {
logger.log(Level.WARNING, "Couldn't set known state for file " + name + " - see sleuthkit log for details", ex);
services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name,
"Error encountered while setting known state for " + name + "."));
ret = ProcessResult.ERROR;
}
}
lookuptime += (System.currentTimeMillis() - lookupstart);
} catch (TskException ex) {
@ -256,25 +260,13 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
"Error encountered while looking up known hash value for " + name + "."));
ret = ProcessResult.ERROR;
}
if (status.equals(TskData.FileKnown.KNOWN)) {
try {
skCase.setKnown(file, TskData.FileKnown.KNOWN);
break;
} catch (TskException ex) {
logger.log(Level.WARNING, "Couldn't set known state for file " + name + " - see sleuthkit log for details", ex);
services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name,
"Error encountered while setting known state for " + name + "."));
ret = ProcessResult.ERROR;
}
}
}
}
return ret;
}
private void processBadFile(AbstractFile abstractFile, String md5Hash, String hashSetName, boolean showInboxMessage) {
private void postHashSetHitToBlackboard(AbstractFile abstractFile, String md5Hash, String hashSetName, boolean showInboxMessage) {
try {
BlackboardArtifact badFile = abstractFile.newArtifact(ARTIFACT_TYPE.TSK_HASHSET_HIT);
//TODO Revisit usage of deprecated constructor as per TSK-583

View File

@ -16,53 +16,69 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.hashdatabase;
import java.beans.PropertyChangeEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.logging.Level;
import java.util.Set;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.XMLUtil;
import org.sleuthkit.autopsy.hashdatabase.HashDb.KnownFilesType;
import org.sleuthkit.datamodel.TskCoreException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
import org.apache.commons.io.FilenameUtils;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.HashInfo;
import org.sleuthkit.datamodel.SleuthkitJNI;
import org.sleuthkit.datamodel.TskCoreException;
/**
* This class is a singleton that manages the set of hash databases
* used to classify files as known or known bad.
* This class implements a singleton that manages the set of hash databases
* used to classify files as unknown, known or known bad.
*/
public class HashDbManager {
private static final String ROOT_EL = "hash_sets";
private static final String SET_EL = "hash_set";
private static final String SET_NAME_ATTR = "name";
private static final String SET_TYPE_ATTR = "type";
private static final String SET_USE_FOR_INGEST_ATTR = "use_for_ingest";
private static final String SET_SHOW_INBOX_MESSAGES = "show_inbox_messages";
private static final String PATH_EL = "hash_set_path";
private static final String CUR_HASHSETS_FILE_NAME = "hashsets.xml";
private static final String XSDFILE = "HashsetsSchema.xsd";
public class HashDbManager implements PropertyChangeListener {
private static final String ROOT_ELEMENT = "hash_sets";
private static final String SET_ELEMENT = "hash_set";
private static final String SET_NAME_ATTRIBUTE = "name";
private static final String SET_TYPE_ATTRIBUTE = "type";
private static final String SEARCH_DURING_INGEST_ATTRIBUTE = "use_for_ingest";
private static final String SEND_INGEST_MESSAGES_ATTRIBUTE = "show_inbox_messages";
private static final String PATH_ELEMENT = "hash_set_path";
private static final String CONFIG_FILE_NAME = "hashsets.xml";
private static final String XSD_FILE_NAME = "HashsetsSchema.xsd";
private static final String ENCODING = "UTF-8";
private static final String SET_CALC = "hash_calculate";
private static final String SET_VALUE = "value";
private static final Logger logger = Logger.getLogger(HashDbManager.class.getName());
private static HashDbManager instance;
private String xmlFilePath = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME;
private static final String ALWAYS_CALCULATE_HASHES_ELEMENT = "hash_calculate";
private static final String VALUE_ATTRIBUTE = "value";
private static final String HASH_DATABASE_FILE_EXTENSON = "kdb";
private static final String LEGACY_INDEX_FILE_EXTENSION = "-md5.idx";
private static HashDbManager instance = null;
private final String configFilePath = PlatformUtil.getUserConfigDirectory() + File.separator + CONFIG_FILE_NAME;
private List<HashDb> knownHashSets = new ArrayList<>();
private List<HashDb> knownBadHashSets = new ArrayList<>();
private boolean alwaysCalculateHashes;
private Set<String> hashSetNames = new HashSet<>();
private Set<String> hashSetPaths = new HashSet<>();
private boolean alwaysCalculateHashes = false;
/**
* Gets the singleton instance of this class.
*/
@ -78,73 +94,238 @@ public class HashDbManager {
readHashSetsConfigurationFromDisk();
}
}
/**
* Adds a hash database to the configuration. Does not check for duplication
* of hash set names and does not save the configuration - the configuration
* is only saved on demand to support cancellation of configuration panels.
* Gets the extension, without the dot separator, that the SleuthKit requires
* for the hash database files that combine a database and an index and can
* therefore be updated.
*/
public void addHashSet(HashDb hashDb) {
static String getHashDatabaseFileExtension() {
return HASH_DATABASE_FILE_EXTENSON;
}
class DuplicateHashSetNameException extends Exception {
private DuplicateHashSetNameException(String hashSetName) {
super("The hash set name '"+ hashSetName +"' has already been used for another hash database.");
}
}
class HashDatabaseDoesNotExistException extends Exception {
private HashDatabaseDoesNotExistException(String path) {
super("No hash database found at\n" + path);
}
}
class HashDatabaseFileAlreadyExistsException extends Exception {
private HashDatabaseFileAlreadyExistsException(String path) {
super("A file already exists at\n" + path);
}
}
class HashDatabaseAlreadyAddedException extends Exception {
private HashDatabaseAlreadyAddedException(String path) {
super("The hash database at\n" + path + "\nhas already been created or imported.");
}
}
class IllegalHashDatabaseFileNameExtensionException extends Exception {
private IllegalHashDatabaseFileNameExtensionException() {
super("The hash database file name must have a ." + getHashDatabaseFileExtension() + " extension.");
}
}
/**
* Adds an existing hash database to the set of hash databases used to classify files as known or known bad.
* Does not save the configuration - the configuration is only saved on demand to support cancellation of
* configuration panels.
* @param hashSetName Name used to represent the hash database in user interface components.
* @param path Full path to either a hash database file or a hash database index file.
* @param searchDuringIngest A flag indicating whether or not the hash database should be searched during ingest.
* @param sendIngestMessages A flag indicating whether hash set hit messages should be sent as ingest messages.
* @param knownFilesType The classification to apply to files whose hashes are found in the hash database.
* @return A HashDb representing the hash database.
* @throws HashDatabaseDoesNotExistException, DuplicateHashSetNameException, HashDatabaseAlreadyAddedException, TskCoreException
*/
synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDatabaseDoesNotExistException, DuplicateHashSetNameException, HashDatabaseAlreadyAddedException, TskCoreException {
if (!new File(path).exists()) {
throw new HashDatabaseDoesNotExistException(path);
}
if (hashSetPaths.contains(path)) {
throw new HashDatabaseAlreadyAddedException(path);
}
if (hashSetNames.contains(hashSetName)) {
throw new DuplicateHashSetNameException(hashSetName);
}
return addHashDatabase(SleuthkitJNI.openHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
}
/**
* Adds a new hash database to the set of hash databases used to classify files as known or known bad.
* Does not save the configuration - the configuration is only saved on demand to support cancellation of
* configuration panels.
* @param hashSetName Hash set name used to represent the hash database in user interface components.
* @param path Full path to the database file to be created.
* @param searchDuringIngest A flag indicating whether or not the hash database should be searched during ingest.
* @param sendIngestMessages A flag indicating whether hash set hit messages should be sent as ingest messages.
* @param knownFilesType The classification to apply to files whose hashes are found in the hash database.
* @return A HashDb representing the hash database.
* @throws TskCoreException
*/
synchronized HashDb addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDatabaseFileAlreadyExistsException, IllegalHashDatabaseFileNameExtensionException, DuplicateHashSetNameException, HashDatabaseAlreadyAddedException, TskCoreException {
File file = new File(path);
if (file.exists()) {
throw new HashDatabaseFileAlreadyExistsException(path);
}
if (!FilenameUtils.getExtension(file.getName()).equalsIgnoreCase(HASH_DATABASE_FILE_EXTENSON)) {
throw new IllegalHashDatabaseFileNameExtensionException();
}
if (hashSetPaths.contains(path)) {
throw new HashDatabaseAlreadyAddedException(path);
}
if (hashSetNames.contains(hashSetName)) {
throw new DuplicateHashSetNameException(hashSetName);
}
return addHashDatabase(SleuthkitJNI.createHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
}
private HashDb addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws TskCoreException {
// Wrap an object around the handle.
HashDb hashDb = new HashDb(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
// Get the indentity data before updating the collections since the
// accessor methods may throw.
String databasePath = hashDb.getDatabasePath();
String indexPath = hashDb.getIndexPath();
// Update the collections used to ensure that hash set names are unique
// and the same database is not added to the configuration more than once.
hashSetNames.add(hashDb.getHashSetName());
if (!databasePath.equals("None")) {
hashSetPaths.add(databasePath);
}
if (!indexPath.equals("None")) {
hashSetPaths.add(indexPath);
}
// Add the hash database to the appropriate collection for its type.
if (hashDb.getKnownFilesType() == HashDb.KnownFilesType.KNOWN) {
knownHashSets.add(hashDb);
}
else {
knownBadHashSets.add(hashDb);
}
}
return hashDb;
}
synchronized void indexHashDatabase(HashDb hashDb, boolean deleteIndexFile) {
hashDb.addPropertyChangeListener(this);
HashDbIndexer creator = new HashDbIndexer(hashDb, deleteIndexFile);
creator.execute();
}
@Override
public void propertyChange(PropertyChangeEvent event) {
if (event.getPropertyName().equals(HashDb.Event.INDEXING_DONE.name())) {
HashDb hashDb = (HashDb)event.getNewValue();
if (null != hashDb) {
try {
String indexPath = hashDb.getIndexPath();
if (!indexPath.equals("None")) {
hashSetPaths.add(indexPath);
}
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDb.getHashSetName() + " hash database after indexing", ex);
}
}
}
}
/**
* Removes a hash database from the configuration. Does not save the
* configuration - the configuration is only saved on demand to support
* cancellation of configuration panels.
* Removes a hash database from the set of hash databases used to classify
* files as known or known bad. Does not save the configuration - the
* configuration is only saved on demand to support cancellation of
* configuration panels.
* @throws TskCoreException
*/
public void removeHashSet(HashDb hashDb) {
try {
hashDb.close();
}
catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error closing hash database at " + hashDb.getDatabasePath(), ex);
}
synchronized void removeHashDatabase(HashDb hashDb) {
// Remove the database from whichever hash set list it occupies,
// and remove its hash set name from the hash set used to ensure unique
// hash set names are used, before undertaking These operations will succeed and constitute
// a mostly effective removal, even if the subsequent operations fail.
knownHashSets.remove(hashDb);
knownBadHashSets.remove(hashDb);
hashSetNames.remove(hashDb.getHashSetName());
// Now undertake the operations that could throw.
try {
hashSetPaths.remove(hashDb.getIndexPath());
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDb.getHashSetName() + " hash database when removing the database", ex);
}
try {
if (!hashDb.hasIndexOnly()) {
hashSetPaths.remove(hashDb.getDatabasePath());
}
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting database path of " + hashDb.getHashSetName() + " hash database when removing the database", ex);
}
try {
hashDb.close();
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + hashDb.getHashSetName() + " hash database when removing the database", ex);
}
}
/**
* Gets all of the configured hash sets.
* @return A list, possibly empty, of HashDb objects representing the hash
* sets.
* Gets all of the hash databases used to classify files as known or known bad.
* @return A list, possibly empty, of hash databases.
*/
public List<HashDb> getAllHashSets() {
public synchronized List<HashDb> getAllHashSets() {
List<HashDb> hashDbs = new ArrayList<>();
hashDbs.addAll(knownHashSets);
hashDbs.addAll(knownBadHashSets);
return Collections.unmodifiableList(hashDbs);
return hashDbs;
}
/**
* Gets the configured known files hash sets.
* @return A list, possibly empty, of HashDb objects.
* Gets all of the hash databases used to classify files as known.
* @return A list, possibly empty, of hash databases.
*/
public List<HashDb> getKnownHashSets() {
return Collections.unmodifiableList(knownHashSets);
public synchronized List<HashDb> getKnownFileHashSets() {
List<HashDb> hashDbs = new ArrayList<>();
hashDbs.addAll(knownHashSets);
return hashDbs;
}
/**
* Gets the configured known bad files hash sets.
* @return A list, possibly empty, of HashDb objects.
* Gets all of the hash databases used to classify files as known bad.
* @return A list, possibly empty, of hash databases.
*/
public List<HashDb> getKnownBadHashSets() {
return Collections.unmodifiableList(knownBadHashSets);
public synchronized List<HashDb> getKnownBadFileHashSets() {
List<HashDb> hashDbs = new ArrayList<>();
hashDbs.addAll(knownBadHashSets);
return hashDbs;
}
/**
* Gets all of the configured hash sets that accept updates.
* @return A list, possibly empty, of HashDb objects.
/**
* Gets all of the hash databases that accept updates.
* @return A list, possibly empty, of hash databases.
*/
public List<HashDb> getUpdateableHashSets() {
public synchronized List<HashDb> getUpdateableHashSets() {
List<HashDb> updateableDbs = getUpdateableHashSets(knownHashSets);
updateableDbs.addAll(getUpdateableHashSets(knownBadHashSets));
return Collections.unmodifiableList(updateableDbs);
return updateableDbs;
}
private List<HashDb> getUpdateableHashSets(List<HashDb> hashDbs) {
@ -156,25 +337,25 @@ public class HashDbManager {
}
}
catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error checking updateable status of hash database at " + db.getDatabasePath(), ex);
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error checking updateable status of " + db.getHashSetName() + " hash database", ex);
}
}
return updateableDbs;
}
}
/**
* Sets the value for the flag that indicates whether hashes should be calculated
* for content even if no hash databases are configured.
*/
public void alwaysCalculateHashes(boolean alwaysCalculateHashes) {
synchronized void setAlwaysCalculateHashes(boolean alwaysCalculateHashes) {
this.alwaysCalculateHashes = alwaysCalculateHashes;
}
/**
* Accesses the flag that indicates whether hashes should be calculated
* Gets the flag that indicates whether hashes should be calculated
* for content even if no hash databases are configured.
*/
public boolean shouldAlwaysCalculateHashes() {
synchronized boolean getAlwaysCalculateHashes() {
return alwaysCalculateHashes;
}
@ -183,7 +364,7 @@ public class HashDbManager {
* saved on demand to support cancellation of configuration panels.
* @return True on success, false otherwise.
*/
public boolean save() {
public synchronized boolean save() {
return writeHashSetConfigurationToDisk();
}
@ -191,67 +372,59 @@ public class HashDbManager {
* Restores the last saved hash sets configuration. This supports
* cancellation of configuration panels.
*/
public void loadLastSavedConfiguration() {
public synchronized void loadLastSavedConfiguration() {
closeHashDatabases(knownHashSets);
closeHashDatabases(knownBadHashSets);
hashSetNames.clear();
hashSetPaths.clear();
if (hashSetsConfigurationFileExists()) {
readHashSetsConfigurationFromDisk();
}
}
private void closeHashDatabases(List<HashDb> hashDbs) {
String dbPath = "";
try {
for (HashDb db : hashDbs) {
dbPath = db.getDatabasePath();
db.close();
private void closeHashDatabases(List<HashDb> hashDatabases) {
for (HashDb database : hashDatabases) {
try {
database.close();
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + database.getHashSetName() + " hash database", ex);
}
}
catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error closing hash database at " + dbPath, ex);
}
hashDbs.clear();
hashDatabases.clear();
}
private boolean hashSetsConfigurationFileExists() {
File f = new File(xmlFilePath);
return f.exists() && f.canRead() && f.canWrite();
}
private boolean writeHashSetConfigurationToDisk() {
boolean success = false;
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element rootEl = doc.createElement(ROOT_EL);
Element rootEl = doc.createElement(ROOT_ELEMENT);
doc.appendChild(rootEl);
writeHashDbsToDisk(doc, rootEl, knownHashSets);
writeHashDbsToDisk(doc, rootEl, knownBadHashSets);
String calcValue = Boolean.toString(alwaysCalculateHashes);
Element setCalc = doc.createElement(SET_CALC);
setCalc.setAttribute(SET_VALUE, calcValue);
Element setCalc = doc.createElement(ALWAYS_CALCULATE_HASHES_ELEMENT);
setCalc.setAttribute(VALUE_ATTRIBUTE, calcValue);
rootEl.appendChild(setCalc);
success = XMLUtil.saveDoc(HashDbManager.class, xmlFilePath, ENCODING, doc);
success = XMLUtil.saveDoc(HashDbManager.class, configFilePath, ENCODING, doc);
}
catch (ParserConfigurationException e) {
logger.log(Level.SEVERE, "Error saving hash databases", e);
catch (ParserConfigurationException ex) {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error saving hash databases", ex);
}
return success;
}
private static void writeHashDbsToDisk(Document doc, Element rootEl, List<HashDb> hashDbs) {
for (HashDb db : hashDbs) {
Element setEl = doc.createElement(SET_EL);
setEl.setAttribute(SET_NAME_ATTR, db.getHashSetName());
setEl.setAttribute(SET_TYPE_ATTR, db.getKnownFilesType().toString());
setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, Boolean.toString(db.getUseForIngest()));
setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, Boolean.toString(db.getShowInboxMessages()));
String path = null;
// Get the path for the hash database before writing anything, in
// case an exception is thrown.
String path;
try {
if (db.hasIndexOnly()) {
path = db.getIndexPath();
@ -259,102 +432,176 @@ public class HashDbManager {
else {
path = db.getDatabasePath();
}
Element pathEl = doc.createElement(PATH_EL);
pathEl.setTextContent(path);
setEl.appendChild(pathEl);
rootEl.appendChild(setEl);
}
catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting path of hash database " + db.getHashSetName() + ", unable to save configuration", ex);
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting path of hash database " + db.getHashSetName() + ", discarding from hash database configuration", ex);
continue;
}
Element setElement = doc.createElement(SET_ELEMENT);
setElement.setAttribute(SET_NAME_ATTRIBUTE, db.getHashSetName());
setElement.setAttribute(SET_TYPE_ATTRIBUTE, db.getKnownFilesType().toString());
setElement.setAttribute(SEARCH_DURING_INGEST_ATTRIBUTE, Boolean.toString(db.getSearchDuringIngest()));
setElement.setAttribute(SEND_INGEST_MESSAGES_ATTRIBUTE, Boolean.toString(db.getSendIngestMessages()));
Element pathElement = doc.createElement(PATH_ELEMENT);
pathElement.setTextContent(path);
setElement.appendChild(pathElement);
rootEl.appendChild(setElement);
}
}
// TODO: The return value from this function is never checked. Failure is not indicated to the user. Is this desired?
private boolean hashSetsConfigurationFileExists() {
File f = new File(configFilePath);
return f.exists() && f.canRead() && f.canWrite();
}
private boolean readHashSetsConfigurationFromDisk() {
final Document doc = XMLUtil.loadDoc(HashDbManager.class, xmlFilePath, XSDFILE);
// Open the XML document that implements the configuration file.
final Document doc = XMLUtil.loadDoc(HashDbManager.class, configFilePath, XSD_FILE_NAME);
if (doc == null) {
return false;
}
// Get the root element.
Element root = doc.getDocumentElement();
if (root == null) {
logger.log(Level.SEVERE, "Error loading hash sets: invalid file format.");
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading hash sets: invalid file format.");
return false;
}
NodeList setsNList = root.getElementsByTagName(SET_EL);
// Get the hash set elements.
NodeList setsNList = root.getElementsByTagName(SET_ELEMENT);
int numSets = setsNList.getLength();
if(numSets == 0) {
logger.log(Level.WARNING, "No element hash_set exists.");
Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, "No element hash_set exists.");
}
// Create HashDb objects for each hash set element. Skip to the next hash database if the definition of
// a particular hash database is not well-formed.
String attributeErrorMessage = " attribute was not set for hash_set at index {0}, cannot make instance of HashDb class";
String elementErrorMessage = " element was not set for hash_set at index {0}, cannot make instance of HashDb class";
for (int i = 0; i < numSets; ++i) {
Element setEl = (Element) setsNList.item(i);
final String name = setEl.getAttribute(SET_NAME_ATTR);
final String type = setEl.getAttribute(SET_TYPE_ATTR);
final String useForIngest = setEl.getAttribute(SET_USE_FOR_INGEST_ATTR);
final String showInboxMessages = setEl.getAttribute(SET_SHOW_INBOX_MESSAGES);
Boolean useForIngestBool = Boolean.parseBoolean(useForIngest);
Boolean showInboxMessagesBool = Boolean.parseBoolean(showInboxMessages);
String path = null;
NodeList pathsNList = setEl.getElementsByTagName(PATH_EL);
if (pathsNList.getLength() > 0) {
// Shouldn't be more than 1
Element pathEl = (Element) pathsNList.item(0);
path = pathEl.getTextContent();
File database = new File(path);
if(!database.exists() && JOptionPane.showConfirmDialog(null, "Database " + name + " could not be found at location\n" + path + "\nWould you like to search for the file?", "Missing Database", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
path = searchForFile();
String hashSetName = setEl.getAttribute(SET_NAME_ATTRIBUTE);
if (hashSetName.isEmpty()) {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, SET_NAME_ATTRIBUTE + attributeErrorMessage, i);
continue;
}
// Handle configurations saved before duplicate hash set names were not permitted.
if (hashSetNames.contains(hashSetName)) {
int suffix = 0;
String newHashSetName;
do {
++suffix;
newHashSetName = hashSetName + suffix;
}
while (hashSetNames.contains(newHashSetName));
JOptionPane.showMessageDialog(null, "Duplicate hash set name " + hashSetName + " found.\nReplacing with " + newHashSetName + ".", "Open Hash Database Error", JOptionPane.ERROR_MESSAGE);
hashSetName = newHashSetName;
}
String knownFilesType = setEl.getAttribute(SET_TYPE_ATTRIBUTE);
if(knownFilesType.isEmpty()) {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, SET_TYPE_ATTRIBUTE + attributeErrorMessage, i);
continue;
}
if(name.isEmpty()) {
logger.log(Level.WARNING, "Name was not set for hash_set at index {0}.", i);
}
// Handle legacy known files types.
if (knownFilesType.equals("NSRL")) {
knownFilesType = HashDb.KnownFilesType.KNOWN.toString();
}
if(type.isEmpty()) {
logger.log(Level.SEVERE, "Type was not set for hash_set at index {0}, cannot make instance of HashDb class.", i);
return false;
final String searchDuringIngest = setEl.getAttribute(SEARCH_DURING_INGEST_ATTRIBUTE);
if (searchDuringIngest.isEmpty()) {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, SEARCH_DURING_INGEST_ATTRIBUTE + attributeErrorMessage, i);
continue;
}
if(useForIngest.isEmpty()) {
logger.log(Level.WARNING, "UseForIngest was not set for hash_set at index {0}.", i);
Boolean seearchDuringIngestFlag = Boolean.parseBoolean(searchDuringIngest);
final String sendIngestMessages = setEl.getAttribute(SEND_INGEST_MESSAGES_ATTRIBUTE);
if (searchDuringIngest.isEmpty()) {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, SEND_INGEST_MESSAGES_ATTRIBUTE + attributeErrorMessage, i);
continue;
}
if(showInboxMessages.isEmpty()) {
logger.log(Level.WARNING, "ShowInboxMessages was not set for hash_set at index {0}.", i);
Boolean sendIngestMessagesFlag = Boolean.parseBoolean(sendIngestMessages);
String dbPath;
NodeList pathsNList = setEl.getElementsByTagName(PATH_ELEMENT);
if (pathsNList.getLength() > 0) {
Element pathEl = (Element) pathsNList.item(0); // Shouldn't be more than one.
dbPath = pathEl.getTextContent();
if (dbPath.isEmpty()) {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, PATH_ELEMENT + elementErrorMessage, i);
continue;
}
}
if(path == null) {
logger.log(Level.WARNING, "No path for hash_set at index {0}, cannot make instance of HashDb class.", i);
else {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, PATH_ELEMENT + elementErrorMessage, i);
continue;
}
dbPath = getValidFilePath(hashSetName, dbPath);
if (null != dbPath) {
try {
addExistingHashDatabase(hashSetName, dbPath, seearchDuringIngestFlag, sendIngestMessagesFlag, HashDb.KnownFilesType.valueOf(knownFilesType));
}
catch (HashDatabaseDoesNotExistException | DuplicateHashSetNameException | HashDatabaseAlreadyAddedException | TskCoreException ex) {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash database", ex);
JOptionPane.showMessageDialog(null, "Unable to open " + dbPath + " hash database.", "Open Hash Database Error", JOptionPane.ERROR_MESSAGE);
}
}
else {
try {
addHashSet(HashDb.openHashDatabase(name, path, useForIngestBool, showInboxMessagesBool, KnownFilesType.valueOf(type)));
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash database", ex);
JOptionPane.showMessageDialog(null, "Unable to open " + path + " hash database.", "Open Hash Database Error", JOptionPane.ERROR_MESSAGE);
}
Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, "No valid path for hash_set at index {0}, cannot make instance of HashDb class", i);
}
}
NodeList calcList = root.getElementsByTagName(SET_CALC);
// Get the element that stores the always calculate hashes flag.
NodeList calcList = root.getElementsByTagName(ALWAYS_CALCULATE_HASHES_ELEMENT);
if (calcList.getLength() > 0) {
Element calcEl = (Element) calcList.item(0); // Shouldn't be more than 1
final String value = calcEl.getAttribute(SET_VALUE);
Element calcEl = (Element) calcList.item(0); // Shouldn't be more than one.
final String value = calcEl.getAttribute(VALUE_ATTRIBUTE);
alwaysCalculateHashes = Boolean.parseBoolean(value);
}
else {
logger.log(Level.WARNING, "No element hash_calculate exists.");
Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, " element ");
alwaysCalculateHashes = false;
}
return true;
}
private String getValidFilePath(String hashSetName, String configuredPath) {
// Check the configured path.
File database = new File(configuredPath);
if (database.exists()) {
return configuredPath;
}
// Try a path that could be in an older version of the configuration file.
String legacyPath = configuredPath + LEGACY_INDEX_FILE_EXTENSION;
database = new File(legacyPath);
if (database.exists()) {
return legacyPath;
}
// Give the user an opportunity to find the desired file.
String newPath = null;
if (JOptionPane.showConfirmDialog(null, "Database " + hashSetName + " could not be found at location\n" + configuredPath + "\nWould you like to search for the file?", "Missing Database", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
newPath = searchForFile();
if (null != newPath && !newPath.isEmpty()) {
database = new File(newPath);
if (!database.exists()) {
newPath = null;
}
}
}
return newPath;
}
private String searchForFile() {
String filePath = null;
JFileChooser fc = new JFileChooser();
fc.setDragEnabled(false);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
@ -362,18 +609,223 @@ public class HashDbManager {
FileNameExtensionFilter filter = new FileNameExtensionFilter("Hash Database File", EXTENSION);
fc.setFileFilter(filter);
fc.setMultiSelectionEnabled(false);
String filePath = null;
if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
File f = fc.getSelectedFile();
try {
filePath = f.getCanonicalPath();
}
catch (IOException ex) {
logger.log(Level.WARNING, "Couldn't get selected file path", ex);
Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, "Couldn't get selected file path", ex);
}
}
}
return filePath;
}
/**
* Instances of this class represent hash databases used to classify files as known or know bad.
*/
public static class HashDb {
/**
* Indicates how files with hashes stored in a particular hash database
* object should be classified.
*/
public enum KnownFilesType{
KNOWN("Known"),
KNOWN_BAD("Known Bad");
private String displayName;
private KnownFilesType(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return this.displayName;
}
}
/**
* Property change events published by hash database objects.
*/
public enum Event {
INDEXING_DONE
}
private int handle;
private String hashSetName;
private boolean searchDuringIngest;
private boolean sendIngestMessages;
private KnownFilesType knownFilesType;
private boolean indexing;
private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
private HashDb(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) {
this.handle = handle;
this.hashSetName = hashSetName;
this.searchDuringIngest = useForIngest;
this.sendIngestMessages = sendHitMessages;
this.knownFilesType = knownFilesType;
this.indexing = false;
}
/**
* Adds a listener for the events defined in HashDb.Event.
*/
public void addPropertyChangeListener(PropertyChangeListener pcl) {
propertyChangeSupport.addPropertyChangeListener(pcl);
}
/**
* Removes a listener for the events defined in HashDb.Event.
*/
public void removePropertyChangeListener(PropertyChangeListener pcl) {
propertyChangeSupport.removePropertyChangeListener(pcl);
}
public String getHashSetName() {
return hashSetName;
}
public String getDatabasePath() throws TskCoreException {
return SleuthkitJNI.getHashDatabasePath(handle);
}
public String getIndexPath() throws TskCoreException {
return SleuthkitJNI.getHashDatabaseIndexPath(handle);
}
public KnownFilesType getKnownFilesType() {
return knownFilesType;
}
public boolean getSearchDuringIngest() {
return searchDuringIngest;
}
void setSearchDuringIngest(boolean useForIngest) {
this.searchDuringIngest = useForIngest;
}
public boolean getSendIngestMessages() {
return sendIngestMessages;
}
void setSendIngestMessages(boolean showInboxMessages) {
this.sendIngestMessages = showInboxMessages;
}
/**
* Indicates whether the hash database accepts updates.
* @return True if the database accepts updates, false otherwise.
*/
public boolean isUpdateable() throws TskCoreException {
return SleuthkitJNI.isUpdateableHashDatabase(this.handle);
}
/**
* Adds hashes of content (if calculated) to the hash database.
* @param content The content for which the calculated hashes, if any, are to be added to the hash database.
* @throws TskCoreException
*/
public void addHashes(Content content) throws TskCoreException {
addHashes(content, null);
}
/**
* Adds hashes of content (if calculated) to the hash database.
* @param content The content for which the calculated hashes, if any, are to be added to the hash database.
* @param comment A comment to associate with the hashes, e.g., the name of the case in which the content was encountered.
* @throws TskCoreException
*/
public void addHashes(Content content, String comment) throws TskCoreException {
// TODO: This only works for AbstractFiles and MD5 hashes at present.
assert content instanceof AbstractFile;
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile)content;
if (null != file.getMd5Hash()) {
SleuthkitJNI.addToHashDatabase(null, file.getMd5Hash(), null, null, comment, handle);
}
}
}
public boolean hasMd5HashOf(Content content) throws TskCoreException {
boolean result = false;
assert content instanceof AbstractFile;
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile)content;
if (null != file.getMd5Hash()) {
result = SleuthkitJNI.lookupInHashDatabase(file.getMd5Hash(), handle);
}
}
return result;
}
public HashInfo lookUp(Content content) throws TskCoreException {
HashInfo result = null;
// TODO: This only works for AbstractFiles and MD5 hashes at present.
assert content instanceof AbstractFile;
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile)content;
if (null != file.getMd5Hash()) {
result = SleuthkitJNI.lookupInHashDatabaseVerbose(file.getMd5Hash(), handle);
}
}
return result;
}
boolean hasLookupIndex() throws TskCoreException {
return SleuthkitJNI.hashDatabaseHasLookupIndex(handle);
}
boolean hasIndexOnly() throws TskCoreException {
return SleuthkitJNI.hashDatabaseHasLegacyLookupIndexOnly(handle);
}
boolean canBeReIndexed() throws TskCoreException {
return SleuthkitJNI.hashDatabaseCanBeReindexed(handle);
}
boolean isIndexing() {
return indexing;
}
private void close() throws TskCoreException {
SleuthkitJNI.closeHashDatabase(handle);
}
}
private class HashDbIndexer extends SwingWorker<Object, Void> {
private ProgressHandle progress = null;
private HashDb hashDb = null;
private boolean deleteIndexFile = false;
HashDbIndexer(HashDb hashDb, boolean deleteIndexFile) {
this.hashDb = hashDb;
this.deleteIndexFile = deleteIndexFile;
};
@Override
protected Object doInBackground() {
hashDb.indexing = true;
progress = ProgressHandleFactory.createHandle("Indexing " + hashDb.hashSetName);
progress.start();
progress.switchToIndeterminate();
try {
SleuthkitJNI.createLookupIndexForHashDatabase(hashDb.handle, deleteIndexFile);
}
catch (TskCoreException ex) {
Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error indexing hash database", ex);
JOptionPane.showMessageDialog(null, "Error indexing " + hashDb.getHashSetName() + " hash database.", "Hash Database Indexing Error", JOptionPane.ERROR_MESSAGE);
}
return null;
}
@Override
protected void done() {
hashDb.indexing = false;
progress.finish();
hashDb.propertyChangeSupport.firePropertyChange(HashDb.Event.INDEXING_DONE.toString(), null, hashDb);
}
}
}

View File

@ -28,7 +28,7 @@
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Component id="jScrollPane2" alignment="1" pref="0" max="32767" attributes="1"/>
<Component id="calcHashesButton" alignment="1" max="32767" attributes="0"/>
<Component id="alwaysCalcHashesCheckbox" alignment="1" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
@ -46,7 +46,7 @@
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane2" min="-2" pref="55" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="32767" attributes="0"/>
<Component id="calcHashesButton" min="-2" max="-2" attributes="0"/>
<Component id="alwaysCalcHashesCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
@ -92,10 +92,10 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="calcHashesButton">
<Component class="javax.swing.JCheckBox" name="alwaysCalcHashesCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbSimpleConfigPanel.calcHashesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/hashdatabase/Bundle.properties" key="HashDbSimpleConfigPanel.alwaysCalcHashesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>

View File

@ -30,6 +30,7 @@ import javax.swing.table.TableColumn;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
/**
* Instances of this class provide a simplified UI for managing the hash sets configuration.
@ -39,8 +40,8 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
private HashDbsTableModel knownBadTableModel;
public HashDbSimpleConfigPanel() {
knownTableModel = new HashDbsTableModel(HashDbManager.getInstance().getKnownHashSets());
knownBadTableModel = new HashDbsTableModel(HashDbManager.getInstance().getKnownBadHashSets());
knownTableModel = new HashDbsTableModel(HashDbManager.getInstance().getKnownFileHashSets());
knownBadTableModel = new HashDbsTableModel(HashDbManager.getInstance().getKnownBadFileHashSets());
initComponents();
customizeComponents();
}
@ -51,10 +52,10 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
// Add a listener to the always calculate hashes checkbox component.
// The listener passes the user's selection on to the hash database manager.
calcHashesButton.addActionListener( new ActionListener() {
alwaysCalcHashesCheckbox.addActionListener( new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
HashDbManager.getInstance().alwaysCalculateHashes(calcHashesButton.isSelected());
HashDbManager.getInstance().setAlwaysCalculateHashes(alwaysCalcHashesCheckbox.isSelected());
}
});
@ -82,33 +83,33 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
public void refreshComponents() {
knownTableModel.refresh();
knownBadTableModel.refresh();
refreshAlwaysCalcHashesComponents();
refreshAlwaysCalcHashesCheckbox();
}
private void refreshAlwaysCalcHashesComponents() {
private void refreshAlwaysCalcHashesCheckbox() {
boolean noHashDbsConfiguredForIngest = true;
for (HashDb hashDb : HashDbManager.getInstance().getAllHashSets()) {
try {
if (hashDb.getUseForIngest()== true && hashDb.hasLookupIndex()) {
if (hashDb.getSearchDuringIngest()== true && hashDb.hasLookupIndex()) {
noHashDbsConfiguredForIngest = false;
break;
}
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbSimpleConfigPanel.class.getName()).log(Level.SEVERE, "Error getting info for hash database at " + hashDb.getDatabasePath(), ex);
Logger.getLogger(HashDbSimpleConfigPanel.class.getName()).log(Level.SEVERE, "Error getting info for " + hashDb.getHashSetName() + " hash database", ex);
}
}
// If there are no hash databases configured for use during file ingest,
// default to always calculating hashes of the files.
if (noHashDbsConfiguredForIngest) {
calcHashesButton.setEnabled(true);
calcHashesButton.setSelected(true);
HashDbManager.getInstance().alwaysCalculateHashes(true);
alwaysCalcHashesCheckbox.setEnabled(true);
alwaysCalcHashesCheckbox.setSelected(true);
HashDbManager.getInstance().setAlwaysCalculateHashes(true);
} else {
calcHashesButton.setEnabled(false);
calcHashesButton.setSelected(false);
HashDbManager.getInstance().alwaysCalculateHashes(false);
alwaysCalcHashesCheckbox.setEnabled(false);
alwaysCalcHashesCheckbox.setSelected(false);
HashDbManager.getInstance().setAlwaysCalculateHashes(false);
}
}
@ -137,7 +138,7 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
public Object getValueAt(int rowIndex, int columnIndex) {
HashDb db = hashDbs.get(rowIndex);
if (columnIndex == 0) {
return db.getUseForIngest();
return db.getSearchDuringIngest();
} else {
return db.getHashSetName();
}
@ -157,10 +158,10 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
dbHasIndex = db.hasLookupIndex();
}
catch (TskCoreException ex) {
Logger.getLogger(HashDbSimpleConfigPanel.class.getName()).log(Level.SEVERE, "Error getting info for hash database at " + db.getDatabasePath(), ex);
Logger.getLogger(HashDbSimpleConfigPanel.class.getName()).log(Level.SEVERE, "Error getting info for " + db.getHashSetName() + " hash database", ex);
}
if(((Boolean) getValueAt(rowIndex, columnIndex)) || dbHasIndex) {
db.setUseForIngest((Boolean) aValue);
db.setSearchDuringIngest((Boolean) aValue);
}
else {
JOptionPane.showMessageDialog(HashDbSimpleConfigPanel.this, "Hash databases must be indexed before they can be used for ingest");
@ -187,7 +188,7 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
knownHashTable = new javax.swing.JTable();
knownBadHashDbsLabel = new javax.swing.JLabel();
knownHashDbsLabel = new javax.swing.JLabel();
calcHashesButton = new javax.swing.JCheckBox();
alwaysCalcHashesCheckbox = new javax.swing.JCheckBox();
jScrollPane2 = new javax.swing.JScrollPane();
knownBadHashTable = new javax.swing.JTable();
@ -202,7 +203,7 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
knownHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.knownHashDbsLabel.text")); // NOI18N
calcHashesButton.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.calcHashesButton.text")); // NOI18N
alwaysCalcHashesCheckbox.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.alwaysCalcHashesCheckbox.text")); // NOI18N
jScrollPane2.setBorder(javax.swing.BorderFactory.createEtchedBorder());
@ -233,7 +234,7 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
.addComponent(knownBadHashDbsLabel))
.addGap(0, 0, Short.MAX_VALUE))
.addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addComponent(calcHashesButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(alwaysCalcHashesCheckbox, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
@ -248,13 +249,13 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 55, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(calcHashesButton)
.addComponent(alwaysCalcHashesCheckbox)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox calcHashesButton;
private javax.swing.JCheckBox alwaysCalcHashesCheckbox;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JLabel knownBadHashDbsLabel;

View File

@ -28,6 +28,7 @@ import java.util.logging.Level;
import javax.swing.JOptionPane;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.hashdatabase.HashDbManager.HashDb;
/**
* This class exists as a stop-gap measure to force users to have an indexed database.
@ -210,7 +211,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen
this.CURRENTLYON_LABEL.setText("Currently indexing 1 database");
if (!this.toIndex.isIndexing()) {
this.toIndex.addPropertyChangeListener(this);
this.toIndex.createIndex(okToDeleteOldIndexFile(toIndex));
HashDbManager.getInstance().indexHashDatabase(toIndex, okToDeleteOldIndexFile(toIndex));
}
}
@ -226,7 +227,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen
this.CURRENTLYON_LABEL.setText("Currently indexing 1 of " + length);
if (!db.isIndexing()) {
db.addPropertyChangeListener(this);
db.createIndex(okToDeleteOldIndexFile(db));
HashDbManager.getInstance().indexHashDatabase(db, okToDeleteOldIndexFile(db));
}
}
}
@ -251,8 +252,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen
this.dispose();
} else {
currentcount++;
this.CURRENTLYON_LABEL.setText("Currently indexing " + currentcount + " of " + length);
this.CURRENTLYON_LABEL.setText("Currently indexing " + currentcount + " of " + length);
}
}
}