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)