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));
227 hashDb =
addHashDatabase(SleuthkitJNI.createHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
228 }
catch (TskCoreException ex) {
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);
289 }
catch (TskCoreException ex) {
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);
327 }
catch (TskCoreException ex) {
334 }
catch (TskCoreException ex) {
339 }
catch (TskCoreException ex) {
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);
418 }
catch (TskCoreException ex) {
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) {
442 }
catch (TskCoreException ex) {
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;
477 }
catch (TskCoreException ex) {
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);
626 return SleuthkitJNI.getHashDatabasePath(handle);
630 return SleuthkitJNI.getHashDatabaseIndexPath(handle);
641 void setSearchDuringIngest(
boolean useForIngest) {
642 this.searchDuringIngest = useForIngest;
649 void setSendIngestMessages(
boolean showInboxMessages) {
650 this.sendIngestMessages = showInboxMessages;
661 return SleuthkitJNI.isUpdateableHashDatabase(this.handle);
672 public void addHashes(Content content)
throws TskCoreException {
686 public void addHashes(Content content, String comment)
throws TskCoreException {
688 assert content instanceof AbstractFile;
689 if (content instanceof AbstractFile) {
690 AbstractFile file = (AbstractFile) content;
691 if (null != file.getMd5Hash()) {
692 SleuthkitJNI.addToHashDatabase(null, file.getMd5Hash(), null, null, comment,
handle);
704 public void addHashes(List<HashEntry> hashes)
throws TskCoreException {
705 SleuthkitJNI.addToHashDatabase(hashes, handle);
718 boolean result =
false;
719 assert content instanceof AbstractFile;
720 if (content instanceof AbstractFile) {
721 AbstractFile file = (AbstractFile) content;
722 if (null != file.getMd5Hash()) {
723 result = SleuthkitJNI.lookupInHashDatabase(file.getMd5Hash(),
handle);
738 public HashHitInfo
lookupMD5(Content content)
throws TskCoreException {
739 HashHitInfo result = null;
741 assert content instanceof AbstractFile;
742 if (content instanceof AbstractFile) {
743 AbstractFile file = (AbstractFile) content;
744 if (null != file.getMd5Hash()) {
745 result = SleuthkitJNI.lookupInHashDatabaseVerbose(file.getMd5Hash(),
handle);
751 boolean hasIndex() throws TskCoreException {
752 return SleuthkitJNI.hashDatabaseHasLookupIndex(handle);
756 return SleuthkitJNI.hashDatabaseIsIndexOnly(handle);
759 boolean canBeReIndexed() throws TskCoreException {
760 return SleuthkitJNI.hashDatabaseCanBeReindexed(handle);
763 boolean isIndexing() {
767 private void close() throws TskCoreException {
768 SleuthkitJNI.closeHashDatabase(handle);
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();
828 SleuthkitJNI.createLookupIndexForHashDatabase(hashDb.
handle);
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
void configureSettings(HashLookupSettings settings)
static final Logger logger
static final String HASH_DATABASE_FILE_EXTENSON
void loadHashsetsConfiguration()
void addHashes(Content content, String comment)
static synchronized IngestManager getInstance()
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)
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
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)
static boolean coreComponentsAreActive()
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()
synchronized List< HashDb > getAllHashSets()
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()
synchronized List< HashDb > getKnownFileHashSets()
void removePropertyChangeListener(PropertyChangeListener pcl)
HashDb(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType)
synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)