19 package org.sleuthkit.autopsy.modules.hashdatabase;
 
   21 import java.beans.PropertyChangeEvent;
 
   22 import java.beans.PropertyChangeListener;
 
   23 import java.beans.PropertyChangeSupport;
 
   25 import java.io.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;
 
   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;
 
   79     private List<HashDb> 
hashSets = 
new ArrayList<>();
 
   87     PropertyChangeSupport changeSupport = 
new PropertyChangeSupport(
HashDbManager.class);
 
   92     private static final String 
KDB_EXT = 
"kdb";
 
   96     private static final Pattern 
OFFICIAL_FILENAME = Pattern.compile(
"(?<" + DB_NAME_PARAM + 
">.+?)\\.(?<" + KNOWN_STATUS_PARAM + 
">.+?)\\." + KDB_EXT);
 
  102         public boolean accept(File dir, String name) {
 
  103             return name.endsWith(
"." + KDB_EXT);
 
  114         DB_ADDED, DB_DELETED, DB_INDEXED
 
  123         if (instance == null) {
 
  130         changeSupport.addPropertyChangeListener(listener);
 
  134         changeSupport.removePropertyChangeListener(listener);
 
  137     synchronized boolean verifyAllDatabasesLoadedCorrectly() {
 
  151     static String getHashDatabaseFileExtension() {
 
  164             super(message, exception);
 
  189         hashDb = this.addExistingHashDatabaseNoSave(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType);
 
  197             if (!
new File(path).exists()) {
 
  198                 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class, 
"HashDbManager.hashDbDoesNotExistExceptionMsg", path));
 
  203             hashDb = 
addHashDatabase(SleuthkitJNI.openHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
 
  204         } 
catch (TskCoreException ex) {
 
  205             throw new HashDbManagerException(ex.getMessage());
 
  228     public synchronized HashDb addNewHashDatabase(String hashSetName, String path, 
boolean searchDuringIngest, 
boolean sendIngestMessages,
 
  243             File file = 
new File(path);
 
  245                 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class, 
"HashDbManager.hashDbFileExistsExceptionMsg", path));
 
  247             if (!FilenameUtils.getExtension(file.getName()).equalsIgnoreCase(HASH_DATABASE_FILE_EXTENSON)) {
 
  248                 throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class, 
"HashDbManager.illegalHashDbFileNameExtensionMsg",
 
  249                         getHashDatabaseFileExtension()));
 
  256             throw new HashDbManagerException(ex.getMessage());
 
  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));
 
  277         if (hashSetNames.contains(hashSetName) || officialHashSetNames.contains(hashSetName)) {
 
  278             throw new HashDbManagerException(NbBundle.getMessage(
HashDbManager.class, 
"HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName));
 
  284         SleuthkitHashSet hashDb = 
new SleuthkitHashSet(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
 
  288         String databasePath = hashDb.getDatabasePath();
 
  289         String indexPath = hashDb.getIndexPath();
 
  293         hashSetNames.add(hashDb.getHashSetName());
 
  294         if (!databasePath.equals(
"None")) { 
 
  295             hashSetPaths.add(databasePath);
 
  297         if (!indexPath.equals(
"None")) { 
 
  298             hashSetPaths.add(indexPath);
 
  302         hashSets.add(hashDb);
 
  306             changeSupport.firePropertyChange(
SetEvt.
DB_ADDED.toString(), null, hashSetName);
 
  307         } 
catch (Exception e) {
 
  308             logger.log(Level.SEVERE, 
"HashDbManager listener threw exception", e); 
 
  310                     NbBundle.getMessage(
this.getClass(), 
"HashDbManager.moduleErr"),
 
  311                     NbBundle.getMessage(
this.getClass(), 
"HashDbManager.moduleErrorListeningToUpdatesMsg"),
 
  317     CentralRepoHashSet addExistingCentralRepoHashSet(String hashSetName, String version, 
int referenceSetID,
 
  322             throw new TskCoreException(
"Could not load central repository hash set " + hashSetName + 
" - central repository is not enabled");
 
  325         CentralRepoHashSet db = 
new CentralRepoHashSet(hashSetName, version, referenceSetID, searchDuringIngest,
 
  326                 sendIngestMessages, knownFilesType, readOnly);
 
  329             throw new TskCoreException(
"Error finding hash set " + hashSetName + 
" in central repository");
 
  333         if(!hashSets.contains(db)) {
 
  338                 changeSupport.firePropertyChange(SetEvt.DB_ADDED.toString(), null, hashSetName);
 
  339             } 
catch (Exception e) {
 
  340                 logger.log(Level.SEVERE, 
"HashDbManager listener threw exception", e); 
 
  341                 MessageNotifyUtil.Notify.show(
 
  342                         NbBundle.getMessage(
this.getClass(), 
"HashDbManager.moduleErr"),
 
  343                         NbBundle.getMessage(
this.getClass(), 
"HashDbManager.moduleErrorListeningToUpdatesMsg"),
 
  344                         MessageNotifyUtil.MessageType.ERROR);
 
  351     synchronized void indexHashDatabase(SleuthkitHashSet hashDb) {
 
  352         hashDb.addPropertyChangeListener(
this);
 
  353         HashDbIndexer creator = 
new HashDbIndexer(hashDb);
 
  359         if (event.getPropertyName().equals(SleuthkitHashSet.Event.INDEXING_DONE.name())) {
 
  360             SleuthkitHashSet hashDb = (SleuthkitHashSet) event.getNewValue();
 
  361             if (null != hashDb) {
 
  363                     String indexPath = hashDb.getIndexPath();
 
  364                     if (!indexPath.equals(
"None")) { 
 
  365                         hashSetPaths.add(indexPath);
 
  368                     Logger.
getLogger(
HashDbManager.class.getName()).log(Level.SEVERE, 
"Error getting index path of " + hashDb.getHashSetName() + 
" hash set after indexing", ex); 
 
  390         if (ingestIsRunning) {
 
  391             throw new HashDbManagerException(NbBundle.getMessage(
this.getClass(), 
"HashDbManager.ingestRunningExceptionMsg"));
 
  397         String hashSetName = hashDb.getHashSetName();
 
  398         hashSetNames.remove(hashSetName);
 
  399         hashSets.remove(hashDb);
 
  403         if (hashDb instanceof SleuthkitHashSet) {
 
  404             SleuthkitHashSet hashDatabase = (SleuthkitHashSet) hashDb;
 
  406                 if (hashDatabase.hasIndex()) {
 
  407                     hashSetPaths.remove(hashDatabase.getIndexPath());
 
  410                 Logger.
getLogger(
HashDbManager.class.getName()).log(Level.SEVERE, 
"Error getting index path of " + hashDatabase.getHashSetName() + 
" hash set when removing the hash set", ex); 
 
  414                 if (!hashDatabase.hasIndexOnly()) {
 
  415                     hashSetPaths.remove(hashDatabase.getDatabasePath());
 
  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); 
 
  422                 hashDatabase.close();
 
  424                 Logger.
getLogger(
HashDbManager.class.getName()).log(Level.SEVERE, 
"Error closing " + hashDb.getHashSetName() + 
" hash set when removing the hash set", ex); 
 
  430             changeSupport.firePropertyChange(
SetEvt.
DB_DELETED.toString(), null, hashSetName);
 
  431         } 
catch (Exception e) {
 
  432             logger.log(Level.SEVERE, 
"HashDbManager listener threw exception", e); 
 
  434                     NbBundle.getMessage(
this.getClass(), 
"HashDbManager.moduleErr"),
 
  435                     NbBundle.getMessage(
this.getClass(), 
"HashDbManager.moduleErrorListeningToUpdatesMsg"),
 
  440     void save() throws HashDbManagerException {
 
  442             if (!HashLookupSettings.writeSettings(
new HashLookupSettings(HashLookupSettings.convertHashSetList(
this.hashSets)))) {
 
  443                 throw new HashDbManagerException(NbBundle.getMessage(
this.getClass(), 
"HashDbManager.saveErrorExceptionMsg"));
 
  445         } 
catch (HashLookupSettings.HashLookupSettingsException ex) {
 
  446             throw new HashDbManagerException(NbBundle.getMessage(
this.getClass(), 
"HashDbManager.saveErrorExceptionMsg"));
 
  464         return Stream.concat(this.officialHashSets.stream(), this.hashSets.stream())
 
  465                 .collect(Collectors.toList());
 
  477                 .collect(Collectors.toList());
 
  489                 .collect(Collectors.toList());
 
  512                 .collect(Collectors.toList());
 
  516         List<HashDbInfo> crHashSets = 
new ArrayList<>();
 
  526                     crHashSets.add(
new HashDbInfo(globalSet.getSetName(), globalSet.getVersion(),
 
  527                             globalSet.getGlobalSetID(), 
KnownFilesType.
fromFileKnown(globalSet.getFileKnownStatus()), globalSet.isReadOnly(), 
false, sendIngestMessages));
 
  542         hashSetNames.clear();
 
  543         hashSetPaths.clear();
 
  549         for (
HashDb database : hashDatabases) {
 
  550             if (database instanceof SleuthkitHashSet) {
 
  552                     ((SleuthkitHashSet) database).close();
 
  558         hashDatabases.clear();
 
  565             HashLookupSettings settings = HashLookupSettings.readSettings();
 
  567         } 
catch (HashLookupSettings.HashLookupSettingsException ex) {
 
  577         officialHashSetPaths = 
new HashSet<>();
 
  578         officialHashSetNames = 
new HashSet<>();
 
  582             officialHashSets.forEach(db -> {
 
  583                 officialHashSetNames.add(db.getHashSetName());
 
  585                     String databasePath = db.getDatabasePath();
 
  586                     String indexPath = db.getIndexPath();
 
  588                     if (StringUtils.isNotBlank(databasePath) && !databasePath.equals(
"None")) { 
 
  589                         officialHashSetPaths.add(databasePath);
 
  591                     if (StringUtils.isNotBlank(indexPath) && !indexPath.equals(
"None")) { 
 
  592                         officialHashSetPaths.add(indexPath);
 
  595                     logger.log(Level.SEVERE, 
"There was an error loading the official hash set name.", ex);
 
  598         } 
catch (HashDbManagerException ex) {
 
  599             logger.log(Level.WARNING, 
"There was an error loading the official hash sets.", ex);
 
  600             officialHashSets = 
new ArrayList<HashDb>();
 
  616         "# {0} - hashSetName",
 
  617         "HashDbManager_handleNameConflict_conflictSuffix={0} (Custom)" 
  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);
 
  630                 newItems.add(
new HashDbInfo(
 
  632                         hashset.getKnownFilesType(),
 
  633                         hashset.getSearchDuringIngest(),
 
  634                         hashset.getSendIngestMessages(),
 
  636                         hashset.getReferenceSetID(),
 
  637                         hashset.getVersion(),
 
  638                         hashset.isReadOnly(),
 
  639                         hashset.isCentralRepoDatabaseType()
 
  643                 newItems.add(hashset);
 
  646             curNames.add(thisName);
 
  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);
 
  673         File configFolder = InstalledFileLocator.getDefault().locate(
 
  676         if (configFolder == null || !configFolder.exists() || !configFolder.isDirectory()) {
 
  677             throw new HashDbManagerException(
"Folder provided: " + folder + 
" does not exist.");
 
  680         return Stream.of(configFolder.listFiles(DEFAULT_KDB_FILTER))
 
  685                         logger.log(Level.WARNING, String.format(
"Hashset: %s could not be properly read.", f.getAbsolutePath()), ex);
 
  689                 .filter((hashdb) -> hashdb != null)
 
  690                 .collect(Collectors.toList());
 
  706         if (file == null || !file.exists()) {
 
  707             throw new HashDbManagerException(String.format(
"No file found for: %s", file == null ? 
"<null>" : file.getAbsolutePath()));
 
  709         String filename = file.getName();
 
  710         Matcher match = OFFICIAL_FILENAME.matcher(filename);
 
  712             throw new HashDbManagerException(String.format(
"File with name: %s does not match regex of: %s", filename, OFFICIAL_FILENAME.toString()));
 
  715         String hashdbName = match.group(DB_NAME_PARAM);
 
  716         final String knownStatus = match.group(KNOWN_STATUS_PARAM);
 
  719                 .filter(k -> k.getIdentifier().toUpperCase().equals(knownStatus.toUpperCase()))
 
  721                 .orElseThrow(() -> 
new HashDbManagerException(String.format(
"No KnownFilesType matches %s for file: %s", knownStatus, filename)));
 
  723         return new SleuthkitHashSet(
 
  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"})
 
  743         allDatabasesLoadedCorrectly = 
true;
 
  744         List<HashDbInfo> hashDbInfoList = settings.getHashDbInfo();
 
  747         for (HashDbInfo hashDbInfo : hashDbInfoList) {
 
  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);
 
  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;
 
  799             if (hashDbInfo.isFileDatabaseType()) {
 
  800                 String dbPath = this.
getValidFilePath(hashDbInfo.getHashSetName(), hashDbInfo.getPath());
 
  801                 if (dbPath != null) {
 
  804                     logger.log(Level.WARNING, Bundle.HashDbManager_noDbPath_message(hashDbInfo.getHashSetName()));
 
  805                     allDatabasesLoadedCorrectly = 
false;
 
  809                     addExistingCentralRepoHashSet(hashDbInfo.getHashSetName(), hashDbInfo.getVersion(),
 
  810                             hashDbInfo.getReferenceSetID(),
 
  811                             hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(),
 
  812                             hashDbInfo.getKnownFilesType(), hashDbInfo.isReadOnly());
 
  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;
 
  829             for (HashDbInfo hashDbInfo : crHashDbInfoList) {
 
  831                     addExistingCentralRepoHashSet(hashDbInfo.getHashSetName(), hashDbInfo.getVersion(),
 
  832                             hashDbInfo.getReferenceSetID(),
 
  833                             hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType(),
 
  834                             hashDbInfo.isReadOnly());
 
  841         for (
HashDb db : this.hashSets) {
 
  842             if (dbInfo.matches(db)) {
 
  851         File database = 
new File(configuredPath);
 
  852         if (database.exists()) {
 
  853             return configuredPath;
 
  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) {
 
  865             if (null != newPath && !newPath.isEmpty()) {
 
  866                 database = 
new File(newPath);
 
  867                 if (!database.exists()) {
 
  876         String filePath = null;
 
  878         fc.setDragEnabled(
false);
 
  879         fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
 
  880         String[] EXTENSION = 
new String[]{
"txt", 
"idx", 
"hash", 
"Hash", 
"kdb"}; 
 
  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();
 
  888                 filePath = f.getCanonicalPath();
 
  889             } 
catch (IOException ex) {
 
  903             "HashDbManager.noChange.text=No Change",
 
  904             "HashDbManager.known.text=Known",
 
  905             "HashDbManager.knownBad.text=Notable" 
  920                     boolean allowSendInboxMessages, 
boolean defaultSendInboxMessages) {
 
  922                 this.displayName = displayName;
 
  923                 this.identifier = identifier;
 
  924                 this.fileKnown = fileKnown;
 
  925                 this.allowSendInboxMessages = allowSendInboxMessages;
 
  926                 this.defaultSendInboxMessages = defaultSendInboxMessages;
 
  937                 return allowSendInboxMessages;
 
  948                 return defaultSendInboxMessages;
 
  962                 return this.displayName;
 
  972                 return this.fileKnown;
 
  983                 if (fileKnown == null) {
 
  988                         .filter((type) -> type.getFileKnown() == fileKnown)
 
  990                         .orElseThrow(() -> 
new IllegalArgumentException(
"Unknown TskData.FileKnown type: " + fileKnown));
 
 1004         abstract String getDisplayName();
 
 1012         abstract 
void setSearchDuringIngest(
boolean useForIngest);
 
 1016         abstract 
void setSendIngestMessages(
boolean showInboxMessages);
 
 1025         public abstract 
boolean isUpdateable() throws TskCoreException;
 
 1037         public abstract 
void addHashes(
Content content, String comment) throws TskCoreException;
 
 1053         abstract 
boolean isValid() throws TskCoreException;
 
 1055         public abstract String 
getIndexPath() throws TskCoreException;
 
 1057         public abstract 
boolean hasIndexOnly() throws TskCoreException;
 
 1059         public abstract 
void firePropertyChange(String propertyName, Object oldValue, Object newValue);
 
 1074     class SleuthkitHashSet extends 
HashDb {
 
 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;
 
 1082         private boolean indexing;
 
 1083         private final PropertyChangeSupport propertyChangeSupport = 
new PropertyChangeSupport(
this);
 
 1084         private final boolean officialSet;
 
 1086         private SleuthkitHashSet(
int handle, String hashSetName, 
boolean useForIngest, 
boolean sendHitMessages, 
KnownFilesType knownFilesType) {
 
 1087             this(handle, hashSetName, useForIngest, sendHitMessages, knownFilesType, 
false);
 
 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;
 
 1108             propertyChangeSupport.addPropertyChangeListener(pcl);
 
 1118             propertyChangeSupport.removePropertyChangeListener(pcl);
 
 1131         String getDisplayName() {
 
 1137             return SleuthkitJNI.getHashDatabasePath(handle);
 
 1140         public void setIndexing(
boolean indexing) {
 
 1141             this.indexing = indexing;
 
 1146             return SleuthkitJNI.getHashDatabaseIndexPath(handle);
 
 1151             return knownFilesType;
 
 1156             return searchDuringIngest;
 
 1160         void setSearchDuringIngest(
boolean useForIngest) {
 
 1161             this.searchDuringIngest = useForIngest;
 
 1166             return sendIngestMessages;
 
 1170         void setSendIngestMessages(
boolean showInboxMessages) {
 
 1171             this.sendIngestMessages = showInboxMessages;
 
 1182         public boolean isUpdateable() throws TskCoreException {
 
 1183             if (isOfficialSet()) {
 
 1187             return SleuthkitJNI.isUpdateableHashDatabase(this.handle);
 
 1199         public void addHashes(Content content) 
throws TskCoreException {
 
 1214         public void addHashes(Content content, String comment) 
throws TskCoreException {
 
 1216             assert content instanceof AbstractFile;
 
 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);
 
 1231         private void officialSetCheck() throws TskCoreException {
 
 1232             if (isOfficialSet()) {
 
 1233                 throw new TskCoreException(
"Hashes cannot be added to an official set");
 
 1245         public void addHashes(List<HashEntry> hashes) 
throws TskCoreException {
 
 1247             SleuthkitJNI.addToHashDatabase(hashes, handle);
 
 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);
 
 1282         public HashHitInfo 
lookupMD5(Content content) 
throws TskCoreException {
 
 1283             HashHitInfo result = null;
 
 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);
 
 1304         boolean isValid() throws TskCoreException {
 
 1308         boolean hasIndex() throws TskCoreException {
 
 1309             return SleuthkitJNI.hashDatabaseHasLookupIndex(handle);
 
 1313         public boolean hasIndexOnly() throws TskCoreException {
 
 1314             return SleuthkitJNI.hashDatabaseIsIndexOnly(handle);
 
 1317         boolean canBeReIndexed() throws TskCoreException {
 
 1318             return SleuthkitJNI.hashDatabaseCanBeReindexed(handle);
 
 1321         boolean isIndexing() {
 
 1326         public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
 
 1327             this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
 
 1330         private void close() throws TskCoreException {
 
 1331             SleuthkitJNI.closeHashDatabase(handle);
 
 1340         public int hashCode() {
 
 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);
 
 1350         public boolean equals(Object obj) {
 
 1354             if (getClass() != obj.getClass()) {
 
 1357             final SleuthkitHashSet other = (SleuthkitHashSet) obj;
 
 1358             if (!Objects.equals(
this.hashSetName, other.hashSetName)) {
 
 1361             if (this.knownFilesType != other.knownFilesType) {
 
 1373         boolean isOfficialSet() {
 
 1382     class CentralRepoHashSet 
extends HashDb {
 
 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);
 
 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,
 
 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;
 
 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); 
 
 1412                 orgName = Bundle.HashDbManager_CentralRepoHashDb_orgError();
 
 1424             propertyChangeSupport.addPropertyChangeListener(pcl);
 
 1434             propertyChangeSupport.removePropertyChangeListener(pcl);
 
 1438         public boolean hasIndexOnly() throws TskCoreException {
 
 1448         public String getDisplayName() {
 
 1449             if (!getVersion().isEmpty()) {
 
 1456         String getVersion() {
 
 1460         String getOrgName() {
 
 1464         int getReferenceSetID() {
 
 1465             return referenceSetID;
 
 1480             return knownFilesType;
 
 1485             return searchDuringIngest;
 
 1489         void setSearchDuringIngest(
boolean useForIngest) {
 
 1490             this.searchDuringIngest = useForIngest;
 
 1495             return sendIngestMessages;
 
 1499         void setSendIngestMessages(
boolean showInboxMessages) {
 
 1500             this.sendIngestMessages = showInboxMessages;
 
 1511         public boolean isUpdateable() throws TskCoreException {
 
 1524         public void addHashes(Content content) 
throws TskCoreException {
 
 1539         public void addHashes(Content content, String comment) 
throws TskCoreException {
 
 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();
 
 1548                         CentralRepoFileInstance fileInstance = 
new CentralRepoFileInstance(referenceSetID, file.getMd5Hash(),
 
 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);   
 
 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();
 
 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);
 
 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);
 
 1596         public boolean lookupMD5Quick(Content content) 
throws TskCoreException {
 
 1598             assert content instanceof AbstractFile;
 
 1599             if (content instanceof AbstractFile) {
 
 1600                 AbstractFile file = (AbstractFile) content;
 
 1601                 if (null != file.getMd5Hash()) {
 
 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); 
 
 1607                         throw new TskCoreException(
"Error performing central reposiotry hash lookup", ex);
 
 1624         public HashHitInfo 
lookupMD5(Content content) 
throws TskCoreException {
 
 1625             HashHitInfo result = null;
 
 1627             assert content instanceof AbstractFile;
 
 1628             if (content instanceof AbstractFile) {
 
 1629                 AbstractFile file = (AbstractFile) content;
 
 1630                 if (null != file.getMd5Hash()) {
 
 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); 
 
 1636                         throw new TskCoreException(
"Error performing central reposiotry hash lookup", ex);
 
 1650             if (!CentralRepository.isEnabled()) {
 
 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); 
 
 1662         public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
 
 1663             this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
 
 1668             return getDisplayName();
 
 1672         public int hashCode() {
 
 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);
 
 1682         public boolean equals(Object obj) {
 
 1686             if (getClass() != obj.getClass()) {
 
 1689             final CentralRepoHashSet other = (CentralRepoHashSet) obj;
 
 1690             if (!Objects.equals(
this.hashSetName, other.hashSetName)) {
 
 1693             if (!Objects.equals(
this.version, other.version)) {
 
 1696             if (this.knownFilesType != other.knownFilesType) {
 
 1708         private ProgressHandle progress = null;
 
 1709         private SleuthkitHashSet hashDb = null;
 
 1712             this.hashDb = hashDb;
 
 1717             hashDb.setIndexing(
true);
 
 1718             progress = ProgressHandle.createHandle(
 
 1719                     NbBundle.getMessage(
this.getClass(), 
"HashDbManager.progress.indexingHashSet", hashDb.getHashSetName()));
 
 1721             progress.switchToIndeterminate();
 
 1724             } 
catch (TskCoreException ex) {
 
 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);
 
 1738             hashDb.setIndexing(
false);
 
 1744             } 
catch (InterruptedException | ExecutionException ex) {
 
 1745                 logger.log(Level.SEVERE, 
"Error creating index", ex); 
 
 1747                         NbBundle.getMessage(
this.getClass(), 
"HashDbManager.errCreatingIndex.title"),
 
 1748                         NbBundle.getMessage(
this.getClass(), 
"HashDbManager.errCreatingIndex.msg", ex.getMessage()),
 
 1751             catch (java.util.concurrent.CancellationException ex) {
 
 1755                 hashDb.firePropertyChange(SleuthkitHashSet.Event.INDEXING_DONE.toString(), null, hashDb);
 
 1757             } 
catch (Exception e) {
 
 1758                 logger.log(Level.SEVERE, 
"HashDbManager listener threw exception", e); 
 
 1760                         NbBundle.getMessage(
this.getClass(), 
"HashDbManager.moduleErr"),
 
 1761                         NbBundle.getMessage(
this.getClass(), 
"HashDbManager.moduleErrorListeningToUpdatesMsg"),
 
abstract boolean getSendIngestMessages()
Set< String > hashSetPaths
abstract String getIndexPath()
static final Pattern OFFICIAL_FILENAME
static void createLookupIndexForHashDatabase(int dbHandle)
static final Logger logger
static final String HASH_DATABASE_FILE_EXTENSON
void loadHashsetsConfiguration()
static synchronized IngestManager getInstance()
Set< String > officialHashSetPaths
static int createHashDatabase(String path)
static final String DB_NAME_PARAM
Set< String > officialHashSetNames
static boolean runningWithGUI
synchronized void addPropertyChangeListener(PropertyChangeListener listener)
HashDbManagerException(String message)
void checkDbCollision(String path, String hashSetName)
List< CentralRepoFileSet > getAllReferenceSets(CorrelationAttributeInstance.Type correlationType)
static KnownFilesType fromFileKnown(TskData.FileKnown fileKnown)
abstract String getHashSetName()
List< HashDbInfo > getCentralRepoHashSetsFromDatabase()
List< HashDb > loadOfficialHashSetsFromFolder(String folder)
boolean isIngestRunning()
static final long serialVersionUID
final TskData.FileKnown fileKnown
List< HashDb > getUpdateableHashSets(List< HashDb > hashDbs)
abstract String toString()
static final String KDB_EXT
synchronized HashDb addNewHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
void configureSettings(HashLookupSettings settings, Set< String > officialSetNames)
HashDbManagerException(String message, Throwable exception)
synchronized void removeHashDatabase(HashDb hashDb)
static final String OFFICIAL_HASH_SETS_FOLDER
final boolean allowSendInboxMessages
boolean allDatabasesLoadedCorrectly
abstract void firePropertyChange(String propertyName, Object oldValue, Object newValue)
void loadOfficialHashSets()
synchronized List< HashDb > getKnownBadFileHashSets()
boolean hashDbInfoIsNew(HashDbInfo dbInfo)
TskData.FileKnown getFileKnown()
synchronized void removeHashDatabaseNoSave(HashDb hashDb)
static HashDbManager instance
Set< String > hashSetNames
static synchronized HashDbManager getInstance()
String getValidFilePath(String hashSetName, String configuredPath)
static final String KNOWN_STATUS_PARAM
final JFileChooserFactory chooserHelper
abstract HashDb.KnownFilesType getKnownFilesType()
synchronized HashDb addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
boolean isDefaultInboxMessages()
synchronized void removePropertyChangeListener(PropertyChangeListener listener)
JFileChooser getChooser()
abstract HashHitInfo lookupMD5(Content content)
synchronized List< HashDb > getUpdateableHashSets()
static int openHashDatabase(String path)
synchronized List< HashDb > getAllHashSets()
abstract boolean isUpdateable()
abstract boolean lookupMD5Quick(Content content)
abstract String getDatabasePath()
void propertyChange(PropertyChangeEvent event)
void closeHashDatabases(List< HashDb > hashDatabases)
synchronized void loadLastSavedConfiguration()
HashDb getOfficialHashDbFromFile(File file)
abstract void addPropertyChangeListener(PropertyChangeListener pcl)
synchronized static Logger getLogger(String name)
final boolean defaultSendInboxMessages
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)
boolean isInboxMessagesAllowed()
abstract boolean hasIndexOnly()
SleuthkitHashSet addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
abstract boolean getSearchDuringIngest()
static CentralRepository getInstance()
void updateHashSetsFromCentralRepository()
synchronized List< HashDb > getKnownFileHashSets()
void configureLocalDb(HashDbInfo hashDbInfo)
synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
static final int FILES_TYPE_ID
static final FilenameFilter DEFAULT_KDB_FILTER
static boolean isEnabled()
abstract void addHashes(Content content)
abstract void removePropertyChangeListener(PropertyChangeListener pcl)
List< HashDb > officialHashSets
List< HashDbInfo > handleNameConflict(List< HashDbInfo > curHashsets, Set< String > officialNames)