19 package org.sleuthkit.autopsy.modules.hashdatabase;
21 import java.beans.PropertyChangeEvent;
22 import java.beans.PropertyChangeListener;
23 import java.beans.PropertyChangeSupport;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Objects;
31 import java.util.concurrent.ExecutionException;
32 import java.util.logging.Level;
33 import javax.swing.JFileChooser;
34 import javax.swing.JOptionPane;
35 import javax.swing.SwingWorker;
36 import javax.swing.filechooser.FileNameExtensionFilter;
37 import org.apache.commons.io.FilenameUtils;
38 import org.netbeans.api.progress.ProgressHandle;
39 import org.openide.util.NbBundle;
40 import org.openide.util.NbBundle.Messages;
65 PropertyChangeSupport changeSupport =
new PropertyChangeSupport(
HashDbManager.class);
76 DB_ADDED, DB_DELETED, DB_INDEXED
85 if (instance == null) {
92 changeSupport.addPropertyChangeListener(listener);
96 changeSupport.removePropertyChangeListener(listener);
99 synchronized boolean verifyAllDatabasesLoadedCorrectly(){
112 static String getHashDatabaseFileExtension() {
125 super(message, exception);
150 hashDb = this.addExistingHashDatabaseNoSave(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType);
158 if (!
new File(path).exists()) {
159 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class,
"HashDbManager.hashDbDoesNotExistExceptionMsg", path));
162 if (hashSetPaths.contains(path)) {
163 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class,
"HashDbManager.hashDbAlreadyAddedExceptionMsg", path));
166 if (hashSetNames.contains(hashSetName)) {
167 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class,
"HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName));
170 hashDb =
addHashDatabase(SleuthkitJNI.openHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
171 }
catch (TskCoreException ex) {
172 throw new HashDbManagerException(ex.getMessage());
195 public synchronized HashDb addNewHashDatabase(String hashSetName, String path,
boolean searchDuringIngest,
boolean sendIngestMessages,
210 File file =
new File(path);
212 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class,
"HashDbManager.hashDbFileExistsExceptionMsg", path));
214 if (!FilenameUtils.getExtension(file.getName()).equalsIgnoreCase(HASH_DATABASE_FILE_EXTENSON)) {
215 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class,
"HashDbManager.illegalHashDbFileNameExtensionMsg",
216 getHashDatabaseFileExtension()));
219 if (hashSetPaths.contains(path)) {
220 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class,
"HashDbManager.hashDbAlreadyAddedExceptionMsg", path));
223 if (hashSetNames.contains(hashSetName)) {
224 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class,
"HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName));
229 throw new HashDbManagerException(ex.getMessage());
236 HashDb hashDb =
new HashDb(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
246 if (!databasePath.equals(
"None")) {
247 hashSetPaths.add(databasePath);
249 if (!indexPath.equals(
"None")) {
250 hashSetPaths.add(indexPath);
255 knownHashSets.add(hashDb);
257 knownBadHashSets.add(hashDb);
262 changeSupport.firePropertyChange(
SetEvt.
DB_ADDED.toString(), null, hashSetName);
263 }
catch (Exception e) {
264 logger.log(Level.SEVERE,
"HashDbManager listener threw exception", e);
266 NbBundle.getMessage(
this.getClass(),
"HashDbManager.moduleErr"),
267 NbBundle.getMessage(
this.getClass(),
"HashDbManager.moduleErrorListeningToUpdatesMsg"),
273 synchronized void indexHashDatabase(
HashDb hashDb) {
275 HashDbIndexer creator =
new HashDbIndexer(hashDb);
283 if (null != hashDb) {
286 if (!indexPath.equals(
"None")) {
287 hashSetPaths.add(indexPath);
312 if (ingestIsRunning) {
313 throw new HashDbManagerException(NbBundle.getMessage(
this.getClass(),
"HashDbManager.ingestRunningExceptionMsg"));
320 knownHashSets.remove(hashDb);
321 knownBadHashSets.remove(hashDb);
322 hashSetNames.remove(hashSetName);
345 changeSupport.firePropertyChange(
SetEvt.
DB_DELETED.toString(), null, hashSetName);
346 }
catch (Exception e) {
347 logger.log(Level.SEVERE,
"HashDbManager listener threw exception", e);
349 NbBundle.getMessage(
this.getClass(),
"HashDbManager.moduleErr"),
350 NbBundle.getMessage(
this.getClass(),
"HashDbManager.moduleErrorListeningToUpdatesMsg"),
355 void save() throws HashDbManagerException {
357 if (!HashLookupSettings.writeSettings(
new HashLookupSettings(this.knownHashSets, this.knownBadHashSets))) {
358 throw new HashDbManagerException(NbBundle.getMessage(
this.getClass(),
"HashDbManager.saveErrorExceptionMsg"));
360 }
catch (HashLookupSettings.HashLookupSettingsException ex) {
361 throw new HashDbManagerException(NbBundle.getMessage(
this.getClass(),
"HashDbManager.saveErrorExceptionMsg"));
372 List<HashDb> hashDbs =
new ArrayList<>();
373 hashDbs.addAll(knownHashSets);
374 hashDbs.addAll(knownBadHashSets);
384 List<HashDb> hashDbs =
new ArrayList<>();
385 hashDbs.addAll(knownHashSets);
395 List<HashDb> hashDbs =
new ArrayList<>();
396 hashDbs.addAll(knownBadHashSets);
408 return updateableDbs;
412 ArrayList<HashDb> updateableDbs =
new ArrayList<>();
413 for (
HashDb db : hashDbs) {
415 if (db.isUpdateable()) {
416 updateableDbs.add(db);
419 Logger.
getLogger(
HashDbManager.class.getName()).log(Level.SEVERE,
"Error checking updateable status of " + db.getHashSetName() +
" hash database", ex);
422 return updateableDbs;
432 hashSetNames.clear();
433 hashSetPaths.clear();
439 for (
HashDb database : hashDatabases) {
446 hashDatabases.clear();
451 HashLookupSettings settings = HashLookupSettings.readSettings();
453 }
catch (HashLookupSettings.HashLookupSettingsException ex) {
464 @Messages({
"# {0} - database name",
"HashDbManager.noDbPath.message=Couldn't get valid database path for: {0}"})
466 allDatabasesLoadedCorrectly =
true;
467 List<HashDbInfo> hashDbInfoList = settings.getHashDbInfo();
468 for (HashDbInfo hashDb : hashDbInfoList) {
471 if (dbPath != null) {
474 logger.log(Level.WARNING, Bundle.HashDbManager_noDbPath_message(hashDb.
getHashSetName()));
475 allDatabasesLoadedCorrectly =
false;
479 JOptionPane.showMessageDialog(null,
480 NbBundle.getMessage(
this.getClass(),
482 NbBundle.getMessage(
this.getClass(),
"HashDbManager.openHashDbErr"),
483 JOptionPane.ERROR_MESSAGE);
484 allDatabasesLoadedCorrectly =
false;
497 HashLookupSettings.writeSettings(
new HashLookupSettings(this.knownHashSets, this.knownBadHashSets));
498 allDatabasesLoadedCorrectly =
true;
499 }
catch (HashLookupSettings.HashLookupSettingsException ex) {
500 allDatabasesLoadedCorrectly =
false;
501 logger.log(Level.SEVERE,
"Could not overwrite hash database settings.", ex);
508 File database =
new File(configuredPath);
509 if (database.exists()) {
510 return configuredPath;
514 String newPath = null;
516 JOptionPane.showConfirmDialog(null,
517 NbBundle.getMessage(
this.getClass(),
"HashDbManager.dlgMsg.dbNotFoundAtLoc",
518 hashSetName, configuredPath),
519 NbBundle.getMessage(
this.getClass(),
"HashDbManager.dlgTitle.MissingDb"),
520 JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
522 if (null != newPath && !newPath.isEmpty()) {
523 database =
new File(newPath);
524 if (!database.exists()) {
533 String filePath = null;
534 JFileChooser fc =
new JFileChooser();
535 fc.setDragEnabled(
false);
536 fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
537 String[] EXTENSION =
new String[]{
"txt",
"idx",
"hash",
"Hash",
"kdb"};
538 FileNameExtensionFilter filter =
new FileNameExtensionFilter(
539 NbBundle.getMessage(
this.getClass(),
"HashDbManager.fileNameExtensionFilter.title"), EXTENSION);
540 fc.setFileFilter(filter);
541 fc.setMultiSelectionEnabled(
false);
542 if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
543 File f = fc.getSelectedFile();
545 filePath = f.getCanonicalPath();
546 }
catch (IOException ex) {
570 this.displayName = displayName;
574 return this.displayName;
594 private HashDb(
int handle, String hashSetName,
boolean useForIngest,
boolean sendHitMessages,
KnownFilesType knownFilesType) {
597 this.searchDuringIngest = useForIngest;
598 this.sendIngestMessages = sendHitMessages;
600 this.indexing =
false;
609 propertyChangeSupport.addPropertyChangeListener(pcl);
618 propertyChangeSupport.removePropertyChangeListener(pcl);
641 void setSearchDuringIngest(
boolean useForIngest) {
642 this.searchDuringIngest = useForIngest;
649 void setSendIngestMessages(
boolean showInboxMessages) {
650 this.sendIngestMessages = showInboxMessages;
689 if (content instanceof AbstractFile) {
690 AbstractFile file = (AbstractFile) content;
718 boolean result =
false;
720 if (content instanceof AbstractFile) {
721 AbstractFile file = (AbstractFile) content;
742 if (content instanceof AbstractFile) {
743 AbstractFile file = (AbstractFile) content;
759 boolean canBeReIndexed() throws TskCoreException {
763 boolean isIndexing() {
767 private void close() throws TskCoreException {
774 code = 47 * code + Integer.hashCode(handle);
775 code = 47 * code + Objects.hashCode(this.hashSetName);
776 code = 47 * code + Objects.hashCode(this.propertyChangeSupport);
777 code = 47 * code + Objects.hashCode(this.knownFilesType);
786 if (getClass() != obj.getClass()) {
790 if (!Objects.equals(
this.hashSetName, other.
hashSetName)) {
823 progress = ProgressHandle.createHandle(
824 NbBundle.getMessage(
this.getClass(),
"HashDbManager.progress.indexingHashSet", hashDb.
hashSetName));
826 progress.switchToIndeterminate();
829 }
catch (TskCoreException ex) {
831 JOptionPane.showMessageDialog(null,
832 NbBundle.getMessage(
this.getClass(),
833 "HashDbManager.dlgMsg.errorIndexingHashSet",
835 NbBundle.getMessage(
this.getClass(),
"HashDbManager.hashDbIndexingErr"),
836 JOptionPane.ERROR_MESSAGE);
849 }
catch (InterruptedException | ExecutionException ex) {
850 logger.log(Level.SEVERE,
"Error creating index", ex);
852 NbBundle.getMessage(
this.getClass(),
"HashDbManager.errCreatingIndex.title"),
853 NbBundle.getMessage(
this.getClass(),
"HashDbManager.errCreatingIndex.msg", ex.getMessage()),
856 catch (java.util.concurrent.CancellationException ex) {
862 }
catch (Exception e) {
863 logger.log(Level.SEVERE,
"HashDbManager listener threw exception", e);
865 NbBundle.getMessage(
this.getClass(),
"HashDbManager.moduleErr"),
866 NbBundle.getMessage(
this.getClass(),
"HashDbManager.moduleErrorListeningToUpdatesMsg"),
boolean getSendIngestMessages()
Set< String > hashSetPaths
static String getHashDatabaseIndexPath(int dbHandle)
void configureSettings(HashLookupSettings settings)
static void createLookupIndexForHashDatabase(int dbHandle)
static final Logger logger
static final String HASH_DATABASE_FILE_EXTENSON
void loadHashsetsConfiguration()
static void addToHashDatabase(String filename, String md5, String sha1, String sha256, String comment, int dbHandle)
void addHashes(Content content, String comment)
static synchronized IngestManager getInstance()
static int createHashDatabase(String path)
static boolean runningWithGUI
boolean getSearchDuringIngest()
synchronized void addPropertyChangeListener(PropertyChangeListener listener)
HashDbManagerException(String message)
final PropertyChangeSupport propertyChangeSupport
HashDb addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
static HashHitInfo lookupInHashDatabaseVerbose(String hash, int dbHandle)
final KnownFilesType knownFilesType
boolean isIngestRunning()
static final long serialVersionUID
List< HashDb > getUpdateableHashSets(List< HashDb > hashDbs)
synchronized HashDb addNewHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
HashDbManagerException(String message, Throwable exception)
List< HashDb > knownHashSets
static final long serialVersionUID
static boolean hashDatabaseIsIndexOnly(int dbHandle)
synchronized void removeHashDatabase(HashDb hashDb)
KnownFilesType(String displayName)
void addPropertyChangeListener(PropertyChangeListener pcl)
List< HashDb > knownBadHashSets
boolean allDatabasesLoadedCorrectly
synchronized List< HashDb > getKnownBadFileHashSets()
synchronized void removeHashDatabaseNoSave(HashDb hashDb)
static HashDbManager instance
Set< String > hashSetNames
static synchronized HashDbManager getInstance()
String getValidFilePath(String hashSetName, String configuredPath)
void addHashes(List< HashEntry > hashes)
boolean equals(Object obj)
void addHashes(Content content)
synchronized HashDb addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
HashHitInfo lookupMD5(Content content)
synchronized void removePropertyChangeListener(PropertyChangeListener listener)
synchronized List< HashDb > getUpdateableHashSets()
static int openHashDatabase(String path)
synchronized List< HashDb > getAllHashSets()
static boolean lookupInHashDatabase(String hash, int dbHandle)
static boolean hashDatabaseHasLookupIndex(int dbHandle)
void propertyChange(PropertyChangeEvent event)
boolean sendIngestMessages
void closeHashDatabases(List< HashDb > hashDatabases)
boolean lookupMD5Quick(Content content)
boolean searchDuringIngest
synchronized void loadLastSavedConfiguration()
synchronized static Logger getLogger(String name)
static void show(String title, String message, MessageType type, ActionListener actionListener)
KnownFilesType getKnownFilesType()
static boolean isUpdateableHashDatabase(int dbHandle)
static boolean hashDatabaseCanBeReindexed(int dbHandle)
synchronized List< HashDb > getKnownFileHashSets()
void removePropertyChangeListener(PropertyChangeListener pcl)
HashDb(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType)
static String getHashDatabasePath(int dbHandle)
static void closeHashDatabase(int dbHandle)
synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)