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)