Autopsy  4.9.1
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-2018 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.IOException;
26 import java.util.ArrayList;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Objects;
30 import java.util.Set;
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;
41 import org.openide.windows.WindowManager;
53 import org.sleuthkit.datamodel.AbstractFile;
54 import org.sleuthkit.datamodel.Content;
55 import org.sleuthkit.datamodel.HashEntry;
56 import org.sleuthkit.datamodel.HashHitInfo;
57 import org.sleuthkit.datamodel.SleuthkitJNI;
58 import org.sleuthkit.datamodel.TskCoreException;
59 import org.sleuthkit.datamodel.TskData;
60 
65 public class HashDbManager implements PropertyChangeListener {
66 
67  private static final String HASH_DATABASE_FILE_EXTENSON = "kdb"; //NON-NLS
68  private static HashDbManager instance = null;
69  private List<HashDb> hashSets = new ArrayList<>();
70  private Set<String> hashSetNames = new HashSet<>();
71  private Set<String> hashSetPaths = new HashSet<>();
72  PropertyChangeSupport changeSupport = new PropertyChangeSupport(HashDbManager.class);
73  private static final Logger logger = Logger.getLogger(HashDbManager.class.getName());
74  private boolean allDatabasesLoadedCorrectly = false;
75 
81  public enum SetEvt {
82 
83  DB_ADDED, DB_DELETED, DB_INDEXED
84  };
85 
91  public static synchronized HashDbManager getInstance() {
92  if (instance == null) {
93  instance = new HashDbManager();
94  }
95  return instance;
96  }
97 
98  public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
99  changeSupport.addPropertyChangeListener(listener);
100  }
101 
102  public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
103  changeSupport.removePropertyChangeListener(listener);
104  }
105 
106  synchronized boolean verifyAllDatabasesLoadedCorrectly(){
108  }
109 
110  private HashDbManager() {
112  }
113 
119  static String getHashDatabaseFileExtension() {
121  }
122 
123  public class HashDbManagerException extends Exception {
124 
125  private static final long serialVersionUID = 1L;
126 
127  private HashDbManagerException(String message) {
128  super(message);
129  }
130 
131  private HashDbManagerException(String message, Throwable exception) {
132  super(message, exception);
133  }
134  }
135 
155  public synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException {
156  HashDb hashDb = null;
157  hashDb = this.addExistingHashDatabaseNoSave(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType);
158  this.save();
159  return hashDb;
160  }
161 
162  synchronized HashDb addExistingHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException {
163  HashDb hashDb = null;
164  try {
165  if (!new File(path).exists()) {
166  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.hashDbDoesNotExistExceptionMsg", path));
167  }
168 
169  if (hashSetPaths.contains(path)) {
170  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.hashDbAlreadyAddedExceptionMsg", path));
171  }
172 
173  if (hashSetNames.contains(hashSetName)) {
174  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName));
175  }
176 
177  hashDb = addHashDatabase(SleuthkitJNI.openHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
178  } catch (TskCoreException ex) {
179  throw new HashDbManagerException(ex.getMessage());
180  }
181  return hashDb;
182  }
183 
202  public synchronized HashDb addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages,
203  HashDb.KnownFilesType knownFilesType) throws HashDbManagerException {
204 
205  HashDb hashDb = null;
206  hashDb = this.addNewHashDatabaseNoSave(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType);
207 
208  this.save();
209 
210  return hashDb;
211  }
212 
213  public synchronized HashDb addNewHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages,
214  HashDb.KnownFilesType knownFilesType) throws HashDbManagerException {
215  HashDb hashDb = null;
216  try {
217  File file = new File(path);
218  if (file.exists()) {
219  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.hashDbFileExistsExceptionMsg", path));
220  }
221  if (!FilenameUtils.getExtension(file.getName()).equalsIgnoreCase(HASH_DATABASE_FILE_EXTENSON)) {
222  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.illegalHashDbFileNameExtensionMsg",
223  getHashDatabaseFileExtension()));
224  }
225 
226  if (hashSetPaths.contains(path)) {
227  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.hashDbAlreadyAddedExceptionMsg", path));
228  }
229 
230  if (hashSetNames.contains(hashSetName)) {
231  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName));
232  }
233 
234  hashDb = addHashDatabase(SleuthkitJNI.createHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
235  } catch (TskCoreException ex) {
236  throw new HashDbManagerException(ex.getMessage());
237  }
238  return hashDb;
239  }
240 
241  private SleuthkitHashSet addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws TskCoreException {
242  // Wrap an object around the handle.
243  SleuthkitHashSet hashDb = new SleuthkitHashSet(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
244 
245  // Get the indentity data before updating the collections since the
246  // accessor methods may throw.
247  String databasePath = hashDb.getDatabasePath();
248  String indexPath = hashDb.getIndexPath();
249 
250  // Update the collections used to ensure that hash set names are unique
251  // and the same database is not added to the configuration more than once.
252  hashSetNames.add(hashDb.getHashSetName());
253  if (!databasePath.equals("None")) { //NON-NLS
254  hashSetPaths.add(databasePath);
255  }
256  if (!indexPath.equals("None")) { //NON-NLS
257  hashSetPaths.add(indexPath);
258  }
259 
260  // Add the hash database to the collection
261  hashSets.add(hashDb);
262 
263  // Let any external listeners know that there's a new set
264  try {
265  changeSupport.firePropertyChange(SetEvt.DB_ADDED.toString(), null, hashSetName);
266  } catch (Exception e) {
267  logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS
269  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErr"),
270  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErrorListeningToUpdatesMsg"),
272  }
273  return hashDb;
274  }
275 
276  CentralRepoHashSet addExistingCentralRepoHashSet(String hashSetName, String version, int referenceSetID,
277  boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType,
278  boolean readOnly) throws TskCoreException{
279 
280  if(! EamDb.isEnabled()){
281  throw new TskCoreException("Could not load central repository hash set " + hashSetName + " - central repository is not enabled");
282  }
283 
284  CentralRepoHashSet db = new CentralRepoHashSet(hashSetName, version, referenceSetID, searchDuringIngest,
285  sendIngestMessages, knownFilesType, readOnly);
286 
287  if(! db.isValid()){
288  throw new TskCoreException("Error finding hash set " + hashSetName + " in central repository");
289  }
290 
291  // Add the hash database to the collection
292  hashSets.add(db);
293 
294  // Let any external listeners know that there's a new set
295  try {
296  changeSupport.firePropertyChange(SetEvt.DB_ADDED.toString(), null, hashSetName);
297  } catch (Exception e) {
298  logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS
299  MessageNotifyUtil.Notify.show(
300  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErr"),
301  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErrorListeningToUpdatesMsg"),
302  MessageNotifyUtil.MessageType.ERROR);
303  }
304  return db;
305 
306  }
307 
308  synchronized void indexHashDatabase(SleuthkitHashSet hashDb) {
309  hashDb.addPropertyChangeListener(this);
310  HashDbIndexer creator = new HashDbIndexer(hashDb);
311  creator.execute();
312  }
313 
314  @Override
315  public void propertyChange(PropertyChangeEvent event) {
316  if (event.getPropertyName().equals(SleuthkitHashSet.Event.INDEXING_DONE.name())) {
317  SleuthkitHashSet hashDb = (SleuthkitHashSet) event.getNewValue();
318  if (null != hashDb) {
319  try {
320  String indexPath = hashDb.getIndexPath();
321  if (!indexPath.equals("None")) { //NON-NLS
322  hashSetPaths.add(indexPath);
323  }
324  } catch (TskCoreException ex) {
325  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDb.getHashSetName() + " hash set after indexing", ex); //NON-NLS
326  }
327  }
328  }
329  }
330 
339  public synchronized void removeHashDatabase(HashDb hashDb) throws HashDbManagerException {
340  this.removeHashDatabaseNoSave(hashDb);
341  this.save();
342  }
343 
344  public synchronized void removeHashDatabaseNoSave(HashDb hashDb) throws HashDbManagerException {
345  // Don't remove a database if ingest is running
346  boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning();
347  if (ingestIsRunning) {
348  throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.ingestRunningExceptionMsg"));
349  }
350  // Remove the database from whichever hash set list it occupies,
351  // and remove its hash set name from the hash set used to ensure unique
352  // hash set names are used, before undertaking These operations will succeed and constitute
353  // a mostly effective removal, even if the subsequent operations fail.
354  String hashSetName = hashDb.getHashSetName();
355  hashSetNames.remove(hashSetName);
356  hashSets.remove(hashDb);
357 
358  // Now undertake the operations that could throw.
359 
360  // Indexing is only relevanet for sleuthkit hashsets
361  if(hashDb instanceof SleuthkitHashSet){
362  SleuthkitHashSet hashDatabase = (SleuthkitHashSet)hashDb;
363  try {
364  if(hashDatabase.hasIndex()){
365  hashSetPaths.remove(hashDatabase.getIndexPath());
366  }
367  } catch (TskCoreException ex) {
368  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
369  }
370 
371  try {
372  if (!hashDatabase.hasIndexOnly()) {
373  hashSetPaths.remove(hashDatabase.getDatabasePath());
374  }
375  } catch (TskCoreException ex) {
376  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
377  }
378 
379  try {
380  hashDatabase.close();
381  } catch (TskCoreException ex) {
382  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + hashDb.getHashSetName() + " hash set when removing the hash set", ex); //NON-NLS
383  }
384  }
385 
386  // Let any external listeners know that a set has been deleted
387  try {
388  changeSupport.firePropertyChange(SetEvt.DB_DELETED.toString(), null, hashSetName);
389  } catch (Exception e) {
390  logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS
392  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErr"),
393  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErrorListeningToUpdatesMsg"),
395  }
396  }
397 
398  void save() throws HashDbManagerException {
399  try {
400  if (!HashLookupSettings.writeSettings(new HashLookupSettings(HashLookupSettings.convertHashSetList(this.hashSets)))) {
401  throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.saveErrorExceptionMsg"));
402  }
403  } catch (HashLookupSettings.HashLookupSettingsException ex) {
404  throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.saveErrorExceptionMsg"));
405  }
406  }
407 
415  public synchronized List<HashDb> getAllHashSets() {
416  try{
418  } catch (TskCoreException ex){
419  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS
420  }
421 
422  List<HashDb> hashDbs = new ArrayList<>();
423  hashDbs.addAll(this.hashSets);
424  return hashDbs;
425  }
426 
432  public synchronized List<HashDb> getKnownFileHashSets() {
433  List<HashDb> hashDbs = new ArrayList<>();
434  try{
436  } catch (TskCoreException ex){
437  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS
438  }
439  this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN)).forEach((db) -> {
440  hashDbs.add(db);
441  });
442  return hashDbs;
443  }
444 
450  public synchronized List<HashDb> getKnownBadFileHashSets() {
451  List<HashDb> hashDbs = new ArrayList<>();
452  try{
454  } catch (TskCoreException ex){
455  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS
456  }
457  this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN_BAD)).forEach((db) -> {
458  hashDbs.add(db);
459  });
460  return hashDbs;
461  }
462 
468  public synchronized List<HashDb> getUpdateableHashSets() {
469  return getUpdateableHashSets(this.hashSets);
470  }
471 
472  private List<HashDb> getUpdateableHashSets(List<HashDb> hashDbs) {
473  ArrayList<HashDb> updateableDbs = new ArrayList<>();
474  try{
476  } catch (TskCoreException ex){
477  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS
478  }
479  for (HashDb db : hashDbs) {
480  try {
481  if (db.isUpdateable()) {
482  updateableDbs.add(db);
483  }
484  } catch (TskCoreException ex) {
485  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error checking updateable status of " + db.getHashSetName() + " hash set", ex); //NON-NLS
486  }
487  }
488  return updateableDbs;
489  }
490 
491  private List<HashDbInfo> getCentralRepoHashSetsFromDatabase(){
492  List<HashDbInfo> crHashSets = new ArrayList<>();
493  if(EamDb.isEnabled()){
494  try{
496  for(EamGlobalSet globalSet:crSets){
497 
498  // Defaults for fields not stored in the central repository:
499  // searchDuringIngest: false
500  // sendIngestMessages: true if the hash set is notable
501  boolean sendIngestMessages = convertFileKnown(globalSet.getFileKnownStatus()).equals(HashDb.KnownFilesType.KNOWN_BAD);
502  crHashSets.add(new HashDbInfo(globalSet.getSetName(), globalSet.getVersion(),
503  globalSet.getGlobalSetID(), convertFileKnown(globalSet.getFileKnownStatus()), globalSet.isReadOnly(), false, sendIngestMessages));
504  }
505  } catch (EamDbException ex){
506  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS
507  }
508  }
509  return crHashSets;
510  }
511 
512  private static HashDb.KnownFilesType convertFileKnown(TskData.FileKnown fileKnown){
513  if(fileKnown.equals(TskData.FileKnown.BAD)){
515  }
516  return HashDb.KnownFilesType.KNOWN;
517  }
518 
523  public synchronized void loadLastSavedConfiguration() {
524  closeHashDatabases(this.hashSets);
525  hashSetNames.clear();
526  hashSetPaths.clear();
527 
529  }
530 
531  private void closeHashDatabases(List<HashDb> hashDatabases) {
532  for (HashDb database : hashDatabases) {
533  if(database instanceof SleuthkitHashSet){
534  try {
535  ((SleuthkitHashSet)database).close();
536  } catch (TskCoreException ex) {
537  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + database.getHashSetName() + " hash set", ex); //NON-NLS
538  }
539  }
540  }
541  hashDatabases.clear();
542  }
543 
544  private void loadHashsetsConfiguration() {
545  try {
546  HashLookupSettings settings = HashLookupSettings.readSettings();
547  this.configureSettings(settings);
548  } catch (HashLookupSettings.HashLookupSettingsException ex) {
549  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Could not read Hash lookup settings from disk.", ex);
550  }
551  }
552 
559  @Messages({"# {0} - hash set name", "HashDbManager.noDbPath.message=Couldn't get valid hash set path for: {0}",
560  "HashDbManager.centralRepoLoadError.message=Error loading central repository hash sets"})
561  private void configureSettings(HashLookupSettings settings) {
562  allDatabasesLoadedCorrectly = true;
563  List<HashDbInfo> hashDbInfoList = settings.getHashDbInfo();
564  for (HashDbInfo hashDbInfo : hashDbInfoList) {
565  try {
566  if(hashDbInfo.isFileDatabaseType()){
567  String dbPath = this.getValidFilePath(hashDbInfo.getHashSetName(), hashDbInfo.getPath());
568  if (dbPath != null) {
569  addHashDatabase(SleuthkitJNI.openHashDatabase(dbPath), hashDbInfo.getHashSetName(), hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType());
570  } else {
571  logger.log(Level.WARNING, Bundle.HashDbManager_noDbPath_message(hashDbInfo.getHashSetName()));
572  allDatabasesLoadedCorrectly = false;
573  }
574  } else {
575  if(EamDb.isEnabled()){
576  addExistingCentralRepoHashSet(hashDbInfo.getHashSetName(), hashDbInfo.getVersion(),
577  hashDbInfo.getReferenceSetID(),
578  hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(),
579  hashDbInfo.getKnownFilesType(), hashDbInfo.isReadOnly());
580  }
581  }
582  } catch (TskCoreException ex) {
583  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash set", ex); //NON-NLS
584  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
585  NbBundle.getMessage(this.getClass(),
586  "HashDbManager.unableToOpenHashDbMsg", hashDbInfo.getHashSetName()),
587  NbBundle.getMessage(this.getClass(), "HashDbManager.openHashDbErr"),
588  JOptionPane.ERROR_MESSAGE);
589  allDatabasesLoadedCorrectly = false;
590  }
591  }
592 
593  if(EamDb.isEnabled()){
594  try{
596  } catch (TskCoreException ex){
597  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash set", ex); //NON-NLS
598 
599  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
600  Bundle.HashDbManager_centralRepoLoadError_message(),
601  NbBundle.getMessage(this.getClass(), "HashDbManager.openHashDbErr"),
602  JOptionPane.ERROR_MESSAGE);
603  allDatabasesLoadedCorrectly = false;
604  }
605  }
606 
607  /* NOTE: When RuntimeProperties.coreComponentsAreActive() is "false",
608  I don't think we should overwrite hash db settings file because we
609  were unable to load a database. The user should have to fix the issue or
610  remove the database from settings. Overwiting the settings effectively removes
611  the database from HashLookupSettings and the user may not know about this
612  because the dialogs are not being displayed. The next time user starts Autopsy, HashDB
613  will load without errors and the user may think that the problem was solved.*/
614  if (!allDatabasesLoadedCorrectly && RuntimeProperties.runningWithGUI()) {
615  try {
616  HashLookupSettings.writeSettings(new HashLookupSettings(HashLookupSettings.convertHashSetList(this.hashSets)));
617  allDatabasesLoadedCorrectly = true;
618  } catch (HashLookupSettings.HashLookupSettingsException ex) {
619  allDatabasesLoadedCorrectly = false;
620  logger.log(Level.SEVERE, "Could not overwrite hash set settings.", ex);
621  }
622  }
623  }
624 
625  private void updateHashSetsFromCentralRepository() throws TskCoreException {
626  if(EamDb.isEnabled()){
627  List<HashDbInfo> crHashDbInfoList = getCentralRepoHashSetsFromDatabase();
628  for(HashDbInfo hashDbInfo : crHashDbInfoList) {
629  if(hashDbInfoIsNew(hashDbInfo)){
630  addExistingCentralRepoHashSet(hashDbInfo.getHashSetName(), hashDbInfo.getVersion(),
631  hashDbInfo.getReferenceSetID(),
632  hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType(),
633  hashDbInfo.isReadOnly());
634  }
635  }
636  }
637  }
638 
639  private boolean hashDbInfoIsNew(HashDbInfo dbInfo){
640  for(HashDb db:this.hashSets){
641  if(dbInfo.matches(db)){
642  return false;
643  }
644  }
645  return true;
646  }
647 
648  private String getValidFilePath(String hashSetName, String configuredPath) {
649  // Check the configured path.
650  File database = new File(configuredPath);
651  if (database.exists()) {
652  return configuredPath;
653  }
654 
655  // Give the user an opportunity to find the desired file.
656  String newPath = null;
658  JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(),
659  NbBundle.getMessage(this.getClass(), "HashDbManager.dlgMsg.dbNotFoundAtLoc",
660  hashSetName, configuredPath),
661  NbBundle.getMessage(this.getClass(), "HashDbManager.dlgTitle.MissingDb"),
662  JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
663  newPath = searchForFile();
664  if (null != newPath && !newPath.isEmpty()) {
665  database = new File(newPath);
666  if (!database.exists()) {
667  newPath = null;
668  }
669  }
670  }
671  return newPath;
672  }
673 
674  private String searchForFile() {
675  String filePath = null;
676  JFileChooser fc = new JFileChooser();
677  fc.setDragEnabled(false);
678  fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
679  String[] EXTENSION = new String[]{"txt", "idx", "hash", "Hash", "kdb"}; //NON-NLS
680  FileNameExtensionFilter filter = new FileNameExtensionFilter(
681  NbBundle.getMessage(this.getClass(), "HashDbManager.fileNameExtensionFilter.title"), EXTENSION);
682  fc.setFileFilter(filter);
683  fc.setMultiSelectionEnabled(false);
684  if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
685  File f = fc.getSelectedFile();
686  try {
687  filePath = f.getCanonicalPath();
688  } catch (IOException ex) {
689  Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, "Couldn't get selected file path", ex); //NON-NLS
690  }
691  }
692  return filePath;
693  }
694 
695  public static abstract class HashDb {
696 
701  public enum KnownFilesType {
702 
703  KNOWN(NbBundle.getMessage(HashDbManager.class, "HashDbManager.known.text")),
704  KNOWN_BAD(NbBundle.getMessage(HashDbManager.class, "HashDbManager.knownBad.text"));
705  private final String displayName;
706 
707  private KnownFilesType(String displayName) {
708  this.displayName = displayName;
709  }
710 
711  public String getDisplayName() {
712  return this.displayName;
713  }
714  }
715 
719  public enum Event {
720 
721  INDEXING_DONE
722  }
723 
724  public abstract String getHashSetName();
725 
726  abstract String getDisplayName();
727 
728  public abstract String getDatabasePath() throws TskCoreException;
729 
730  public abstract HashDb.KnownFilesType getKnownFilesType();
731 
732  public abstract boolean getSearchDuringIngest();
733 
734  abstract void setSearchDuringIngest(boolean useForIngest);
735 
736  public abstract boolean getSendIngestMessages();
737 
738  abstract void setSendIngestMessages(boolean showInboxMessages);
739 
747  public abstract boolean isUpdateable() throws TskCoreException;
748 
757  public abstract void addHashes(Content content) throws TskCoreException;
758 
759  public abstract void addHashes(Content content, String comment) throws TskCoreException;
760 
761  public abstract void addHashes(List<HashEntry> hashes) throws TskCoreException;
762 
763  public abstract boolean lookupMD5Quick(Content content) throws TskCoreException;
764 
765  public abstract HashHitInfo lookupMD5(Content content) throws TskCoreException;
766 
773  abstract boolean isValid() throws TskCoreException;
774 
775  public abstract String getIndexPath() throws TskCoreException;
776 
777  public abstract boolean hasIndexOnly() throws TskCoreException;
778 
779  public abstract void firePropertyChange(String propertyName, Object oldValue, Object newValue);
780 
781  public abstract void addPropertyChangeListener(PropertyChangeListener pcl);
782 
783  public abstract void removePropertyChangeListener(PropertyChangeListener pcl);
784 
785  @Override
786  public abstract String toString();
787 
788  }
789 
794  class SleuthkitHashSet extends HashDb{
795 
796  private static final long serialVersionUID = 1L;
797  private final int handle;
798  private final String hashSetName;
799  private boolean searchDuringIngest;
800  private boolean sendIngestMessages;
801  private final HashDb.KnownFilesType knownFilesType;
802  private boolean indexing;
803  private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
804 
805  private SleuthkitHashSet(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) {
806  this.handle = handle;
807  this.hashSetName = hashSetName;
808  this.searchDuringIngest = useForIngest;
809  this.sendIngestMessages = sendHitMessages;
810  this.knownFilesType = knownFilesType;
811  this.indexing = false;
812  }
813 
820  @Override
821  public void addPropertyChangeListener(PropertyChangeListener pcl) {
822  propertyChangeSupport.addPropertyChangeListener(pcl);
823  }
824 
830  @Override
831  public void removePropertyChangeListener(PropertyChangeListener pcl) {
832  propertyChangeSupport.removePropertyChangeListener(pcl);
833  }
834 
835  int getHandle(){
836  return handle;
837  }
838 
839  @Override
840  public String getHashSetName() {
841  return hashSetName;
842  }
843 
844  @Override
845  String getDisplayName(){
846  return getHashSetName();
847  }
848 
849  @Override
850  public String getDatabasePath() throws TskCoreException {
851  return SleuthkitJNI.getHashDatabasePath(handle);
852  }
853 
854  public void setIndexing(boolean indexing){
855  this.indexing = indexing;
856  }
857 
858  @Override
859  public String getIndexPath() throws TskCoreException {
860  return SleuthkitJNI.getHashDatabaseIndexPath(handle);
861  }
862 
863  @Override
864  public KnownFilesType getKnownFilesType() {
865  return knownFilesType;
866  }
867 
868  @Override
869  public boolean getSearchDuringIngest() {
870  return searchDuringIngest;
871  }
872 
873  @Override
874  void setSearchDuringIngest(boolean useForIngest) {
875  this.searchDuringIngest = useForIngest;
876  }
877 
878  @Override
879  public boolean getSendIngestMessages() {
880  return sendIngestMessages;
881  }
882 
883  @Override
884  void setSendIngestMessages(boolean showInboxMessages) {
885  this.sendIngestMessages = showInboxMessages;
886  }
887 
895  @Override
896  public boolean isUpdateable() throws TskCoreException {
897  return SleuthkitJNI.isUpdateableHashDatabase(this.handle);
898  }
899 
908  @Override
909  public void addHashes(Content content) throws TskCoreException {
910  addHashes(content, null);
911  }
912 
923  @Override
924  public void addHashes(Content content, String comment) throws TskCoreException {
925  // This only works for AbstractFiles and MD5 hashes at present.
926  assert content instanceof AbstractFile;
927  if (content instanceof AbstractFile) {
928  AbstractFile file = (AbstractFile) content;
929  if (null != file.getMd5Hash()) {
930  SleuthkitJNI.addToHashDatabase(null, file.getMd5Hash(), null, null, comment, handle);
931  }
932  }
933  }
934 
942  @Override
943  public void addHashes(List<HashEntry> hashes) throws TskCoreException {
944  SleuthkitJNI.addToHashDatabase(hashes, handle);
945  }
946 
956  @Override
957  public boolean lookupMD5Quick(Content content) throws TskCoreException {
958  boolean result = false;
959  assert content instanceof AbstractFile;
960  if (content instanceof AbstractFile) {
961  AbstractFile file = (AbstractFile) content;
962  if (null != file.getMd5Hash()) {
963  result = SleuthkitJNI.lookupInHashDatabase(file.getMd5Hash(), handle);
964  }
965  }
966  return result;
967  }
968 
978  @Override
979  public HashHitInfo lookupMD5(Content content) throws TskCoreException {
980  HashHitInfo result = null;
981  // This only works for AbstractFiles and MD5 hashes at present.
982  assert content instanceof AbstractFile;
983  if (content instanceof AbstractFile) {
984  AbstractFile file = (AbstractFile) content;
985  if (null != file.getMd5Hash()) {
986  result = SleuthkitJNI.lookupInHashDatabaseVerbose(file.getMd5Hash(), handle);
987  }
988  }
989  return result;
990  }
991 
998  @Override
999  boolean isValid() throws TskCoreException {
1000  return hasIndex();
1001  }
1002 
1003  boolean hasIndex() throws TskCoreException {
1004  return SleuthkitJNI.hashDatabaseHasLookupIndex(handle);
1005  }
1006 
1007  @Override
1008  public boolean hasIndexOnly() throws TskCoreException {
1009  return SleuthkitJNI.hashDatabaseIsIndexOnly(handle);
1010  }
1011 
1012  boolean canBeReIndexed() throws TskCoreException {
1013  return SleuthkitJNI.hashDatabaseCanBeReindexed(handle);
1014  }
1015 
1016  boolean isIndexing() {
1017  return indexing;
1018  }
1019 
1020  @Override
1021  public void firePropertyChange(String propertyName, Object oldValue, Object newValue){
1022  this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
1023  }
1024 
1025  private void close() throws TskCoreException {
1026  SleuthkitJNI.closeHashDatabase(handle);
1027  }
1028 
1029  @Override
1030  public String toString(){
1031  return getHashSetName();
1032  }
1033 
1034 
1035  @Override
1036  public int hashCode() {
1037  int code = 23;
1038  code = 47 * code + Integer.hashCode(handle);
1039  code = 47 * code + Objects.hashCode(this.hashSetName);
1040  code = 47 * code + Objects.hashCode(this.propertyChangeSupport);
1041  code = 47 * code + Objects.hashCode(this.knownFilesType);
1042  return code;
1043  }
1044 
1045  @Override
1046  public boolean equals(Object obj) {
1047  if (obj == null) {
1048  return false;
1049  }
1050  if (getClass() != obj.getClass()) {
1051  return false;
1052  }
1053  final SleuthkitHashSet other = (SleuthkitHashSet) obj;
1054  if (!Objects.equals(this.hashSetName, other.hashSetName)) {
1055  return false;
1056  }
1057  if (this.knownFilesType != other.knownFilesType) {
1058  return false;
1059  }
1060  return true;
1061  }
1062  }
1063 
1068  class CentralRepoHashSet extends HashDb{
1069 
1070  private static final long serialVersionUID = 1L;
1071  private final String hashSetName;
1072  private boolean searchDuringIngest;
1073  private boolean sendIngestMessages;
1074  private final HashDb.KnownFilesType knownFilesType;
1075  private final int referenceSetID;
1076  private final String version;
1077  private String orgName;
1078  private final boolean readOnly;
1079  private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
1080 
1081  @Messages({"HashDbManager.CentralRepoHashDb.orgError=Error loading organization"})
1082  private CentralRepoHashSet(String hashSetName, String version, int referenceSetID,
1083  boolean useForIngest, boolean sendHitMessages, HashDb.KnownFilesType knownFilesType,
1084  boolean readOnly)
1085  throws TskCoreException{
1086  this.hashSetName = hashSetName;
1087  this.version = version;
1088  this.referenceSetID = referenceSetID;
1089  this.searchDuringIngest = useForIngest;
1090  this.sendIngestMessages = sendHitMessages;
1091  this.knownFilesType = knownFilesType;
1092  this.readOnly = readOnly;
1093 
1094  try{
1095  orgName = EamDb.getInstance().getReferenceSetOrganization(referenceSetID).getName();
1096  } catch (EamDbException ex){
1097  Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error looking up central repository organization for reference set " + referenceSetID, ex); //NON-NLS
1098  orgName = Bundle.HashDbManager_CentralRepoHashDb_orgError();
1099  }
1100  }
1101 
1108  @Override
1109  public void addPropertyChangeListener(PropertyChangeListener pcl) {
1110  propertyChangeSupport.addPropertyChangeListener(pcl);
1111  }
1112 
1118  @Override
1119  public void removePropertyChangeListener(PropertyChangeListener pcl) {
1120  propertyChangeSupport.removePropertyChangeListener(pcl);
1121  }
1122 
1123  @Override
1124  public boolean hasIndexOnly() throws TskCoreException{
1125  return true;
1126  }
1127 
1128  @Override
1129  public String getHashSetName() {
1130  return hashSetName;
1131  }
1132 
1133  @Override
1134  public String getDisplayName(){
1135  if(! getVersion().isEmpty()){
1136  return getHashSetName() + " " + getVersion() + " (remote)";
1137  } else {
1138  return getHashSetName() + " (remote)";
1139  }
1140  }
1141 
1142  String getVersion(){
1143  return version;
1144  }
1145 
1146  String getOrgName(){
1147  return orgName;
1148  }
1149 
1150  int getReferenceSetID(){
1151  return referenceSetID;
1152  }
1153 
1154  @Override
1155  public String getDatabasePath() throws TskCoreException {
1156  return "";
1157  }
1158 
1159  @Override
1160  public String getIndexPath() throws TskCoreException {
1161  return "";
1162  }
1163 
1164  @Override
1165  public HashDb.KnownFilesType getKnownFilesType() {
1166  return knownFilesType;
1167  }
1168 
1169  @Override
1170  public boolean getSearchDuringIngest() {
1171  return searchDuringIngest;
1172  }
1173 
1174  @Override
1175  void setSearchDuringIngest(boolean useForIngest) {
1176  this.searchDuringIngest = useForIngest;
1177  }
1178 
1179  @Override
1180  public boolean getSendIngestMessages() {
1181  return sendIngestMessages;
1182  }
1183 
1184  @Override
1185  void setSendIngestMessages(boolean showInboxMessages) {
1186  this.sendIngestMessages = showInboxMessages;
1187  }
1188 
1196  @Override
1197  public boolean isUpdateable() throws TskCoreException {
1198  return (! readOnly);
1199  }
1200 
1209  @Override
1210  public void addHashes(Content content) throws TskCoreException {
1211  addHashes(content, null);
1212  }
1213 
1224  @Override
1225  public void addHashes(Content content, String comment) throws TskCoreException {
1226  // This only works for AbstractFiles and MD5 hashes at present.
1227  assert content instanceof AbstractFile;
1228  if (content instanceof AbstractFile) {
1229  AbstractFile file = (AbstractFile) content;
1230  if (null != file.getMd5Hash()) {
1231  TskData.FileKnown type;
1232  if(knownFilesType.equals(HashDb.KnownFilesType.KNOWN_BAD)){
1233  type = TskData.FileKnown.BAD;
1234  } else {
1235  type = TskData.FileKnown.KNOWN;
1236  }
1237 
1238  try{
1239  EamGlobalFileInstance fileInstance = new EamGlobalFileInstance(referenceSetID, file.getMd5Hash(),
1240  type, comment);
1241  EamDb.getInstance().addReferenceInstance(fileInstance,EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID));
1242  } catch (EamDbException | CorrelationAttributeNormalizationException ex){
1243  throw new TskCoreException("Error adding hashes to " + getDisplayName(), ex); //NON-NLS
1244  }
1245  }
1246  }
1247  }
1248 
1256  @Override
1257  public void addHashes(List<HashEntry> hashes) throws TskCoreException {
1258  Set<EamGlobalFileInstance> globalFileInstances = new HashSet<>();
1259  for(HashEntry hashEntry:hashes){
1260  TskData.FileKnown type;
1261  if(knownFilesType.equals(HashDb.KnownFilesType.KNOWN_BAD)){
1262  type = TskData.FileKnown.BAD;
1263  } else {
1264  type = TskData.FileKnown.KNOWN;
1265  }
1266  try {
1267  globalFileInstances.add(new EamGlobalFileInstance(referenceSetID, hashEntry.getMd5Hash(), type, hashEntry.getComment()));
1268  } catch (EamDbException | CorrelationAttributeNormalizationException ex){
1269  throw new TskCoreException("Error adding hashes to " + getDisplayName(), ex);
1270  }
1271  }
1272 
1273  try{
1274  EamDb.getInstance().bulkInsertReferenceTypeEntries(globalFileInstances,
1275  EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID));
1276  } catch (EamDbException ex){
1277  throw new TskCoreException("Error adding hashes to " + getDisplayName(), ex);
1278  }
1279  }
1280 
1290  @Override
1291  public boolean lookupMD5Quick(Content content) throws TskCoreException {
1292  // This only works for AbstractFiles and MD5 hashes
1293  assert content instanceof AbstractFile;
1294  if (content instanceof AbstractFile) {
1295  AbstractFile file = (AbstractFile) content;
1296  if (null != file.getMd5Hash()) {
1297  try{
1298  return EamDb.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID);
1299  } catch (EamDbException | CorrelationAttributeNormalizationException ex){
1300  Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup for hash "
1301  + file.getMd5Hash() + " in reference set " + referenceSetID, ex); //NON-NLS
1302  throw new TskCoreException("Error performing central reposiotry hash lookup", ex);
1303  }
1304  }
1305  }
1306  return false;
1307  }
1308 
1318  @Override
1319  public HashHitInfo lookupMD5(Content content) throws TskCoreException {
1320  HashHitInfo result = null;
1321  // This only works for AbstractFiles and MD5 hashes
1322  assert content instanceof AbstractFile;
1323  if (content instanceof AbstractFile) {
1324  AbstractFile file = (AbstractFile) content;
1325  if (null != file.getMd5Hash()) {
1326  try{
1327  if(EamDb.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID)){
1328  // Make a bare-bones HashHitInfo for now
1329  result = new HashHitInfo(file.getMd5Hash(), "", "");
1330  }
1331  } catch (EamDbException | CorrelationAttributeNormalizationException ex){
1332  Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup for hash "
1333  + file.getMd5Hash() + " in reference set " + referenceSetID, ex); //NON-NLS
1334  throw new TskCoreException("Error performing central reposiotry hash lookup", ex);
1335  }
1336  }
1337  }
1338  return result;
1339  }
1340 
1346  @Override
1347  boolean isValid() {
1348  if(! EamDb.isEnabled()) {
1349  return false;
1350  }
1351  try{
1352  return EamDb.getInstance().referenceSetIsValid(this.referenceSetID, this.hashSetName, this.version);
1353  } catch (EamDbException ex){
1354  Logger.getLogger(CentralRepoHashSet.class.getName()).log(Level.SEVERE, "Error validating hash set " + hashSetName, ex); //NON-NLS
1355  return false;
1356  }
1357  }
1358 
1359  @Override
1360  public void firePropertyChange(String propertyName, Object oldValue, Object newValue){
1361  this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
1362  }
1363 
1364  @Override
1365  public String toString(){
1366  return getDisplayName();
1367  }
1368 
1369 
1370  @Override
1371  public int hashCode() {
1372  int code = 23;
1373  code = 47 * code + Objects.hashCode(this.hashSetName);
1374  code = 47 * code + Objects.hashCode(this.version);
1375  code = 47 * code + Integer.hashCode(this.referenceSetID);
1376  code = 47 * code + Objects.hashCode(this.knownFilesType);
1377  return code;
1378  }
1379 
1380  @Override
1381  public boolean equals(Object obj) {
1382  if (obj == null) {
1383  return false;
1384  }
1385  if (getClass() != obj.getClass()) {
1386  return false;
1387  }
1388  final CentralRepoHashSet other = (CentralRepoHashSet) obj;
1389  if (!Objects.equals(this.hashSetName, other.hashSetName)) {
1390  return false;
1391  }
1392  if (!Objects.equals(this.version, other.version)) {
1393  return false;
1394  }
1395  if (this.knownFilesType != other.knownFilesType) {
1396  return false;
1397  }
1398  return true;
1399  }
1400  }
1401 
1405  private class HashDbIndexer extends SwingWorker<Object, Void> {
1406 
1407  private ProgressHandle progress = null;
1408  private SleuthkitHashSet hashDb = null;
1409 
1410  HashDbIndexer(SleuthkitHashSet hashDb) {
1411  this.hashDb = hashDb;
1412  }
1413 
1414  @Override
1415  protected Object doInBackground() {
1416  hashDb.setIndexing(true);
1417  progress = ProgressHandle.createHandle(
1418  NbBundle.getMessage(this.getClass(), "HashDbManager.progress.indexingHashSet", hashDb.getHashSetName()));
1419  progress.start();
1420  progress.switchToIndeterminate();
1421  try {
1422  SleuthkitJNI.createLookupIndexForHashDatabase(hashDb.getHandle());
1423  } catch (TskCoreException ex) {
1424  Logger.getLogger(HashDbIndexer.class.getName()).log(Level.SEVERE, "Error indexing hash set " + hashDb.getHashSetName(), ex); //NON-NLS
1425  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
1426  NbBundle.getMessage(this.getClass(),
1427  "HashDbManager.dlgMsg.errorIndexingHashSet",
1428  hashDb.getHashSetName()),
1429  NbBundle.getMessage(this.getClass(), "HashDbManager.hashDbIndexingErr"),
1430  JOptionPane.ERROR_MESSAGE);
1431  }
1432  return null;
1433  }
1434 
1435  @Override
1436  protected void done() {
1437  hashDb.setIndexing(false);
1438  progress.finish();
1439 
1440  // see if we got any errors
1441  try {
1442  get();
1443  } catch (InterruptedException | ExecutionException ex) {
1444  logger.log(Level.SEVERE, "Error creating index", ex); //NON-NLS
1446  NbBundle.getMessage(this.getClass(), "HashDbManager.errCreatingIndex.title"),
1447  NbBundle.getMessage(this.getClass(), "HashDbManager.errCreatingIndex.msg", ex.getMessage()),
1449  } // catch and ignore if we were cancelled
1450  catch (java.util.concurrent.CancellationException ex) {
1451  }
1452 
1453  try {
1454  hashDb.firePropertyChange(SleuthkitHashSet.Event.INDEXING_DONE.toString(), null, hashDb);
1455  hashDb.firePropertyChange(HashDbManager.SetEvt.DB_INDEXED.toString(), null, hashDb.getHashSetName());
1456  } catch (Exception e) {
1457  logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS
1459  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErr"),
1460  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErrorListeningToUpdatesMsg"),
1462  }
1463  }
1464  }
1465 }
static synchronized IngestManager getInstance()
synchronized void addPropertyChangeListener(PropertyChangeListener listener)
List< HashDb > getUpdateableHashSets(List< HashDb > hashDbs)
synchronized HashDb addNewHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
abstract void firePropertyChange(String propertyName, Object oldValue, Object newValue)
synchronized void removeHashDatabaseNoSave(HashDb hashDb)
CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId)
String getValidFilePath(String hashSetName, String configuredPath)
List< EamGlobalSet > getAllReferenceSets(CorrelationAttributeInstance.Type correlationType)
static HashDb.KnownFilesType convertFileKnown(TskData.FileKnown fileKnown)
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)
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)

Copyright © 2012-2018 Basis Technology. Generated on: Tue Dec 18 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.