Autopsy  4.21.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
HashDbManager.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2021 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.modules.hashdatabase;
20 
21 import java.beans.PropertyChangeEvent;
22 import java.beans.PropertyChangeListener;
23 import java.beans.PropertyChangeSupport;
24 import java.io.File;
25 import java.io.FilenameFilter;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.MissingResourceException;
31 import java.util.Objects;
32 import java.util.Set;
33 import java.util.concurrent.ExecutionException;
34 import java.util.logging.Level;
35 import java.util.regex.Matcher;
36 import java.util.regex.Pattern;
37 import java.util.stream.Collectors;
38 import java.util.stream.Stream;
39 import javax.swing.JFileChooser;
40 import javax.swing.JOptionPane;
41 import javax.swing.SwingWorker;
42 import javax.swing.filechooser.FileNameExtensionFilter;
43 import org.apache.commons.io.FilenameUtils;
44 import org.apache.commons.lang.StringUtils;
45 import org.netbeans.api.progress.ProgressHandle;
46 import org.openide.modules.InstalledFileLocator;
47 import org.openide.util.NbBundle;
48 import org.openide.util.NbBundle.Messages;
49 import org.openide.windows.WindowManager;
60 import org.sleuthkit.datamodel.AbstractFile;
61 import org.sleuthkit.datamodel.Content;
62 import org.sleuthkit.datamodel.HashEntry;
63 import org.sleuthkit.datamodel.HashHitInfo;
64 import org.sleuthkit.datamodel.SleuthkitJNI;
65 import org.sleuthkit.datamodel.TskCoreException;
66 import org.sleuthkit.datamodel.TskData;
70 
75 public class HashDbManager implements PropertyChangeListener {
76 
77  private static final String HASH_DATABASE_FILE_EXTENSON = "kdb"; //NON-NLS
78  private static HashDbManager instance = null;
79  private List<HashDb> hashSets = new ArrayList<>();
80  private Set<String> hashSetNames = new HashSet<>();
81  private Set<String> hashSetPaths = new HashSet<>();
82 
83  private List<HashDb> officialHashSets = new ArrayList<>();
84  private Set<String> officialHashSetNames = new HashSet<>();
85  private Set<String> officialHashSetPaths = new HashSet<>();
86 
87  PropertyChangeSupport changeSupport = new PropertyChangeSupport(HashDbManager.class);
88  private static final Logger logger = Logger.getLogger(HashDbManager.class.getName());
89  private boolean allDatabasesLoadedCorrectly = false;
90 
91  private static final String OFFICIAL_HASH_SETS_FOLDER = "OfficialHashSets";
92  private static final String KDB_EXT = "kdb";
93 
94  private static final String DB_NAME_PARAM = "dbName";
95  private static final String KNOWN_STATUS_PARAM = "knownStatus";
96  private static final Pattern OFFICIAL_FILENAME = Pattern.compile("(?<" + DB_NAME_PARAM + ">.+?)\\.(?<" + KNOWN_STATUS_PARAM + ">.+?)\\." + KDB_EXT);
97 
99 
100  private static final FilenameFilter DEFAULT_KDB_FILTER = new FilenameFilter() {
101  @Override
102  public boolean accept(File dir, String name) {
103  return name.endsWith("." + KDB_EXT);
104  }
105  };
106 
112  public enum SetEvt {
113 
114  DB_ADDED, DB_DELETED, DB_INDEXED
115  };
116 
122  public static synchronized HashDbManager getInstance() {
123  if (instance == null) {
124  instance = new HashDbManager();
125  }
126  return instance;
127  }
128 
129  public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
130  changeSupport.addPropertyChangeListener(listener);
131  }
132 
133  public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
134  changeSupport.removePropertyChangeListener(listener);
135  }
136 
137  synchronized boolean verifyAllDatabasesLoadedCorrectly() {
139  }
140 
141  private HashDbManager() {
142  chooserHelper = new JFileChooserFactory();
144  }
145 
151  static String getHashDatabaseFileExtension() {
153  }
154 
155  public class HashDbManagerException extends Exception {
156 
157  private static final long serialVersionUID = 1L;
158 
159  private HashDbManagerException(String message) {
160  super(message);
161  }
162 
163  private HashDbManagerException(String message, Throwable exception) {
164  super(message, exception);
165  }
166  }
167 
187  public synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException {
188  HashDb hashDb = null;
189  hashDb = this.addExistingHashDatabaseNoSave(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType);
190  this.save();
191  return hashDb;
192  }
193 
194  synchronized HashDb addExistingHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException {
195  HashDb hashDb = null;
196  try {
197  if (!new File(path).exists()) {
198  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.hashDbDoesNotExistExceptionMsg", path));
199  }
200 
201  checkDbCollision(path, hashSetName);
202 
203  hashDb = addHashDatabase(SleuthkitJNI.openHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
204  } catch (TskCoreException ex) {
205  throw new HashDbManagerException(ex.getMessage());
206  }
207  return hashDb;
208  }
209 
228  public synchronized HashDb addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages,
229  HashDb.KnownFilesType knownFilesType) throws HashDbManagerException {
230 
231  HashDb hashDb = null;
232  hashDb = this.addNewHashDatabaseNoSave(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType);
233 
234  this.save();
235 
236  return hashDb;
237  }
238 
239  public synchronized HashDb addNewHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages,
240  HashDb.KnownFilesType knownFilesType) throws HashDbManagerException {
241  HashDb hashDb = null;
242  try {
243  File file = new File(path);
244  if (file.exists()) {
245  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.hashDbFileExistsExceptionMsg", path));
246  }
247  if (!FilenameUtils.getExtension(file.getName()).equalsIgnoreCase(HASH_DATABASE_FILE_EXTENSON)) {
248  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.illegalHashDbFileNameExtensionMsg",
249  getHashDatabaseFileExtension()));
250  }
251 
252  checkDbCollision(path, hashSetName);
253 
254  hashDb = addHashDatabase(SleuthkitJNI.createHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
255  } catch (TskCoreException ex) {
256  throw new HashDbManagerException(ex.getMessage());
257  }
258  return hashDb;
259  }
260 
272  private void checkDbCollision(String path, String hashSetName) throws HashDbManagerException, MissingResourceException {
273  if (hashSetPaths.contains(path) || officialHashSetPaths.contains(path)) {
274  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.hashDbAlreadyAddedExceptionMsg", path));
275  }
276 
277  if (hashSetNames.contains(hashSetName) || officialHashSetNames.contains(hashSetName)) {
278  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName));
279  }
280  }
281 
282  private SleuthkitHashSet addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws TskCoreException {
283  // Wrap an object around the handle.
284  SleuthkitHashSet hashDb = new SleuthkitHashSet(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
285 
286  // Get the indentity data before updating the collections since the
287  // accessor methods may throw.
288  String databasePath = hashDb.getDatabasePath();
289  String indexPath = hashDb.getIndexPath();
290 
291  // Update the collections used to ensure that hash set names are unique
292  // and the same database is not added to the configuration more than once.
293  hashSetNames.add(hashDb.getHashSetName());
294  if (!databasePath.equals("None")) { //NON-NLS
295  hashSetPaths.add(databasePath);
296  }
297  if (!indexPath.equals("None")) { //NON-NLS
298  hashSetPaths.add(indexPath);
299  }
300 
301  // Add the hash database to the collection
302  hashSets.add(hashDb);
303 
304  // Let any external listeners know that there's a new set
305  try {
306  changeSupport.firePropertyChange(SetEvt.DB_ADDED.toString(), null, hashSetName);
307  } catch (Exception e) {
308  logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS
310  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErr"),
311  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErrorListeningToUpdatesMsg"),
313  }
314  return hashDb;
315  }
316 
317  CentralRepoHashSet addExistingCentralRepoHashSet(String hashSetName, String version, int referenceSetID,
318  boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType,
319  boolean readOnly) throws TskCoreException {
320 
321  if (!CentralRepository.isEnabled()) {
322  throw new TskCoreException("Could not load central repository hash set " + hashSetName + " - central repository is not enabled");
323  }
324 
325  CentralRepoHashSet db = new CentralRepoHashSet(hashSetName, version, referenceSetID, searchDuringIngest,
326  sendIngestMessages, knownFilesType, readOnly);
327 
328  if (!db.isValid()) {
329  throw new TskCoreException("Error finding hash set " + hashSetName + " in central repository");
330  }
331 
332  // Add the hash database to the collection
333  if(!hashSets.contains(db)) {
334  hashSets.add(db);
335 
336  // Let any external listeners know that there's a new set
337  try {
338  changeSupport.firePropertyChange(SetEvt.DB_ADDED.toString(), null, hashSetName);
339  } catch (Exception e) {
340  logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS
341  MessageNotifyUtil.Notify.show(
342  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErr"),
343  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErrorListeningToUpdatesMsg"),
344  MessageNotifyUtil.MessageType.ERROR);
345  }
346  }
347  return db;
348 
349  }
350 
351  synchronized void indexHashDatabase(SleuthkitHashSet hashDb) {
352  hashDb.addPropertyChangeListener(this);
353  HashDbIndexer creator = new HashDbIndexer(hashDb);
354  creator.execute();
355  }
356 
357  @Override
358  public void propertyChange(PropertyChangeEvent event) {
359  if (event.getPropertyName().equals(SleuthkitHashSet.Event.INDEXING_DONE.name())) {
360  SleuthkitHashSet hashDb = (SleuthkitHashSet) event.getNewValue();
361  if (null != hashDb) {
362  try {
363  String indexPath = hashDb.getIndexPath();
364  if (!indexPath.equals("None")) { //NON-NLS
365  hashSetPaths.add(indexPath);
366  }
367  } catch (TskCoreException ex) {
368  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDb.getHashSetName() + " hash set after indexing", ex); //NON-NLS
369  }
370  }
371  }
372  }
373 
382  public synchronized void removeHashDatabase(HashDb hashDb) throws HashDbManagerException {
383  this.removeHashDatabaseNoSave(hashDb);
384  this.save();
385  }
386 
387  public synchronized void removeHashDatabaseNoSave(HashDb hashDb) throws HashDbManagerException {
388  // Don't remove a database if ingest is running
389  boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning();
390  if (ingestIsRunning) {
391  throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.ingestRunningExceptionMsg"));
392  }
393  // Remove the database from whichever hash set list it occupies,
394  // and remove its hash set name from the hash set used to ensure unique
395  // hash set names are used, before undertaking These operations will succeed and constitute
396  // a mostly effective removal, even if the subsequent operations fail.
397  String hashSetName = hashDb.getHashSetName();
398  hashSetNames.remove(hashSetName);
399  hashSets.remove(hashDb);
400 
401  // Now undertake the operations that could throw.
402  // Indexing is only relevanet for sleuthkit hashsets
403  if (hashDb instanceof SleuthkitHashSet) {
404  SleuthkitHashSet hashDatabase = (SleuthkitHashSet) hashDb;
405  try {
406  if (hashDatabase.hasIndex()) {
407  hashSetPaths.remove(hashDatabase.getIndexPath());
408  }
409  } catch (TskCoreException ex) {
410  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDatabase.getHashSetName() + " hash set when removing the hash set", ex); //NON-NLS
411  }
412 
413  try {
414  if (!hashDatabase.hasIndexOnly()) {
415  hashSetPaths.remove(hashDatabase.getDatabasePath());
416  }
417  } catch (TskCoreException ex) {
418  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting hash set path of " + hashDatabase.getHashSetName() + " hash set when removing the hash set", ex); //NON-NLS
419  }
420 
421  try {
422  hashDatabase.close();
423  } catch (TskCoreException ex) {
424  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + hashDb.getHashSetName() + " hash set when removing the hash set", ex); //NON-NLS
425  }
426  }
427 
428  // Let any external listeners know that a set has been deleted
429  try {
430  changeSupport.firePropertyChange(SetEvt.DB_DELETED.toString(), null, hashSetName);
431  } catch (Exception e) {
432  logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS
434  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErr"),
435  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErrorListeningToUpdatesMsg"),
437  }
438  }
439 
440  void save() throws HashDbManagerException {
441  try {
442  if (!HashLookupSettings.writeSettings(new HashLookupSettings(HashLookupSettings.convertHashSetList(this.hashSets)))) {
443  throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.saveErrorExceptionMsg"));
444  }
445  } catch (HashLookupSettings.HashLookupSettingsException ex) {
446  throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.saveErrorExceptionMsg"));
447  }
448  }
449 
457  public synchronized List<HashDb> getAllHashSets() {
458  try {
460  } catch (TskCoreException ex) {
461  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS
462  }
463 
464  return Stream.concat(this.officialHashSets.stream(), this.hashSets.stream())
465  .collect(Collectors.toList());
466  }
467 
473  public synchronized List<HashDb> getKnownFileHashSets() {
474  return getAllHashSets()
475  .stream()
476  .filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN))
477  .collect(Collectors.toList());
478  }
479 
485  public synchronized List<HashDb> getKnownBadFileHashSets() {
486  return getAllHashSets()
487  .stream()
488  .filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN_BAD))
489  .collect(Collectors.toList());
490  }
491 
497  public synchronized List<HashDb> getUpdateableHashSets() {
499  }
500 
501  private List<HashDb> getUpdateableHashSets(List<HashDb> hashDbs) {
502  return hashDbs
503  .stream()
504  .filter((HashDb db) -> {
505  try {
506  return db.isUpdateable();
507  } catch (TskCoreException ex) {
508  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error checking updateable status of " + db.getHashSetName() + " hash set", ex); //NON-NLS
509  return false;
510  }
511  })
512  .collect(Collectors.toList());
513  }
514 
515  private List<HashDbInfo> getCentralRepoHashSetsFromDatabase() {
516  List<HashDbInfo> crHashSets = new ArrayList<>();
518  try {
520  for (CentralRepoFileSet globalSet : crSets) {
521 
522  // Defaults for fields not stored in the central repository:
523  // searchDuringIngest: false
524  // sendIngestMessages: true if the hash set is notable
525  boolean sendIngestMessages = KnownFilesType.fromFileKnown(globalSet.getFileKnownStatus()).equals(HashDb.KnownFilesType.KNOWN_BAD);
526  crHashSets.add(new HashDbInfo(globalSet.getSetName(), globalSet.getVersion(),
527  globalSet.getGlobalSetID(), KnownFilesType.fromFileKnown(globalSet.getFileKnownStatus()), globalSet.isReadOnly(), false, sendIngestMessages));
528  }
529  } catch (CentralRepoException ex) {
530  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS
531  }
532  }
533  return crHashSets;
534  }
535 
540  public synchronized void loadLastSavedConfiguration() {
541  closeHashDatabases(this.hashSets);
542  hashSetNames.clear();
543  hashSetPaths.clear();
544 
546  }
547 
548  private void closeHashDatabases(List<HashDb> hashDatabases) {
549  for (HashDb database : hashDatabases) {
550  if (database instanceof SleuthkitHashSet) {
551  try {
552  ((SleuthkitHashSet) database).close();
553  } catch (TskCoreException ex) {
554  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + database.getHashSetName() + " hash set", ex); //NON-NLS
555  }
556  }
557  }
558  hashDatabases.clear();
559  }
560 
561  private void loadHashsetsConfiguration() {
563 
564  try {
565  HashLookupSettings settings = HashLookupSettings.readSettings();
566  this.configureSettings(settings, officialHashSetNames);
567  } catch (HashLookupSettings.HashLookupSettingsException ex) {
568  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Could not read Hash lookup settings from disk.", ex);
569  }
570  }
571 
576  private void loadOfficialHashSets() {
577  officialHashSetPaths = new HashSet<>();
578  officialHashSetNames = new HashSet<>();
579 
580  try {
581  officialHashSets = loadOfficialHashSetsFromFolder(OFFICIAL_HASH_SETS_FOLDER);
582  officialHashSets.forEach(db -> {
583  officialHashSetNames.add(db.getHashSetName());
584  try {
585  String databasePath = db.getDatabasePath();
586  String indexPath = db.getIndexPath();
587 
588  if (StringUtils.isNotBlank(databasePath) && !databasePath.equals("None")) { //NON-NLS
589  officialHashSetPaths.add(databasePath);
590  }
591  if (StringUtils.isNotBlank(indexPath) && !indexPath.equals("None")) { //NON-NLS
592  officialHashSetPaths.add(indexPath);
593  }
594  } catch (TskCoreException ex) {
595  logger.log(Level.SEVERE, "There was an error loading the official hash set name.", ex);
596  }
597  });
598  } catch (HashDbManagerException ex) {
599  logger.log(Level.WARNING, "There was an error loading the official hash sets.", ex);
600  officialHashSets = new ArrayList<HashDb>();
601  }
602  }
603 
615  @Messages({
616  "# {0} - hashSetName",
617  "HashDbManager_handleNameConflict_conflictSuffix={0} (Custom)"
618  })
619  private List<HashDbInfo> handleNameConflict(List<HashDbInfo> curHashsets, Set<String> officialNames) {
620  Set<String> curNames = new HashSet<String>(officialNames);
621  boolean change = false;
622  List<HashDbInfo> newItems = new ArrayList<>();
623  for (HashDbInfo hashset : curHashsets) {
624  String thisName = hashset.getHashSetName();
625  if (curNames.contains(thisName)) {
626  while (curNames.contains(thisName)) {
627  thisName = Bundle.HashDbManager_handleNameConflict_conflictSuffix(thisName);
628  }
629 
630  newItems.add(new HashDbInfo(
631  thisName,
632  hashset.getKnownFilesType(),
633  hashset.getSearchDuringIngest(),
634  hashset.getSendIngestMessages(),
635  hashset.getPath(),
636  hashset.getReferenceSetID(),
637  hashset.getVersion(),
638  hashset.isReadOnly(),
639  hashset.isCentralRepoDatabaseType()
640  ));
641  change = true;
642  } else {
643  newItems.add(hashset);
644  }
645 
646  curNames.add(thisName);
647  }
648 
649  if (!change) {
650  return curHashsets;
651  } else {
652  try {
653  HashLookupSettings.writeSettings(new HashLookupSettings(newItems));
654  HashLookupSettings toRet = HashLookupSettings.readSettings();
655  return toRet.getHashDbInfo();
656  } catch (HashLookupSettings.HashLookupSettingsException ex) {
657  logger.log(Level.SEVERE, "There was an error while trying to resave after name conflict.", ex);
658  return newItems;
659  }
660  }
661  }
662 
672  private List<HashDb> loadOfficialHashSetsFromFolder(String folder) throws HashDbManagerException {
673  File configFolder = InstalledFileLocator.getDefault().locate(
674  folder, HashDbManager.class.getPackage().getName(), false);
675 
676  if (configFolder == null || !configFolder.exists() || !configFolder.isDirectory()) {
677  throw new HashDbManagerException("Folder provided: " + folder + " does not exist.");
678  }
679 
680  return Stream.of(configFolder.listFiles(DEFAULT_KDB_FILTER))
681  .map((f) -> {
682  try {
683  return getOfficialHashDbFromFile(f);
684  } catch (HashDbManagerException | TskCoreException ex) {
685  logger.log(Level.WARNING, String.format("Hashset: %s could not be properly read.", f.getAbsolutePath()), ex);
686  return null;
687  }
688  })
689  .filter((hashdb) -> hashdb != null)
690  .collect(Collectors.toList());
691  }
692 
705  private HashDb getOfficialHashDbFromFile(File file) throws HashDbManagerException, TskCoreException {
706  if (file == null || !file.exists()) {
707  throw new HashDbManagerException(String.format("No file found for: %s", file == null ? "<null>" : file.getAbsolutePath()));
708  }
709  String filename = file.getName();
710  Matcher match = OFFICIAL_FILENAME.matcher(filename);
711  if (!match.find()) {
712  throw new HashDbManagerException(String.format("File with name: %s does not match regex of: %s", filename, OFFICIAL_FILENAME.toString()));
713  }
714 
715  String hashdbName = match.group(DB_NAME_PARAM);
716  final String knownStatus = match.group(KNOWN_STATUS_PARAM);
717 
718  KnownFilesType knownFilesType = Stream.of(HashDb.KnownFilesType.values())
719  .filter(k -> k.getIdentifier().toUpperCase().equals(knownStatus.toUpperCase()))
720  .findFirst()
721  .orElseThrow(() -> new HashDbManagerException(String.format("No KnownFilesType matches %s for file: %s", knownStatus, filename)));
722 
723  return new SleuthkitHashSet(
724  SleuthkitJNI.openHashDatabase(file.getAbsolutePath()),
725  hashdbName,
726  true, //searchDuringIngest
727  false, //sendIngestMessages
728  knownFilesType,
729  true); // official set
730  }
731 
740  @Messages({"# {0} - hash set name", "HashDbManager.noDbPath.message=Couldn't get valid hash set path for: {0}",
741  "HashDbManager.centralRepoLoadError.message=Error loading central repository hash sets"})
742  private void configureSettings(HashLookupSettings settings, Set<String> officialSetNames) {
743  allDatabasesLoadedCorrectly = true;
744  List<HashDbInfo> hashDbInfoList = settings.getHashDbInfo();
745  hashDbInfoList = handleNameConflict(hashDbInfoList, officialSetNames);
746 
747  for (HashDbInfo hashDbInfo : hashDbInfoList) {
748  configureLocalDb(hashDbInfo);
749  }
750 
752  configureCrDbs();
753  }
754 
755  /*
756  * NOTE: When RuntimeProperties.coreComponentsAreActive() is "false", I
757  * don't think we should overwrite hash db settings file because we were
758  * unable to load a database. The user should have to fix the issue or
759  * remove the database from settings. Overwiting the settings
760  * effectively removes the database from HashLookupSettings and the user
761  * may not know about this because the dialogs are not being displayed.
762  * The next time user starts Autopsy, HashDB will load without errors
763  * and the user may think that the problem was solved.
764  */
765  if (!allDatabasesLoadedCorrectly && RuntimeProperties.runningWithGUI()) {
766  try {
767  HashLookupSettings.writeSettings(new HashLookupSettings(HashLookupSettings.convertHashSetList(this.hashSets)));
768  allDatabasesLoadedCorrectly = true;
769  } catch (HashLookupSettings.HashLookupSettingsException ex) {
770  allDatabasesLoadedCorrectly = false;
771  logger.log(Level.SEVERE, "Could not overwrite hash set settings.", ex);
772  }
773  }
774  }
775 
779  private void configureCrDbs() {
780  try {
782  } catch (TskCoreException ex) {
783  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash set", ex); //NON-NLS
784 
785  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
786  Bundle.HashDbManager_centralRepoLoadError_message(),
787  NbBundle.getMessage(this.getClass(), "HashDbManager.openHashDbErr"),
788  JOptionPane.ERROR_MESSAGE);
789  allDatabasesLoadedCorrectly = false;
790  }
791  }
792 
797  private void configureLocalDb(HashDbInfo hashDbInfo) {
798  try {
799  if (hashDbInfo.isFileDatabaseType()) {
800  String dbPath = this.getValidFilePath(hashDbInfo.getHashSetName(), hashDbInfo.getPath());
801  if (dbPath != null) {
802  addHashDatabase(SleuthkitJNI.openHashDatabase(dbPath), hashDbInfo.getHashSetName(), hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType());
803  } else {
804  logger.log(Level.WARNING, Bundle.HashDbManager_noDbPath_message(hashDbInfo.getHashSetName()));
805  allDatabasesLoadedCorrectly = false;
806  }
807  } else {
809  addExistingCentralRepoHashSet(hashDbInfo.getHashSetName(), hashDbInfo.getVersion(),
810  hashDbInfo.getReferenceSetID(),
811  hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(),
812  hashDbInfo.getKnownFilesType(), hashDbInfo.isReadOnly());
813  }
814  }
815  } catch (TskCoreException ex) {
816  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash set", ex); //NON-NLS
817  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
818  NbBundle.getMessage(this.getClass(),
819  "HashDbManager.unableToOpenHashDbMsg", hashDbInfo.getHashSetName()),
820  NbBundle.getMessage(this.getClass(), "HashDbManager.openHashDbErr"),
821  JOptionPane.ERROR_MESSAGE);
822  allDatabasesLoadedCorrectly = false;
823  }
824  }
825 
826  private void updateHashSetsFromCentralRepository() throws TskCoreException {
828  List<HashDbInfo> crHashDbInfoList = getCentralRepoHashSetsFromDatabase();
829  for (HashDbInfo hashDbInfo : crHashDbInfoList) {
830  if (hashDbInfoIsNew(hashDbInfo)) {
831  addExistingCentralRepoHashSet(hashDbInfo.getHashSetName(), hashDbInfo.getVersion(),
832  hashDbInfo.getReferenceSetID(),
833  hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType(),
834  hashDbInfo.isReadOnly());
835  }
836  }
837  }
838  }
839 
840  private boolean hashDbInfoIsNew(HashDbInfo dbInfo) {
841  for (HashDb db : this.hashSets) {
842  if (dbInfo.matches(db)) {
843  return false;
844  }
845  }
846  return true;
847  }
848 
849  private String getValidFilePath(String hashSetName, String configuredPath) {
850  // Check the configured path.
851  File database = new File(configuredPath);
852  if (database.exists()) {
853  return configuredPath;
854  }
855 
856  // Give the user an opportunity to find the desired file.
857  String newPath = null;
859  && JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(),
860  NbBundle.getMessage(this.getClass(), "HashDbManager.dlgMsg.dbNotFoundAtLoc",
861  hashSetName, configuredPath),
862  NbBundle.getMessage(this.getClass(), "HashDbManager.dlgTitle.MissingDb"),
863  JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
864  newPath = searchForFile();
865  if (null != newPath && !newPath.isEmpty()) {
866  database = new File(newPath);
867  if (!database.exists()) {
868  newPath = null;
869  }
870  }
871  }
872  return newPath;
873  }
874 
875  private String searchForFile() {
876  String filePath = null;
877  JFileChooser fc = chooserHelper.getChooser();
878  fc.setDragEnabled(false);
879  fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
880  String[] EXTENSION = new String[]{"txt", "idx", "hash", "Hash", "kdb"}; //NON-NLS
881  FileNameExtensionFilter filter = new FileNameExtensionFilter(
882  NbBundle.getMessage(this.getClass(), "HashDbManager.fileNameExtensionFilter.title"), EXTENSION);
883  fc.setFileFilter(filter);
884  fc.setMultiSelectionEnabled(false);
885  if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
886  File f = fc.getSelectedFile();
887  try {
888  filePath = f.getCanonicalPath();
889  } catch (IOException ex) {
890  Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, "Couldn't get selected file path", ex); //NON-NLS
891  }
892  }
893  return filePath;
894  }
895 
896  public static abstract class HashDb {
897 
902  @Messages({
903  "HashDbManager.noChange.text=No Change",
904  "HashDbManager.known.text=Known",
905  "HashDbManager.knownBad.text=Notable"
906  })
907  public enum KnownFilesType {
908 
909  KNOWN(Bundle.HashDbManager_known_text(), "Known", TskData.FileKnown.KNOWN, false, false),
910  KNOWN_BAD(Bundle.HashDbManager_knownBad_text(), "Notable", TskData.FileKnown.BAD, true, true),
911  NO_CHANGE(Bundle.HashDbManager_noChange_text(), "NoChange", TskData.FileKnown.UNKNOWN, true, false);
912 
913  private final String displayName;
914  private final String identifier;
915  private final TskData.FileKnown fileKnown;
916  private final boolean allowSendInboxMessages;
917  private final boolean defaultSendInboxMessages;
918 
919  KnownFilesType(String displayName, String identifier, TskData.FileKnown fileKnown,
920  boolean allowSendInboxMessages, boolean defaultSendInboxMessages) {
921 
922  this.displayName = displayName;
923  this.identifier = identifier;
924  this.fileKnown = fileKnown;
925  this.allowSendInboxMessages = allowSendInboxMessages;
926  this.defaultSendInboxMessages = defaultSendInboxMessages;
927  }
928 
937  return allowSendInboxMessages;
938  }
939 
948  return defaultSendInboxMessages;
949  }
950 
957  String getIdentifier() {
958  return identifier;
959  }
960 
961  public String getDisplayName() {
962  return this.displayName;
963  }
964 
971  TskData.FileKnown getFileKnown() {
972  return this.fileKnown;
973  }
974 
982  static KnownFilesType fromFileKnown(TskData.FileKnown fileKnown) {
983  if (fileKnown == null) {
984  return null;
985  }
986 
987  return Stream.of(KnownFilesType.values())
988  .filter((type) -> type.getFileKnown() == fileKnown)
989  .findFirst()
990  .orElseThrow(() -> new IllegalArgumentException("Unknown TskData.FileKnown type: " + fileKnown));
991  }
992  }
993 
997  public enum Event {
998 
999  INDEXING_DONE
1000  }
1001 
1002  public abstract String getHashSetName();
1003 
1004  abstract String getDisplayName();
1005 
1006  public abstract String getDatabasePath() throws TskCoreException;
1007 
1008  public abstract HashDb.KnownFilesType getKnownFilesType();
1009 
1010  public abstract boolean getSearchDuringIngest();
1011 
1012  abstract void setSearchDuringIngest(boolean useForIngest);
1013 
1014  public abstract boolean getSendIngestMessages();
1015 
1016  abstract void setSendIngestMessages(boolean showInboxMessages);
1017 
1025  public abstract boolean isUpdateable() throws TskCoreException;
1026 
1035  public abstract void addHashes(Content content) throws TskCoreException;
1036 
1037  public abstract void addHashes(Content content, String comment) throws TskCoreException;
1038 
1039  public abstract void addHashes(List<HashEntry> hashes) throws TskCoreException;
1040 
1041  public abstract boolean lookupMD5Quick(Content content) throws TskCoreException;
1042 
1043  public abstract HashHitInfo lookupMD5(Content content) throws TskCoreException;
1044 
1053  abstract boolean isValid() throws TskCoreException;
1054 
1055  public abstract String getIndexPath() throws TskCoreException;
1056 
1057  public abstract boolean hasIndexOnly() throws TskCoreException;
1058 
1059  public abstract void firePropertyChange(String propertyName, Object oldValue, Object newValue);
1060 
1061  public abstract void addPropertyChangeListener(PropertyChangeListener pcl);
1062 
1063  public abstract void removePropertyChangeListener(PropertyChangeListener pcl);
1064 
1065  @Override
1066  public abstract String toString();
1067 
1068  }
1069 
1074  class SleuthkitHashSet extends HashDb {
1075 
1076  private static final long serialVersionUID = 1L;
1077  private final int handle;
1078  private final String hashSetName;
1079  private boolean searchDuringIngest;
1080  private boolean sendIngestMessages;
1081  private final HashDb.KnownFilesType knownFilesType;
1082  private boolean indexing;
1083  private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
1084  private final boolean officialSet;
1085 
1086  private SleuthkitHashSet(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) {
1087  this(handle, hashSetName, useForIngest, sendHitMessages, knownFilesType, false);
1088  }
1089 
1090  private SleuthkitHashSet(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType, boolean officialSet) {
1091  this.handle = handle;
1092  this.hashSetName = hashSetName;
1093  this.searchDuringIngest = useForIngest;
1094  this.sendIngestMessages = sendHitMessages;
1095  this.knownFilesType = knownFilesType;
1096  this.indexing = false;
1097  this.officialSet = officialSet;
1098  }
1099 
1106  @Override
1107  public void addPropertyChangeListener(PropertyChangeListener pcl) {
1108  propertyChangeSupport.addPropertyChangeListener(pcl);
1109  }
1110 
1116  @Override
1117  public void removePropertyChangeListener(PropertyChangeListener pcl) {
1118  propertyChangeSupport.removePropertyChangeListener(pcl);
1119  }
1120 
1121  int getHandle() {
1122  return handle;
1123  }
1124 
1125  @Override
1126  public String getHashSetName() {
1127  return hashSetName;
1128  }
1129 
1130  @Override
1131  String getDisplayName() {
1132  return getHashSetName();
1133  }
1134 
1135  @Override
1136  public String getDatabasePath() throws TskCoreException {
1137  return SleuthkitJNI.getHashDatabasePath(handle);
1138  }
1139 
1140  public void setIndexing(boolean indexing) {
1141  this.indexing = indexing;
1142  }
1143 
1144  @Override
1145  public String getIndexPath() throws TskCoreException {
1146  return SleuthkitJNI.getHashDatabaseIndexPath(handle);
1147  }
1148 
1149  @Override
1150  public KnownFilesType getKnownFilesType() {
1151  return knownFilesType;
1152  }
1153 
1154  @Override
1155  public boolean getSearchDuringIngest() {
1156  return searchDuringIngest;
1157  }
1158 
1159  @Override
1160  void setSearchDuringIngest(boolean useForIngest) {
1161  this.searchDuringIngest = useForIngest;
1162  }
1163 
1164  @Override
1165  public boolean getSendIngestMessages() {
1166  return sendIngestMessages;
1167  }
1168 
1169  @Override
1170  void setSendIngestMessages(boolean showInboxMessages) {
1171  this.sendIngestMessages = showInboxMessages;
1172  }
1173 
1181  @Override
1182  public boolean isUpdateable() throws TskCoreException {
1183  if (isOfficialSet()) {
1184  return false;
1185  }
1186 
1187  return SleuthkitJNI.isUpdateableHashDatabase(this.handle);
1188  }
1189 
1198  @Override
1199  public void addHashes(Content content) throws TskCoreException {
1200  addHashes(content, null);
1201  }
1202 
1213  @Override
1214  public void addHashes(Content content, String comment) throws TskCoreException {
1215  // This only works for AbstractFiles and MD5 hashes at present.
1216  assert content instanceof AbstractFile;
1217  officialSetCheck();
1218  if (content instanceof AbstractFile) {
1219  AbstractFile file = (AbstractFile) content;
1220  if (null != file.getMd5Hash()) {
1221  SleuthkitJNI.addToHashDatabase(null, file.getMd5Hash(), null, null, comment, handle);
1222  }
1223  }
1224  }
1225 
1231  private void officialSetCheck() throws TskCoreException {
1232  if (isOfficialSet()) {
1233  throw new TskCoreException("Hashes cannot be added to an official set");
1234  }
1235  }
1236 
1244  @Override
1245  public void addHashes(List<HashEntry> hashes) throws TskCoreException {
1246  officialSetCheck();
1247  SleuthkitJNI.addToHashDatabase(hashes, handle);
1248  }
1249 
1259  @Override
1260  public boolean lookupMD5Quick(Content content) throws TskCoreException {
1261  boolean result = false;
1262  assert content instanceof AbstractFile;
1263  if (content instanceof AbstractFile) {
1264  AbstractFile file = (AbstractFile) content;
1265  if (null != file.getMd5Hash()) {
1266  result = SleuthkitJNI.lookupInHashDatabase(file.getMd5Hash(), handle);
1267  }
1268  }
1269  return result;
1270  }
1271 
1281  @Override
1282  public HashHitInfo lookupMD5(Content content) throws TskCoreException {
1283  HashHitInfo result = null;
1284  // This only works for AbstractFiles and MD5 hashes at present.
1285  assert content instanceof AbstractFile;
1286  if (content instanceof AbstractFile) {
1287  AbstractFile file = (AbstractFile) content;
1288  if (null != file.getMd5Hash()) {
1289  result = SleuthkitJNI.lookupInHashDatabaseVerbose(file.getMd5Hash(), handle);
1290  }
1291  }
1292  return result;
1293  }
1294 
1303  @Override
1304  boolean isValid() throws TskCoreException {
1305  return hasIndex();
1306  }
1307 
1308  boolean hasIndex() throws TskCoreException {
1309  return SleuthkitJNI.hashDatabaseHasLookupIndex(handle);
1310  }
1311 
1312  @Override
1313  public boolean hasIndexOnly() throws TskCoreException {
1314  return SleuthkitJNI.hashDatabaseIsIndexOnly(handle);
1315  }
1316 
1317  boolean canBeReIndexed() throws TskCoreException {
1318  return SleuthkitJNI.hashDatabaseCanBeReindexed(handle);
1319  }
1320 
1321  boolean isIndexing() {
1322  return indexing;
1323  }
1324 
1325  @Override
1326  public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
1327  this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
1328  }
1329 
1330  private void close() throws TskCoreException {
1331  SleuthkitJNI.closeHashDatabase(handle);
1332  }
1333 
1334  @Override
1335  public String toString() {
1336  return getHashSetName();
1337  }
1338 
1339  @Override
1340  public int hashCode() {
1341  int code = 23;
1342  code = 47 * code + Integer.hashCode(handle);
1343  code = 47 * code + Objects.hashCode(this.hashSetName);
1344  code = 47 * code + Objects.hashCode(this.propertyChangeSupport);
1345  code = 47 * code + Objects.hashCode(this.knownFilesType);
1346  return code;
1347  }
1348 
1349  @Override
1350  public boolean equals(Object obj) {
1351  if (obj == null) {
1352  return false;
1353  }
1354  if (getClass() != obj.getClass()) {
1355  return false;
1356  }
1357  final SleuthkitHashSet other = (SleuthkitHashSet) obj;
1358  if (!Objects.equals(this.hashSetName, other.hashSetName)) {
1359  return false;
1360  }
1361  if (this.knownFilesType != other.knownFilesType) {
1362  return false;
1363  }
1364  return true;
1365  }
1366 
1373  boolean isOfficialSet() {
1374  return officialSet;
1375  }
1376  }
1377 
1382  class CentralRepoHashSet extends HashDb {
1383 
1384  private static final long serialVersionUID = 1L;
1385  private final String hashSetName;
1386  private boolean searchDuringIngest;
1387  private boolean sendIngestMessages;
1388  private final HashDb.KnownFilesType knownFilesType;
1389  private final int referenceSetID;
1390  private final String version;
1391  private String orgName;
1392  private final boolean readOnly;
1393  private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
1394 
1395  @Messages({"HashDbManager.CentralRepoHashDb.orgError=Error loading organization"})
1396  private CentralRepoHashSet(String hashSetName, String version, int referenceSetID,
1397  boolean useForIngest, boolean sendHitMessages, HashDb.KnownFilesType knownFilesType,
1398  boolean readOnly)
1399  throws TskCoreException {
1400  this.hashSetName = hashSetName;
1401  this.version = version;
1402  this.referenceSetID = referenceSetID;
1403  this.searchDuringIngest = useForIngest;
1404  this.sendIngestMessages = sendHitMessages;
1405  this.knownFilesType = knownFilesType;
1406  this.readOnly = readOnly;
1407 
1408  try {
1409  orgName = CentralRepository.getInstance().getReferenceSetOrganization(referenceSetID).getName();
1410  } catch (CentralRepoException ex) {
1411  Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error looking up central repository organization for reference set " + referenceSetID, ex); //NON-NLS
1412  orgName = Bundle.HashDbManager_CentralRepoHashDb_orgError();
1413  }
1414  }
1415 
1422  @Override
1423  public void addPropertyChangeListener(PropertyChangeListener pcl) {
1424  propertyChangeSupport.addPropertyChangeListener(pcl);
1425  }
1426 
1432  @Override
1433  public void removePropertyChangeListener(PropertyChangeListener pcl) {
1434  propertyChangeSupport.removePropertyChangeListener(pcl);
1435  }
1436 
1437  @Override
1438  public boolean hasIndexOnly() throws TskCoreException {
1439  return true;
1440  }
1441 
1442  @Override
1443  public String getHashSetName() {
1444  return hashSetName;
1445  }
1446 
1447  @Override
1448  public String getDisplayName() {
1449  if (!getVersion().isEmpty()) {
1450  return getHashSetName() + " " + getVersion() + " (remote)";
1451  } else {
1452  return getHashSetName() + " (remote)";
1453  }
1454  }
1455 
1456  String getVersion() {
1457  return version;
1458  }
1459 
1460  String getOrgName() {
1461  return orgName;
1462  }
1463 
1464  int getReferenceSetID() {
1465  return referenceSetID;
1466  }
1467 
1468  @Override
1469  public String getDatabasePath() throws TskCoreException {
1470  return "";
1471  }
1472 
1473  @Override
1474  public String getIndexPath() throws TskCoreException {
1475  return "";
1476  }
1477 
1478  @Override
1479  public HashDb.KnownFilesType getKnownFilesType() {
1480  return knownFilesType;
1481  }
1482 
1483  @Override
1484  public boolean getSearchDuringIngest() {
1485  return searchDuringIngest;
1486  }
1487 
1488  @Override
1489  void setSearchDuringIngest(boolean useForIngest) {
1490  this.searchDuringIngest = useForIngest;
1491  }
1492 
1493  @Override
1494  public boolean getSendIngestMessages() {
1495  return sendIngestMessages;
1496  }
1497 
1498  @Override
1499  void setSendIngestMessages(boolean showInboxMessages) {
1500  this.sendIngestMessages = showInboxMessages;
1501  }
1502 
1510  @Override
1511  public boolean isUpdateable() throws TskCoreException {
1512  return (!readOnly);
1513  }
1514 
1523  @Override
1524  public void addHashes(Content content) throws TskCoreException {
1525  addHashes(content, null);
1526  }
1527 
1538  @Override
1539  public void addHashes(Content content, String comment) throws TskCoreException {
1540  // This only works for AbstractFiles and MD5 hashes at present.
1541  assert content instanceof AbstractFile;
1542  if (content instanceof AbstractFile) {
1543  AbstractFile file = (AbstractFile) content;
1544  if (null != file.getMd5Hash()) {
1545  TskData.FileKnown type = knownFilesType.getFileKnown();
1546 
1547  try {
1548  CentralRepoFileInstance fileInstance = new CentralRepoFileInstance(referenceSetID, file.getMd5Hash(),
1549  type, comment);
1550  CentralRepository.getInstance().addReferenceInstance(fileInstance, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID));
1551  } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) {
1552  throw new TskCoreException("Error adding hashes to " + getDisplayName(), ex); //NON-NLS
1553  }
1554  }
1555  }
1556  }
1557 
1565  @Override
1566  public void addHashes(List<HashEntry> hashes) throws TskCoreException {
1567  Set<CentralRepoFileInstance> globalFileInstances = new HashSet<>();
1568  for (HashEntry hashEntry : hashes) {
1569  TskData.FileKnown type = knownFilesType.getFileKnown();
1570 
1571  try {
1572  globalFileInstances.add(new CentralRepoFileInstance(referenceSetID, hashEntry.getMd5Hash(), type, hashEntry.getComment()));
1573  } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) {
1574  throw new TskCoreException("Error adding hashes to " + getDisplayName(), ex);
1575  }
1576  }
1577 
1578  try {
1579  CentralRepository.getInstance().bulkInsertReferenceTypeEntries(globalFileInstances,
1580  CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID));
1581  } catch (CentralRepoException ex) {
1582  throw new TskCoreException("Error adding hashes to " + getDisplayName(), ex);
1583  }
1584  }
1585 
1595  @Override
1596  public boolean lookupMD5Quick(Content content) throws TskCoreException {
1597  // This only works for AbstractFiles and MD5 hashes
1598  assert content instanceof AbstractFile;
1599  if (content instanceof AbstractFile) {
1600  AbstractFile file = (AbstractFile) content;
1601  if (null != file.getMd5Hash()) {
1602  try {
1603  return CentralRepository.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID);
1604  } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) {
1605  Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup for hash "
1606  + file.getMd5Hash() + " in reference set " + referenceSetID, ex); //NON-NLS
1607  throw new TskCoreException("Error performing central reposiotry hash lookup", ex);
1608  }
1609  }
1610  }
1611  return false;
1612  }
1613 
1623  @Override
1624  public HashHitInfo lookupMD5(Content content) throws TskCoreException {
1625  HashHitInfo result = null;
1626  // This only works for AbstractFiles and MD5 hashes
1627  assert content instanceof AbstractFile;
1628  if (content instanceof AbstractFile) {
1629  AbstractFile file = (AbstractFile) content;
1630  if (null != file.getMd5Hash()) {
1631  try {
1632  return CentralRepository.getInstance().lookupHash(file.getMd5Hash(), referenceSetID);
1633  } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) {
1634  Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup for hash "
1635  + file.getMd5Hash() + " in reference set " + referenceSetID, ex); //NON-NLS
1636  throw new TskCoreException("Error performing central reposiotry hash lookup", ex);
1637  }
1638  }
1639  }
1640  return result;
1641  }
1642 
1648  @Override
1649  boolean isValid() {
1650  if (!CentralRepository.isEnabled()) {
1651  return false;
1652  }
1653  try {
1654  return CentralRepository.getInstance().referenceSetIsValid(this.referenceSetID, this.hashSetName, this.version);
1655  } catch (CentralRepoException ex) {
1656  Logger.getLogger(CentralRepoHashSet.class.getName()).log(Level.SEVERE, "Error validating hash set " + hashSetName, ex); //NON-NLS
1657  return false;
1658  }
1659  }
1660 
1661  @Override
1662  public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
1663  this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
1664  }
1665 
1666  @Override
1667  public String toString() {
1668  return getDisplayName();
1669  }
1670 
1671  @Override
1672  public int hashCode() {
1673  int code = 23;
1674  code = 47 * code + Objects.hashCode(this.hashSetName);
1675  code = 47 * code + Objects.hashCode(this.version);
1676  code = 47 * code + Integer.hashCode(this.referenceSetID);
1677  code = 47 * code + Objects.hashCode(this.knownFilesType);
1678  return code;
1679  }
1680 
1681  @Override
1682  public boolean equals(Object obj) {
1683  if (obj == null) {
1684  return false;
1685  }
1686  if (getClass() != obj.getClass()) {
1687  return false;
1688  }
1689  final CentralRepoHashSet other = (CentralRepoHashSet) obj;
1690  if (!Objects.equals(this.hashSetName, other.hashSetName)) {
1691  return false;
1692  }
1693  if (!Objects.equals(this.version, other.version)) {
1694  return false;
1695  }
1696  if (this.knownFilesType != other.knownFilesType) {
1697  return false;
1698  }
1699  return true;
1700  }
1701  }
1702 
1706  private class HashDbIndexer extends SwingWorker<Object, Void> {
1707 
1708  private ProgressHandle progress = null;
1709  private SleuthkitHashSet hashDb = null;
1710 
1711  HashDbIndexer(SleuthkitHashSet hashDb) {
1712  this.hashDb = hashDb;
1713  }
1714 
1715  @Override
1716  protected Object doInBackground() {
1717  hashDb.setIndexing(true);
1718  progress = ProgressHandle.createHandle(
1719  NbBundle.getMessage(this.getClass(), "HashDbManager.progress.indexingHashSet", hashDb.getHashSetName()));
1720  progress.start();
1721  progress.switchToIndeterminate();
1722  try {
1723  SleuthkitJNI.createLookupIndexForHashDatabase(hashDb.getHandle());
1724  } catch (TskCoreException ex) {
1725  Logger.getLogger(HashDbIndexer.class.getName()).log(Level.SEVERE, "Error indexing hash set " + hashDb.getHashSetName(), ex); //NON-NLS
1726  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
1727  NbBundle.getMessage(this.getClass(),
1728  "HashDbManager.dlgMsg.errorIndexingHashSet",
1729  hashDb.getHashSetName()),
1730  NbBundle.getMessage(this.getClass(), "HashDbManager.hashDbIndexingErr"),
1731  JOptionPane.ERROR_MESSAGE);
1732  }
1733  return null;
1734  }
1735 
1736  @Override
1737  protected void done() {
1738  hashDb.setIndexing(false);
1739  progress.finish();
1740 
1741  // see if we got any errors
1742  try {
1743  get();
1744  } catch (InterruptedException | ExecutionException ex) {
1745  logger.log(Level.SEVERE, "Error creating index", ex); //NON-NLS
1747  NbBundle.getMessage(this.getClass(), "HashDbManager.errCreatingIndex.title"),
1748  NbBundle.getMessage(this.getClass(), "HashDbManager.errCreatingIndex.msg", ex.getMessage()),
1750  } // catch and ignore if we were cancelled
1751  catch (java.util.concurrent.CancellationException ex) {
1752  }
1753 
1754  try {
1755  hashDb.firePropertyChange(SleuthkitHashSet.Event.INDEXING_DONE.toString(), null, hashDb);
1756  hashDb.firePropertyChange(HashDbManager.SetEvt.DB_INDEXED.toString(), null, hashDb.getHashSetName());
1757  } catch (Exception e) {
1758  logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS
1760  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErr"),
1761  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErrorListeningToUpdatesMsg"),
1763  }
1764  }
1765  }
1766 }
static synchronized IngestManager getInstance()
synchronized void addPropertyChangeListener(PropertyChangeListener listener)
void checkDbCollision(String path, String hashSetName)
List< CentralRepoFileSet > getAllReferenceSets(CorrelationAttributeInstance.Type correlationType)
static KnownFilesType fromFileKnown(TskData.FileKnown fileKnown)
List< HashDb > getUpdateableHashSets(List< HashDb > hashDbs)
synchronized HashDb addNewHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
void configureSettings(HashLookupSettings settings, Set< String > officialSetNames)
abstract void firePropertyChange(String propertyName, Object oldValue, Object newValue)
synchronized void removeHashDatabaseNoSave(HashDb hashDb)
String getValidFilePath(String hashSetName, String configuredPath)
synchronized HashDb addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
synchronized void removePropertyChangeListener(PropertyChangeListener listener)
void closeHashDatabases(List< HashDb > hashDatabases)
abstract void addPropertyChangeListener(PropertyChangeListener pcl)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static void show(String title, String message, MessageType type, ActionListener actionListener)
CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId)
KnownFilesType(String displayName, String identifier, TskData.FileKnown fileKnown, boolean allowSendInboxMessages, boolean defaultSendInboxMessages)
SleuthkitHashSet addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
abstract void removePropertyChangeListener(PropertyChangeListener pcl)
List< HashDbInfo > handleNameConflict(List< HashDbInfo > curHashsets, Set< String > officialNames)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Feb 6 2024
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.