diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index b16589c3dd..7c7d22066e 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -34,10 +34,8 @@ import java.time.LocalDate; import java.util.HashMap; import java.util.Map; import java.util.Set; -import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; - import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskData; @@ -1250,6 +1248,136 @@ public abstract class AbstractSqlEamDb implements EamDb { return caseNames.stream().collect(Collectors.toList()); } + + /** + * Remove a reference set and all entries contained in it. + * @param referenceSetID + * @throws EamDbException + */ + @Override + public void deleteReferenceSet(int referenceSetID) throws EamDbException{ + deleteReferenceSetEntries(referenceSetID); + deleteReferenceSetEntry(referenceSetID); + } + + /** + * Remove the entry for this set from the reference_sets table + * @param referenceSetID + * @throws EamDbException + */ + private void deleteReferenceSetEntry(int referenceSetID) throws EamDbException{ + Connection conn = connect(); + + PreparedStatement preparedStatement = null; + String sql = "DELETE FROM reference_sets WHERE id=?"; + + try { + preparedStatement = conn.prepareStatement(sql); + preparedStatement.setInt(1, referenceSetID); + preparedStatement.executeUpdate(); + } catch (SQLException ex) { + throw new EamDbException("Error deleting reference set " + referenceSetID, ex); // NON-NLS + } finally { + EamDbUtil.closePreparedStatement(preparedStatement); + EamDbUtil.closeConnection(conn); + } + } + + /** + * Remove all entries for this reference set from the reference tables + * (Currently only removes entries from the reference_file table) + * @param referenceSetID + * @throws EamDbException + */ + private void deleteReferenceSetEntries(int referenceSetID) throws EamDbException{ + Connection conn = connect(); + + PreparedStatement preparedStatement = null; + String sql = "DELETE FROM %s WHERE reference_set_id=?"; + + // When other reference types are added, this will need to loop over all the tables + String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID)); + + try { + preparedStatement = conn.prepareStatement(String.format(sql, fileTableName)); + preparedStatement.setInt(1, referenceSetID); + preparedStatement.executeUpdate(); + } catch (SQLException ex) { + throw new EamDbException("Error deleting files from reference set " + referenceSetID, ex); // NON-NLS + } finally { + EamDbUtil.closePreparedStatement(preparedStatement); + EamDbUtil.closeConnection(conn); + } + } + + /** + * Check whether a reference set with the given parameters exists in the central repository. + * Used to check whether reference sets saved in the settings are still present. + * @param referenceSetID + * @param setName + * @param version + * @return true if a matching entry exists in the central repository + * @throws EamDbException + */ + @Override + public boolean referenceSetIsValid(int referenceSetID, String setName, String version) throws EamDbException{ + EamGlobalSet refSet = this.getReferenceSetByID(referenceSetID); + if(refSet == null){ + return false; + } + + return(refSet.getSetName().equals(setName) && refSet.getVersion().equals(version)); + } + + /** + * Check if the given file hash is in this reference set. + * Only searches the reference_files table. + * @param hash + * @param referenceSetID + * @return true if the hash is found in the reference set + * @throws EamDbException + */ + @Override + public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException{ + return isValueInReferenceSet(hash, referenceSetID, CorrelationAttribute.FILES_TYPE_ID); + } + + /** + * Check if the given value is in a specific reference set + * @param value + * @param referenceSetID + * @param correlationTypeID + * @return true if the value is found in the reference set + */ + @Override + public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException{ + + Connection conn = connect(); + + Long matchingInstances = 0L; + PreparedStatement preparedStatement = null; + ResultSet resultSet = null; + String sql = "SELECT count(*) FROM %s WHERE value=? AND reference_set_id=?"; + + String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID)); + + try { + preparedStatement = conn.prepareStatement(String.format(sql, fileTableName)); + preparedStatement.setString(1, value); + preparedStatement.setInt(2, referenceSetID); + resultSet = preparedStatement.executeQuery(); + resultSet.next(); + matchingInstances = resultSet.getLong(1); + } catch (SQLException ex) { + throw new EamDbException("Error determining if value (" + value + ") is in reference set " + referenceSetID, ex); // NON-NLS + } finally { + EamDbUtil.closePreparedStatement(preparedStatement); + EamDbUtil.closeResultSet(resultSet); + EamDbUtil.closeConnection(conn); + } + + return 0 < matchingInstances; + } /** * Is the artifact known as bad according to the reference entries? @@ -1260,7 +1388,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * @return Global known status of the artifact */ @Override - public boolean isArtifactlKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException { + public boolean isArtifactKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException { // TEMP: Only support file correlation type if (aType.getId() != CorrelationAttribute.FILES_TYPE_ID) { @@ -1396,6 +1524,19 @@ public abstract class AbstractSqlEamDb implements EamDb { EamDbUtil.closeConnection(conn); } } + + /** + * Get the organization associated with the given reference set. + * @param referenceSetID ID of the reference set + * @return The organization object + * @throws EamDbException + */ + @Override + public EamOrganization getReferenceSetOrganization(int referenceSetID) throws EamDbException{ + + EamGlobalSet globalSet = getReferenceSetByID(referenceSetID); + return (getOrganizationByID(globalSet.getOrgID())); + } /** * Update an existing organization. @@ -1469,13 +1610,13 @@ public abstract class AbstractSqlEamDb implements EamDb { * @throws EamDbException */ @Override - public int newReferencelSet(EamGlobalSet eamGlobalSet) throws EamDbException { + public int newReferenceSet(EamGlobalSet eamGlobalSet) throws EamDbException { Connection conn = connect(); PreparedStatement preparedStatement1 = null; PreparedStatement preparedStatement2 = null; ResultSet resultSet = null; - String sql1 = "INSERT INTO reference_sets(org_id, set_name, version, import_date) VALUES (?, ?, ?, ?)"; + String sql1 = "INSERT INTO reference_sets(org_id, set_name, version, known_status, read_only, import_date) VALUES (?, ?, ?, ?, ?, ?)"; String sql2 = "SELECT id FROM reference_sets WHERE org_id=? AND set_name=? AND version=? AND import_date=? LIMIT 1"; try { @@ -1483,7 +1624,9 @@ public abstract class AbstractSqlEamDb implements EamDb { preparedStatement1.setInt(1, eamGlobalSet.getOrgID()); preparedStatement1.setString(2, eamGlobalSet.getSetName()); preparedStatement1.setString(3, eamGlobalSet.getVersion()); - preparedStatement1.setString(4, eamGlobalSet.getImportDate().toString()); + preparedStatement1.setInt(4, eamGlobalSet.getFileKnownStatus().getFileKnownValue()); + preparedStatement1.setBoolean(5, eamGlobalSet.isReadOnly()); + preparedStatement1.setString(6, eamGlobalSet.getImportDate().toString()); preparedStatement1.executeUpdate(); @@ -1539,6 +1682,39 @@ public abstract class AbstractSqlEamDb implements EamDb { EamDbUtil.closeConnection(conn); } } + + /** + * Get all reference sets + * + * @return List of all reference sets in the central repository + * + * @throws EamDbException + */ + @Override + public List getAllReferenceSets() throws EamDbException{ + List results = new ArrayList<>(); + Connection conn = connect(); + + PreparedStatement preparedStatement1 = null; + ResultSet resultSet = null; + String sql1 = "SELECT * FROM reference_sets"; + + try { + preparedStatement1 = conn.prepareStatement(sql1); + resultSet = preparedStatement1.executeQuery(); + while (resultSet.next()) { + results.add(getEamGlobalSetFromResultSet(resultSet)); + } + + } catch (SQLException ex) { + throw new EamDbException("Error getting reference sets.", ex); // NON-NLS + } finally { + EamDbUtil.closePreparedStatement(preparedStatement1); + EamDbUtil.closeResultSet(resultSet); + EamDbUtil.closeConnection(conn); + } + return results; + } /** * Add a new reference instance @@ -1571,6 +1747,39 @@ public abstract class AbstractSqlEamDb implements EamDb { EamDbUtil.closeConnection(conn); } } + + /** + * Check whether a reference set with the given name/version is in the central repo. + * Used to check for name collisions when creating reference sets. + * @param referenceSetName + * @param version + * @return true if a matching set is found + * @throws EamDbException + */ + @Override + public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException{ + Connection conn = connect(); + + PreparedStatement preparedStatement1 = null; + ResultSet resultSet = null; + String sql1 = "SELECT * FROM reference_sets WHERE set_name=? AND version=?"; + + try { + preparedStatement1 = conn.prepareStatement(sql1); + preparedStatement1.setString(1, referenceSetName); + preparedStatement1.setString(2, version); + resultSet = preparedStatement1.executeQuery(); + return (resultSet.next()); + + } catch (SQLException ex) { + throw new EamDbException("Error testing whether reference set exists (name: " + referenceSetName + + " version: " + version, ex); // NON-NLS + } finally { + EamDbUtil.closePreparedStatement(preparedStatement1); + EamDbUtil.closeResultSet(resultSet); + EamDbUtil.closeConnection(conn); + } + } /** * Insert the bulk collection of Reference Type Instances @@ -2001,6 +2210,8 @@ public abstract class AbstractSqlEamDb implements EamDb { resultSet.getInt("org_id"), resultSet.getString("set_name"), resultSet.getString("version"), + TskData.FileKnown.valueOf(resultSet.getByte("known_status")), + resultSet.getBoolean("read_only"), LocalDate.parse(resultSet.getString("import_date")) ); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java index 70ab104fa4..9f7e31fbc5 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java @@ -353,6 +353,53 @@ public interface EamDb { */ List getListCasesHavingArtifactInstancesKnownBad(CorrelationAttribute.Type aType, String value) throws EamDbException; + /** + * Remove a reference set and all values contained in it. + * @param referenceSetID + * @throws EamDbException + */ + public void deleteReferenceSet(int referenceSetID) throws EamDbException; + + /** + * Check whether a reference set with the given parameters exists in the central repository. + * Used to check whether reference sets saved in the settings are still present. + * @param referenceSetID + * @param referenceSetName + * @param version + * @return true if a matching entry exists in the central repository + * @throws EamDbException + */ + public boolean referenceSetIsValid(int referenceSetID, String referenceSetName, String version) throws EamDbException; + + /** + * Check whether a reference set with the given name/version is in the central repo. + * Used to check for name collisions when creating reference sets. + * @param referenceSetName + * @param version + * @return true if a matching set is found + * @throws EamDbException + */ + public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException; + + /** + * Check if the given file hash is in this reference set. + * Only searches the reference_files table. + * @param hash + * @param referenceSetID + * @return true if the hash is found in the reference set + * @throws EamDbException + */ + public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException; + + /** + * Check if the given value is in a specific reference set + * @param value + * @param referenceSetID + * @param correlationTypeID + * @return true if the hash is found in the reference set + */ + public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException; + /** * Is the artifact known as bad according to the reference entries? * @@ -361,7 +408,7 @@ public interface EamDb { * * @return Global known status of the artifact */ - boolean isArtifactlKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException; + boolean isArtifactKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException; /** * Add a new organization @@ -394,6 +441,14 @@ public interface EamDb { */ EamOrganization getOrganizationByID(int orgID) throws EamDbException; + /** + * Get the organization associated with the given reference set. + * @param referenceSetID ID of the reference set + * @return The organization object + * @throws EamDbException + */ + EamOrganization getReferenceSetOrganization(int referenceSetID) throws EamDbException; + /** * Update an existing organization. * @@ -413,7 +468,6 @@ public interface EamDb { */ void deleteOrganization(EamOrganization organizationToDelete) throws EamDbException; - /** * Add a new Global Set * @@ -423,7 +477,7 @@ public interface EamDb { * * @throws EamDbException */ - int newReferencelSet(EamGlobalSet eamGlobalSet) throws EamDbException; + int newReferenceSet(EamGlobalSet eamGlobalSet) throws EamDbException; /** * Get a global set by ID @@ -435,6 +489,15 @@ public interface EamDb { * @throws EamDbException */ EamGlobalSet getReferenceSetByID(int globalSetID) throws EamDbException; + + /** + * Get all reference sets + * + * @return List of all reference sets in the central repository + * + * @throws EamDbException + */ + List getAllReferenceSets() throws EamDbException; /** * Add a new reference instance diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java index 21b4bd282c..23a4c257ae 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.centralrepository.datamodel; import java.time.LocalDate; +import org.sleuthkit.datamodel.TskData; /** * A global set in the Central Repository database @@ -29,6 +30,8 @@ public class EamGlobalSet { private int orgID; private String setName; private String version; + private TskData.FileKnown fileKnownStatus; + private boolean isReadOnly; private LocalDate importDate; public EamGlobalSet( @@ -36,11 +39,15 @@ public class EamGlobalSet { int orgID, String setName, String version, + TskData.FileKnown knownStatus, + boolean isReadOnly, LocalDate importDate) { this.globalSetID = globalSetID; this.orgID = orgID; this.setName = setName; this.version = version; + this.fileKnownStatus = knownStatus; + this.isReadOnly = isReadOnly; this.importDate = importDate; } @@ -48,8 +55,30 @@ public class EamGlobalSet { int orgID, String setName, String version, + TskData.FileKnown knownStatus, + boolean isReadOnly, LocalDate importDate) { - this(-1, orgID, setName, version, importDate); + this(-1, orgID, setName, version, knownStatus, isReadOnly, importDate); + } + + /** + * Create a new EamGlobalSet object. + * This is intended to be used when creating a new global set as the + * globalSetID will be unknown to start. + * importDate will be automatically set to the current time. + * @param orgID + * @param setName + * @param version + * @param knownStatus + * @param isReadOnly + */ + public EamGlobalSet( + int orgID, + String setName, + String version, + TskData.FileKnown knownStatus, + boolean isReadOnly) { + this(-1, orgID, setName, version, knownStatus, isReadOnly, LocalDate.now()); } /** @@ -107,6 +136,34 @@ public class EamGlobalSet { public void setVersion(String version) { this.version = version; } + + /** + * @return whether it is read only + */ + public boolean isReadOnly() { + return isReadOnly; + } + + /** + * @param isReadOnly + */ + public void setReadOnly(boolean isReadOnly) { + this.isReadOnly = isReadOnly; + } + + /** + * @return the known status + */ + public TskData.FileKnown getFileKnownStatus() { + return fileKnownStatus; + } + + /** + * @param knownStatus the known status to set + */ + public void setFileKnownStatus(TskData.FileKnown fileKnownStatus) { + this.fileKnownStatus = fileKnownStatus; + } /** * @return the importDate diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java index 461a499663..6179a58342 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java @@ -370,6 +370,8 @@ public final class PostgresEamDbSettings { createReferenceSetsTable.append("org_id integer NOT NULL,"); createReferenceSetsTable.append("set_name text NOT NULL,"); createReferenceSetsTable.append("version text NOT NULL,"); + createReferenceSetsTable.append("known_status integer NOT NULL,"); + createReferenceSetsTable.append("read_only boolean NOT NULL,"); createReferenceSetsTable.append("import_date text NOT NULL,"); createReferenceSetsTable.append("foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL,"); createReferenceSetsTable.append("CONSTRAINT hash_set_unique UNIQUE (set_name, version)"); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java index 5890dd2a67..719a58385b 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java @@ -635,6 +635,55 @@ public class SqliteEamDb extends AbstractSqlEamDb { } } + /** + * Remove a reference set and all values contained in it. + * @param referenceSetID + * @throws EamDbException + */ + @Override + public void deleteReferenceSet(int referenceSetID) throws EamDbException{ + try{ + acquireExclusiveLock(); + super.deleteReferenceSet(referenceSetID); + } finally { + releaseExclusiveLock(); + } + } + + /** + * Check if the given hash is in a specific reference set + * @param hash + * @param referenceSetID + * @return true if the hash is found in the reference set + */ + @Override + public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException { + try{ + acquireSharedLock(); + return super.isValueInReferenceSet(value, referenceSetID, correlationTypeID); + } finally { + releaseSharedLock(); + } + } + + /** + * Check whether a reference set with the given name/version is in the central repo. + * Used to check for name collisions when creating reference sets. + * @param referenceSetName + * @param version + * @return true if a matching set is found + * @throws EamDbException + */ + @Override + public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException { + try{ + acquireSharedLock(); + return super.referenceSetExists(referenceSetName, version); + } finally { + releaseSharedLock(); + } + } + /** * Is the artifact known as bad according to the reference entries? * @@ -644,10 +693,10 @@ public class SqliteEamDb extends AbstractSqlEamDb { * @return Global known status of the artifact */ @Override - public boolean isArtifactlKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException { + public boolean isArtifactKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException { try{ acquireSharedLock(); - return super.isArtifactlKnownBadByReference(aType, value); + return super.isArtifactKnownBadByReference(aType, value); } finally { releaseSharedLock(); } @@ -737,10 +786,10 @@ public class SqliteEamDb extends AbstractSqlEamDb { * @throws EamDbException */ @Override - public int newReferencelSet(EamGlobalSet eamGlobalSet) throws EamDbException { + public int newReferenceSet(EamGlobalSet eamGlobalSet) throws EamDbException { try{ acquireExclusiveLock(); - return super.newReferencelSet(eamGlobalSet); + return super.newReferenceSet(eamGlobalSet); } finally { releaseExclusiveLock(); } @@ -765,6 +814,23 @@ public class SqliteEamDb extends AbstractSqlEamDb { } } + /** + * Get all reference sets + * + * @return List of all reference sets in the central repository + * + * @throws EamDbException + */ + @Override + public List getAllReferenceSets() throws EamDbException{ + try{ + acquireSharedLock(); + return super.getAllReferenceSets(); + } finally { + releaseSharedLock(); + } + } + /** * Add a new reference instance * @@ -782,7 +848,7 @@ public class SqliteEamDb extends AbstractSqlEamDb { } finally { releaseExclusiveLock(); } - } + } /** * Insert the bulk collection of Reference Type Instances diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java index 6deb5145e8..fa50118924 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java @@ -311,6 +311,8 @@ public final class SqliteEamDbSettings { createReferenceSetsTable.append("org_id integer NOT NULL,"); createReferenceSetsTable.append("set_name text NOT NULL,"); createReferenceSetsTable.append("version text NOT NULL,"); + createReferenceSetsTable.append("known_status integer NOT NULL,"); + createReferenceSetsTable.append("read_only boolean NOT NULL,"); createReferenceSetsTable.append("import_date text NOT NULL,"); createReferenceSetsTable.append("foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL,"); createReferenceSetsTable.append("CONSTRAINT hash_set_unique UNIQUE (set_name, version)"); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index 31d989d74a..30d374f133 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -121,16 +121,6 @@ class IngestModule implements FileIngestModule { } } - // Make a TSK_HASHSET_HIT blackboard artifact for global notable files - try { - if (dbManager.isArtifactlKnownBadByReference(filesType, md5)) { - postCorrelatedHashHitToBlackboard(af); - } - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error retrieving global known status.", ex); // NON-NLS - return ProcessResult.ERROR; - } - try { CorrelationAttribute eamArtifact = new CorrelationAttribute(filesType, md5); CorrelationAttributeInstance cefi = new CorrelationAttributeInstance( @@ -307,33 +297,6 @@ class IngestModule implements FileIngestModule { } } - private void postCorrelatedHashHitToBlackboard(AbstractFile abstractFile) { - try { - String MODULE_NAME = IngestModuleFactory.getModuleName(); - BlackboardArtifact tifArtifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT); - BlackboardAttribute att = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, - Bundle.IngestModule_prevCaseComment_text()); - tifArtifact.addAttribute(att); - - try { - // index the artifact for keyword search - blackboard.indexArtifact(tifArtifact); - } catch (Blackboard.BlackboardException ex) { - LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS - } - - // send inbox message - sendBadFileInboxMessage(tifArtifact, abstractFile.getName(), abstractFile.getMd5Hash()); - - // fire event to notify UI of this new artifact - services.fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT)); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS - } catch (IllegalStateException ex) { - LOGGER.log(Level.SEVERE, "Failed to create BlackboardAttribute.", ex); // NON-NLS - } - } - /** * Post a message to the ingest inbox alerting the user that a bad file was * found. diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties old mode 100755 new mode 100644 index 7ab2c9b2e4..b9ab823b1d --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties @@ -19,20 +19,8 @@ EamSqliteSettingsDialog.tfDatabasePath.text= EamSqliteSettingsDialog.lbDatabasePath.text=Database Path : ImportHashDatabaseDialog.tfDatabaseName.tooltip=Name for this database ImportHashDatabaseDialog.tfDatabaseVersion.tooltip.text=Database Version Number -ImportHashDatabaseDialog.knownRadioButton.text=Known (NSRL or other) -ImportHashDatabaseDialog.openButton.text=Open... -ImportHashDatabaseDialog.cancelButton.text=Cancel -ImportHashDatabaseDialog.lbDatabaseVersion.text=Database Version: -ImportHashDatabaseDialog.okButton.text=OK -ImportHashDatabaseDialog.lbDatabaseName.text=Database Name: -ImportHashDatabaseDialog.lbSourceOrganization.text=Source Organization: -ImportHashDatabaseDialog.lbDatabaseAttribution.text=Database Attribution: -ImportHashDatabaseDialog.lbDatabaseType.text=Type of database: -ImportHashDatabaseDialog.knownBadRadioButton.text=Notable -ImportHashDatabaseDialog.bnNewOrganization.text=Add New Organization ImportHashDatabaseDialog.tfDatabaseName.tooltip=Name for this database ImportHashDatabaseDialog.tfDatabaseVersion.tooltip.text=Database Version Number -GlobalSettingsPanel.bnImportDatabase.actionCommand= GlobalSettingsPanel.bnManageTags.actionCommand= GlobalSettingsPanel.bnManageTags.toolTipText= GlobalSettingsPanel.bnManageTags.text=Manage Tags @@ -71,8 +59,5 @@ ManageCorrelationPropertiesDialog.lbWarningMsg.text=Warning Message ManageCorrelationPropertiesDialog.cancelButton.text=Cancel ManageCorrelationPropertiesDialog.okButton.text=OK GlobalSettingsPanel.bnManageProperties.text=Manage Correlation Properties -ImportHashDatabaseDialog.lbInstructions.text=Choose an .idx file to import into the central repository. -ImportHashDatabaseDialog.lbFilePath.text=File Path: -ImportHashDatabaseDialog.tfFilePath.text= EamDbSettingsDialog.lbDatabaseDesc.text=Database File: EamDbSettingsDialog.lbFullDbPath.text= diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form index 49d525511b..731c177818 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form @@ -31,7 +31,6 @@ - @@ -55,9 +54,7 @@ - - - + @@ -177,22 +174,6 @@ - - - - - - - - - - - - - - - - @@ -415,7 +396,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java index 58eb9fbe40..37d18036d8 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java @@ -71,9 +71,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i private void customizeComponents() { setName(Bundle.GlobalSettingsPanel_title()); - - // The hash set functions of central repo are not being included in the current release. - bnImportDatabase.setVisible(false); } private void addIngestJobEventsListener() { @@ -99,7 +96,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i lbDbNameValue = new javax.swing.JLabel(); lbDbLocationValue = new javax.swing.JLabel(); cbUseCentralRepo = new javax.swing.JCheckBox(); - bnImportDatabase = new javax.swing.JButton(); pnTagManagement = new javax.swing.JPanel(); bnManageTags = new javax.swing.JButton(); manageTagsScrollPane = new javax.swing.JScrollPane(); @@ -180,15 +176,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i } }); - bnImportDatabase.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/centralrepository/images/import16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(bnImportDatabase, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.bnImportDatabase.label")); // NOI18N - bnImportDatabase.setActionCommand(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.bnImportDatabase.actionCommand")); // NOI18N - bnImportDatabase.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnImportDatabaseActionPerformed(evt); - } - }); - pnTagManagement.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnTagManagement.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N pnTagManagement.setPreferredSize(new java.awt.Dimension(674, 97)); @@ -353,8 +340,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i .addComponent(pnCorrelationProperties, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(pnTagManagement, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(cbUseCentralRepo, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 186, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(bnImportDatabase, javax.swing.GroupLayout.Alignment.LEADING)) + .addComponent(cbUseCentralRepo, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 186, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()))) ); layout.setVerticalGroup( @@ -373,20 +359,12 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i .addComponent(organizationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0) .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(bnImportDatabase) - .addContainerGap()) + .addGap(36, 36, 36)) ); pnTagManagement.getAccessibleContext().setAccessibleName(""); }// //GEN-END:initComponents - private void bnImportDatabaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnImportDatabaseActionPerformed - store(); - ImportHashDatabaseDialog dialog = new ImportHashDatabaseDialog(); - firePropertyChange(OptionsPanelController.PROP_VALID, null, null); - }//GEN-LAST:event_bnImportDatabaseActionPerformed - private void bnManageTagsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageTagsActionPerformed store(); ManageTagsDialog dialog = new ManageTagsDialog(); @@ -567,7 +545,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i pnCorrelationProperties.setEnabled(enable && !ingestRunning); pnTagManagement.setEnabled(enable && !ingestRunning); bnManageTypes.setEnabled(enable && !ingestRunning); - bnImportDatabase.setEnabled(enable && !ingestRunning); bnManageTags.setEnabled(enable && !ingestRunning); manageTagsTextArea.setEnabled(enable && !ingestRunning); correlationPropertiesTextArea.setEnabled(enable && !ingestRunning); @@ -579,7 +556,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton bnDbConfigure; - private javax.swing.JButton bnImportDatabase; private javax.swing.JButton bnManageTags; private javax.swing.JButton bnManageTypes; private javax.swing.JCheckBox cbUseCentralRepo; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.form deleted file mode 100755 index 0865173651..0000000000 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.form +++ /dev/null @@ -1,316 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.java deleted file mode 100755 index e041f87a03..0000000000 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.java +++ /dev/null @@ -1,686 +0,0 @@ -/* - * Central Repository - * - * Copyright 2015-2017 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.centralrepository.optionspanel; - -import java.awt.Dimension; -import java.awt.Toolkit; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.net.UnknownHostException; -import java.nio.file.Files; -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.logging.Level; -import javax.swing.JComboBox; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JOptionPane; -import javax.swing.JTextField; -import javax.swing.SwingUtilities; -import javax.swing.SwingWorker; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.filechooser.FileNameExtensionFilter; -import org.netbeans.api.progress.ProgressHandle; -import org.netbeans.spi.options.OptionsPanelController; -import org.openide.util.Exceptions; -import org.openide.util.NbBundle; -import org.openide.util.NbBundle.Messages; -import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.ModuleSettings; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalFileInstance; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalSet; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.datamodel.TskData; - -/** - * Instances of this class allow a user to select an existing hash database and - * add it to the set of hash databases used to classify files as unknown, known, - * or notable. - */ -final class ImportHashDatabaseDialog extends javax.swing.JDialog { - private static final Logger LOGGER = Logger.getLogger(ImportHashDatabaseDialog.class.getName()); - - private final JFileChooser fileChooser = new JFileChooser(); - private final static String LAST_FILE_PATH_KEY = "CentralRepositoryImport_Path"; // NON-NLS - private final int HASH_IMPORT_THRESHOLD = 10000; - private EamOrganization selectedOrg = null; - private List orgs = null; - private final Collection textBoxes; - private final TextBoxChangedListener textBoxChangedListener; - - - /** - * Displays a dialog that allows a user to select an existing hash database - * and add it to the set of hash databases used to classify files as - * unknown, known, or notable. - */ - @Messages({"ImportHashDatabaseDialog.importHashDbMsg=Import Hash Database"}) - ImportHashDatabaseDialog() { - super((JFrame) WindowManager.getDefault().getMainWindow(), - Bundle.ImportHashDatabaseDialog_importHashDbMsg(), - true); // NON-NLS - textBoxes = new ArrayList<>(); - textBoxChangedListener = new TextBoxChangedListener(); - initFileChooser(); - initComponents(); - customizeComponents(); - display(); - } - - @Messages({"ImportHashDatabaseDialog.fileNameExtFilter.text=Hash Database File",}) - private void initFileChooser() { - fileChooser.setDragEnabled(false); - fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - String[] EXTENSION = new String[]{"idx"}; //NON-NLS - FileNameExtensionFilter filter = new FileNameExtensionFilter( - Bundle.ImportHashDatabaseDialog_fileNameExtFilter_text(), - EXTENSION); // NON-NLS - fileChooser.setFileFilter(filter); - fileChooser.setMultiSelectionEnabled(false); - - if (ModuleSettings.settingExists(ModuleSettings.MAIN_SETTINGS, LAST_FILE_PATH_KEY)) { - String lastBaseDirectory = ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, LAST_FILE_PATH_KEY); - File hashDbFolder = new File(lastBaseDirectory); - if(hashDbFolder.exists()){ - fileChooser.setCurrentDirectory(hashDbFolder); - } - } - } - - private void customizeComponents() { - populateCombobox(); - setTextBoxListeners(); - enableOkButton(false); - } - - /** - * Register for notifications when the text boxes get updated. - */ - private void setTextBoxListeners() { - textBoxes.add(tfFilePath); - textBoxes.add(tfDatabaseName); - textBoxes.add(tfDatabaseVersion); - addDocumentListeners(textBoxes, textBoxChangedListener); - } - - private void populateCombobox() { - comboboxSourceOrganization.removeAllItems(); - try { - EamDb dbManager = EamDb.getInstance(); - orgs = dbManager.getOrganizations(); - orgs.forEach((org) -> { - comboboxSourceOrganization.addItem(org.getName()); - }); - if (!orgs.isEmpty()) { - selectedOrg = orgs.get(0); - } - valid(); - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Failure populating combobox with organizations.", ex); - } - } - - /** - * Adds a change listener to a collection of text fields. - * - * @param textFields The text fields. - * @param listener The change listener. - */ - private static void addDocumentListeners(Collection textFields, TextBoxChangedListener listener) { - textFields.forEach((textField) -> { - textField.getDocument().addDocumentListener(listener); - }); - } - - /** - * Tests whether or not values have been entered in all of the required - * text fields. - * - * @return True or false. - */ - private boolean textFieldsArePopulated() { - return !tfDatabaseName.getText().trim().isEmpty() - && !tfDatabaseVersion.getText().trim().isEmpty() - && !tfFilePath.getText().trim().isEmpty(); - } - - /** - * Tests whether or not all of the settings components are populated. - * - * @return True or false. - */ - @Messages({"ImportHashDatabaseDialog.validation.incompleteFields=Fill in all values"}) - private boolean checkFields() { - boolean result = true; - - boolean allPopulated = textFieldsArePopulated(); - - if (!allPopulated) { - // We don't even have everything filled out - result = false; - lbWarningMsg.setText(Bundle.ImportHashDatabaseDialog_validation_incompleteFields()); - } - return result; - } - - /** - * Validates that the form is filled out correctly for our usage. - * - * @return true if it's okay, false otherwise. - */ - @Messages({"ImportHashDatabaseDialog.validation.notEnabled=Central Repository is not enabled."}) - public boolean valid() { - lbWarningMsg.setText(""); - if (!EamDb.isEnabled()) { - lbWarningMsg.setText(Bundle.ImportHashDatabaseDialog_validation_notEnabled()); - return false; - } - - return enableOkButton(checkFields() && null != selectedOrg); - } - - /** - * Enables the "OK" button to create the Global File Set and insert the instances. - * - * @param enable - * - * @return True or False - */ - private boolean enableOkButton(Boolean enable) { - okButton.setEnabled(enable); - return enable; - } - - /** - * Used to listen for changes in text boxes. It lets the panel know things - * have been updated and that validation needs to happen. - */ - private class TextBoxChangedListener implements DocumentListener { - - @Override - public void changedUpdate(DocumentEvent e) { - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - valid(); - } - - @Override - public void insertUpdate(DocumentEvent e) { - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - valid(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - valid(); - } - } - - private void display() { - Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); - setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2); - setVisible(true); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - buttonGroup1 = new javax.swing.ButtonGroup(); - okButton = new javax.swing.JButton(); - cancelButton = new javax.swing.JButton(); - tfFilePath = new javax.swing.JTextField(); - openButton = new javax.swing.JButton(); - knownRadioButton = new javax.swing.JRadioButton(); - knownBadRadioButton = new javax.swing.JRadioButton(); - lbDatabaseType = new javax.swing.JLabel(); - lbDatabasePath = new javax.swing.JLabel(); - lbDatabaseAttribution = new javax.swing.JLabel(); - lbSourceOrganization = new javax.swing.JLabel(); - lbDatabaseName = new javax.swing.JLabel(); - lbDatabaseVersion = new javax.swing.JLabel(); - comboboxSourceOrganization = new javax.swing.JComboBox<>(); - tfDatabaseName = new javax.swing.JTextField(); - tfDatabaseVersion = new javax.swing.JTextField(); - bnNewOrganization = new javax.swing.JButton(); - lbWarningMsg = new javax.swing.JLabel(); - lbInstructions = new javax.swing.JLabel(); - - setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - - org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.okButton.text")); // NOI18N - okButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - okButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.cancelButton.text")); // NOI18N - cancelButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - cancelButtonActionPerformed(evt); - } - }); - - tfFilePath.setText(org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.tfFilePath.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(openButton, org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.openButton.text")); // NOI18N - openButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - openButtonActionPerformed(evt); - } - }); - - buttonGroup1.add(knownRadioButton); - org.openide.awt.Mnemonics.setLocalizedText(knownRadioButton, org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.knownRadioButton.text")); // NOI18N - - buttonGroup1.add(knownBadRadioButton); - knownBadRadioButton.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(knownBadRadioButton, org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.knownBadRadioButton.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbDatabaseType, org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.lbDatabaseType.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbDatabasePath, org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.lbFilePath.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbDatabaseAttribution, org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.lbDatabaseAttribution.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbSourceOrganization, org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.lbSourceOrganization.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbDatabaseName, org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.lbDatabaseName.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(lbDatabaseVersion, org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.lbDatabaseVersion.text")); // NOI18N - - comboboxSourceOrganization.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); - comboboxSourceOrganization.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - comboboxSourceOrganizationActionPerformed(evt); - } - }); - - tfDatabaseName.setToolTipText(org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.tfDatabaseName.tooltip")); // NOI18N - - tfDatabaseVersion.setToolTipText(org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.tfDatabaseVersion.tooltip.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(bnNewOrganization, org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.bnNewOrganization.text")); // NOI18N - bnNewOrganization.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnNewOrganizationActionPerformed(evt); - } - }); - - lbWarningMsg.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N - lbWarningMsg.setForeground(new java.awt.Color(255, 0, 0)); - - lbInstructions.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(lbInstructions, org.openide.util.NbBundle.getMessage(ImportHashDatabaseDialog.class, "ImportHashDatabaseDialog.lbInstructions.text")); // NOI18N - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); - getContentPane().setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbInstructions, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(okButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cancelButton)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(lbDatabasePath) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(tfFilePath)) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGap(23, 23, 23) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(lbDatabaseVersion) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(tfDatabaseVersion, javax.swing.GroupLayout.PREFERRED_SIZE, 154, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)) - .addGroup(layout.createSequentialGroup() - .addComponent(lbSourceOrganization) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(bnNewOrganization)) - .addGroup(layout.createSequentialGroup() - .addComponent(lbDatabaseName) - .addGap(12, 12, 12) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(comboboxSourceOrganization, javax.swing.GroupLayout.Alignment.TRAILING, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(tfDatabaseName)))))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(openButton)) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbDatabaseType) - .addGroup(layout.createSequentialGroup() - .addGap(19, 19, 19) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(knownRadioButton) - .addComponent(knownBadRadioButton))) - .addComponent(lbDatabaseAttribution)) - .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(lbWarningMsg, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) - ); - - layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, okButton}); - - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addComponent(lbInstructions, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(openButton) - .addComponent(tfFilePath, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbDatabasePath)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lbDatabaseType) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(knownRadioButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(knownBadRadioButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(lbDatabaseAttribution) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(bnNewOrganization) - .addGroup(layout.createSequentialGroup() - .addGap(3, 3, 3) - .addComponent(lbSourceOrganization, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(comboboxSourceOrganization, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(tfDatabaseName) - .addComponent(lbDatabaseName, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lbDatabaseVersion, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(tfDatabaseVersion, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lbWarningMsg, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(44, Short.MAX_VALUE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(okButton) - .addComponent(cancelButton)) - .addContainerGap()))) - ); - - pack(); - }// //GEN-END:initComponents - - @Messages({"ImportHashDatabaseDialog.failedToGetDbPathMsg=Failed to get the path of the selected database.",}) - private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed - if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { - File databaseFile = fileChooser.getSelectedFile(); - try { - tfFilePath.setText(databaseFile.getCanonicalPath()); - if (databaseFile.getName().toLowerCase().contains("nsrl")) { //NON-NLS - knownRadioButton.setSelected(true); - } - ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, LAST_FILE_PATH_KEY, databaseFile.getParent()); - } catch (IOException ex) { - Logger.getLogger(ImportHashDatabaseDialog.class.getName()).log(Level.SEVERE, "Failed to get path of selected database", ex); // NON-NLS - lbWarningMsg.setText(Bundle.ImportHashDatabaseDialog_failedToGetDbPathMsg()); - } - } - valid(); - }//GEN-LAST:event_openButtonActionPerformed - - private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed - dispose(); - }//GEN-LAST:event_cancelButtonActionPerformed - - /** - * Create the new global set and return the ID number - * - * @return ID number of new global set - * @throws EamDbException - */ - private int createGlobalSet() throws EamDbException { - EamDb dbManager = EamDb.getInstance(); - EamGlobalSet eamGlobalSet = new EamGlobalSet( - selectedOrg.getOrgID(), - tfDatabaseName.getText().trim(), - tfDatabaseVersion.getText().trim(), - LocalDate.now()); - return dbManager.newReferencelSet(eamGlobalSet); - } - - @Messages({"ImportHashDatabaseDialog.createGlobalSet.failedMsg.text=Failed to store attribution details.", - "ImportHashDatabaseDialog.mustSelectHashDbFilePathMsg=Missing hash database file path.", - "ImportHashDatabaseDialog.hashDbDoesNotExistMsg=The selected hash database does not exist.", - "# {0} - selected file path", - "ImportHashDatabaseDialog.errorMessage.failedToOpenHashDbMsg=Failed to open hash database at {0}.", -}) - private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - // Note that the error handlers in this method call return without disposing of the - // dialog to allow the user to try again, if desired. - String selectedFilePath = tfFilePath.getText(); - - // have valid file path - if (selectedFilePath.isEmpty()) { - lbWarningMsg.setText(Bundle.ImportHashDatabaseDialog_mustSelectHashDbFilePathMsg()); - return; - } - File file = new File(selectedFilePath); - if (!file.exists()) { - lbWarningMsg.setText(Bundle.ImportHashDatabaseDialog_hashDbDoesNotExistMsg()); - return; - } - - // create global set - int globalSetID; - try { - globalSetID = createGlobalSet(); - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Failed to create global set.", ex); - lbWarningMsg.setText(Bundle.ImportHashDatabaseDialog_createGlobalSet_failedMsg_text()); - return; - } - - // insert hashes - TskData.FileKnown knownStatus = TskData.FileKnown.UNKNOWN; - if (knownRadioButton.isSelected()) { - knownStatus = TskData.FileKnown.KNOWN; - } else if (knownBadRadioButton.isSelected()) { - knownStatus = TskData.FileKnown.BAD; - } - - String errorMessage = Bundle.ImportHashDatabaseDialog_errorMessage_failedToOpenHashDbMsg(selectedFilePath); - // Future, make UI handle more than the "FILES" type. - try { - EamDb dbManager = EamDb.getInstance(); - CorrelationAttribute.Type contentType = dbManager.getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID); // get "FILES" type - // run in the background and close dialog - SwingUtilities.invokeLater(new ImportHashDatabaseWorker(selectedFilePath, knownStatus, globalSetID, contentType)::execute); - dispose(); - } catch (EamDbException | UnknownHostException ex) { - Logger.getLogger(ImportHashDatabaseDialog.class.getName()).log(Level.SEVERE, errorMessage, ex); - lbWarningMsg.setText(ex.getMessage()); - } - - }//GEN-LAST:event_okButtonActionPerformed - - @SuppressWarnings({"unchecked"}) - private void bnNewOrganizationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnNewOrganizationActionPerformed - AddNewOrganizationDialog dialogO = new AddNewOrganizationDialog(); - // update the combobox options - if (dialogO.isChanged()) { - populateCombobox(); - } - }//GEN-LAST:event_bnNewOrganizationActionPerformed - - @SuppressWarnings({"unchecked"}) - private void comboboxSourceOrganizationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_comboboxSourceOrganizationActionPerformed - JComboBox cb = (JComboBox)evt.getSource(); - String orgName = (String)cb.getSelectedItem(); - if (null == orgName) return; - - for (EamOrganization org : orgs) { - if (org.getName().equals(orgName)) { - selectedOrg = org; - return; - } - } - valid(); - }//GEN-LAST:event_comboboxSourceOrganizationActionPerformed - - @NbBundle.Messages({"ImportHashDatabaseDialog.ImportHashDatabaseWorker.displayName=Importing Hash Database"}) - private class ImportHashDatabaseWorker extends SwingWorker { - - private final File file; - private final TskData.FileKnown knownStatus; - private final int globalSetID; - private final ProgressHandle progress; - private final CorrelationAttribute.Type contentType; - - public ImportHashDatabaseWorker(String filename, TskData.FileKnown knownStatus, int globalSetID, CorrelationAttribute.Type contentType) throws EamDbException, UnknownHostException { - this.file = new File(filename); - this.knownStatus = knownStatus; - this.globalSetID = globalSetID; - this.contentType = contentType; - this.progress = ProgressHandle.createHandle(Bundle.ImportHashDatabaseDialog_ImportHashDatabaseWorker_displayName()); - - if (!EamDb.isEnabled()) { - throw new EamDbException("Central repository database is not enabled."); // NON-NLS - } - } - - @Override - protected Void doInBackground() throws Exception { - importHashDatabase(); - return null; - } - - @Override - @Messages({"ImportHashDatabaseDialog.ImportHashDatabaseWorker.error=Failed to import hash database."}) - protected void done() { - progress.finish(); - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - Logger.getLogger(ImportHashDatabaseDialog.class.getName()).log(Level.SEVERE, Bundle.ImportHashDatabaseDialog_ImportHashDatabaseWorker_error(), ex); - MessageNotifyUtil.Notify.show(Bundle.ImportHashDatabaseDialog_ImportHashDatabaseWorker_error(), - ex.getMessage(), - MessageNotifyUtil.MessageType.ERROR); - } - } - - private long numberOfLinesInFile(File f) throws IOException { - return Files.lines(f.toPath()).count(); - } - - @Messages({"# {0} - value content", - "ImportHashDatabaseDialog.ImportHashDatabaseWorker.duplicate=Duplicate value {0} found in import file."}) - private void importHashDatabase() throws EamDbException, IOException { - BufferedReader reader = new BufferedReader(new FileReader(file)); - String line; - EamDb dbManager = EamDb.getInstance(); - Set globalInstances = new HashSet<>(); - - long totalLines = numberOfLinesInFile(file); - if (totalLines <= Integer.MAX_VALUE) { - progress.start((int) totalLines); - } else { - progress.start(); - } - - int numLines = 0; - LOGGER.log(Level.INFO, "Importing hash database {0}", file.getName()); - while ((line = reader.readLine()) != null) { - progress.progress(++numLines); - - String[] parts = line.split("\\|"); - - // Header lines start with a 41 character dummy hash, 1 character longer than a SHA-1 hash - if (parts.length != 2 || parts[0].length() == 41) { - continue; - } - - EamGlobalFileInstance eamGlobalFileInstance = new EamGlobalFileInstance( - globalSetID, - parts[0].toLowerCase(), - knownStatus, - ""); - - globalInstances.add(eamGlobalFileInstance); - - if(numLines % HASH_IMPORT_THRESHOLD == 0){ - dbManager.bulkInsertReferenceTypeEntries(globalInstances, contentType); - globalInstances.clear(); - } - } - - dbManager.bulkInsertReferenceTypeEntries(globalInstances, contentType); - LOGGER.log(Level.INFO, "Finished importing hash database. Total entries: {0}", numLines); - - } - } - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton bnNewOrganization; - private javax.swing.ButtonGroup buttonGroup1; - private javax.swing.JButton cancelButton; - private javax.swing.JComboBox comboboxSourceOrganization; - private javax.swing.JRadioButton knownBadRadioButton; - private javax.swing.JRadioButton knownRadioButton; - private javax.swing.JLabel lbDatabaseAttribution; - private javax.swing.JLabel lbDatabaseName; - private javax.swing.JLabel lbDatabasePath; - private javax.swing.JLabel lbDatabaseType; - private javax.swing.JLabel lbDatabaseVersion; - private javax.swing.JLabel lbInstructions; - private javax.swing.JLabel lbSourceOrganization; - private javax.swing.JLabel lbWarningMsg; - private javax.swing.JButton okButton; - private javax.swing.JButton openButton; - private javax.swing.JTextField tfDatabaseName; - private javax.swing.JTextField tfDatabaseVersion; - private javax.swing.JTextField tfFilePath; - // End of variables declaration//GEN-END:variables -} diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index b0f8eba6c3..e802f9f9f5 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -211,3 +211,26 @@ HashLookupSettingsPanel.hashDatabasesLabel.text=Hash Databases: HashLookupSettingsPanel.importDatabaseButton.toolTipText= HashLookupSettingsPanel.importDatabaseButton.text=Import database HashLookupSettingsPanel.deleteDatabaseButton.text=Delete database +ImportHashDatabaseDialog.lbFilePath.text=Database Path: +ImportHashDatabaseDialog.tfDatabaseName.tooltip=Name for this database +ImportHashDatabaseDialog.tfDatabaseVersion.tooltip.text=Database Version Number +ImportHashDatabaseDialog.tfDatabaseName.tooltip=Name for this database +ImportHashDatabaseDialog.tfDatabaseVersion.tooltip.text=Database Version Number +ImportCentralRepoDbProgressDialog.lbProgress.text=Starting import... +ImportCentralRepoDbProgressDialog.bnOk.text=OK +ImportCentralRepoDbProgressDialog.bnCancel.text=Cancel +HashLookupSettingsPanel.versionLabel.text_1=Version: +HashLookupSettingsPanel.hashDbVersionLabel.text_1=No database selected +HashLookupSettingsPanel.orgLabel.text_1=Organization: +HashLookupSettingsPanel.hashDbOrgLabel.text_1=No database selected +HashLookupSettingsPanel.readOnlyLabel.text_1=Read only: +HashLookupSettingsPanel.hashDbReadOnlyLabel.text_1=No database selected +ImportCentralRepoDbProgressDialog.jLabel1.text=Importing hash set into the central repository +HashDbImportDatabaseDialog.lbVersion.text=Version: +HashDbImportDatabaseDialog.lbOrg.text=Source Organization: +HashDbImportDatabaseDialog.readOnlyCheckbox.text=Make database read-only +HashDbImportDatabaseDialog.orgButton.text=Manage Organizations +HashDbImportDatabaseDialog.versionTextField.text= +HashDbImportDatabaseDialog.fileTypeRadioButton.text=File Type +HashDbImportDatabaseDialog.centralRepoRadioButton.text=Central Repository +HashDbImportDatabaseDialog.jLabel4.text=Type: diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form index 088b0001f4..9a3c6acf89 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form @@ -4,6 +4,8 @@ + + @@ -30,23 +32,46 @@ - - + + - + - - + + - + + + - + + + + + + + + + + + + + + + - + + + + + + + + @@ -63,6 +88,7 @@ + @@ -74,6 +100,12 @@ + + + + + + @@ -85,27 +117,33 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -215,5 +253,91 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index e3d49d534d..c281e81db9 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -23,7 +23,9 @@ import java.awt.Toolkit; import java.io.File; import java.io.IOException; import java.nio.file.Paths; +import java.util.List; import java.util.logging.Level; +import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; @@ -31,12 +33,16 @@ import javax.swing.filechooser.FileNameExtensionFilter; import org.apache.commons.io.FilenameUtils; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; +import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDbManagerException; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Instances of this class allow a user to select an existing hash database and @@ -49,6 +55,8 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private String selectedFilePath = ""; private HashDb selectedHashDb = null; private final static String LAST_FILE_PATH_KEY = "HashDbImport_Path"; + private EamOrganization selectedOrg = null; + private List orgs = null; /** * Displays a dialog that allows a user to select an existing hash database @@ -59,8 +67,9 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { super((JFrame) WindowManager.getDefault().getMainWindow(), NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.importHashDbMsg"), true); - initFileChooser(); initComponents(); + enableComponents(); + initFileChooser(); display(); } @@ -76,12 +85,25 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private void initFileChooser() { fileChooser.setDragEnabled(false); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - String[] EXTENSION = new String[]{"txt", "kdb", "idx", "hash", "Hash", "hsh"}; //NON-NLS - FileNameExtensionFilter filter = new FileNameExtensionFilter( - NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.fileNameExtFilter.text"), EXTENSION); - fileChooser.setFileFilter(filter); + updateFileChooserFilter(); fileChooser.setMultiSelectionEnabled(false); } + + @NbBundle.Messages({"HashDbImportDatabaseDialog.centralRepoExtFilter.text=Hash Database File (.idx only)"}) + private void updateFileChooserFilter() { + fileChooser.resetChoosableFileFilters(); + if(centralRepoRadioButton.isSelected()){ + String[] EXTENSION = new String[]{"idx"}; //NON-NLS + FileNameExtensionFilter filter = new FileNameExtensionFilter( + NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.centralRepoExtFilter.text"), EXTENSION); + fileChooser.setFileFilter(filter); + } else { + String[] EXTENSION = new String[]{"txt", "kdb", "idx", "hash", "Hash", "hsh"}; //NON-NLS + FileNameExtensionFilter filter = new FileNameExtensionFilter( + NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.fileNameExtFilter.text"), EXTENSION); + fileChooser.setFileFilter(filter); + } + } private void display() { Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); @@ -96,6 +118,45 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { } return shortenedPath; } + + private void enableComponents(){ + + + if(! EamDb.isEnabled()){ + centralRepoRadioButton.setEnabled(false); + fileTypeRadioButton.setSelected(true); + } else { + populateCombobox(); + } + + boolean isFileType = fileTypeRadioButton.isSelected(); + + // Central repo only + lbVersion.setEnabled(! isFileType); + versionTextField.setEnabled(! isFileType); + lbOrg.setEnabled(! isFileType); + orgButton.setEnabled(! isFileType); + orgComboBox.setEnabled(! isFileType); + readOnlyCheckbox.setEnabled(! isFileType); + } + + @NbBundle.Messages({"HashDbImportDatabaseDialog.populateOrgsError.message=Failure loading organizations."}) + private void populateCombobox() { + orgComboBox.removeAllItems(); + try { + EamDb dbManager = EamDb.getInstance(); + orgs = dbManager.getOrganizations(); + orgs.forEach((org) -> { + orgComboBox.addItem(org.getName()); + }); + if (!orgs.isEmpty()) { + selectedOrg = orgs.get(0); + } + } catch (EamDbException ex) { + JOptionPane.showMessageDialog(null, Bundle.HashDbImportDatabaseDialog_populateOrgsError_message()); + Logger.getLogger(ImportCentralRepoDbProgressDialog.class.getName()).log(Level.SEVERE, "Failure loading organizations", ex); + } + } /** * This method is called from within the constructor to initialize the form. @@ -107,6 +168,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private void initComponents() { buttonGroup1 = new javax.swing.ButtonGroup(); + storageTypeButtonGroup = new javax.swing.ButtonGroup(); okButton = new javax.swing.JButton(); cancelButton = new javax.swing.JButton(); databasePathTextField = new javax.swing.JTextField(); @@ -118,6 +180,15 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { jLabel2 = new javax.swing.JLabel(); sendIngestMessagesCheckbox = new javax.swing.JCheckBox(); jLabel3 = new javax.swing.JLabel(); + lbVersion = new javax.swing.JLabel(); + versionTextField = new javax.swing.JTextField(); + lbOrg = new javax.swing.JLabel(); + orgComboBox = new javax.swing.JComboBox<>(); + orgButton = new javax.swing.JButton(); + readOnlyCheckbox = new javax.swing.JCheckBox(); + fileTypeRadioButton = new javax.swing.JRadioButton(); + centralRepoRadioButton = new javax.swing.JRadioButton(); + jLabel4 = new javax.swing.JLabel(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); @@ -178,6 +249,47 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.jLabel3.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(lbVersion, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.lbVersion.text")); // NOI18N + + versionTextField.setText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.versionTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(lbOrg, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.lbOrg.text")); // NOI18N + + orgComboBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + orgComboBoxActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(orgButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.orgButton.text")); // NOI18N + orgButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + orgButtonActionPerformed(evt); + } + }); + + readOnlyCheckbox.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(readOnlyCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.readOnlyCheckbox.text")); // NOI18N + + storageTypeButtonGroup.add(fileTypeRadioButton); + fileTypeRadioButton.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(fileTypeRadioButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.fileTypeRadioButton.text")); // NOI18N + fileTypeRadioButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + fileTypeRadioButtonActionPerformed(evt); + } + }); + + storageTypeButtonGroup.add(centralRepoRadioButton); + org.openide.awt.Mnemonics.setLocalizedText(centralRepoRadioButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.centralRepoRadioButton.text")); // NOI18N + centralRepoRadioButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + centralRepoRadioButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.jLabel4.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( @@ -186,20 +298,37 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) + .addGap(0, 325, Short.MAX_VALUE) .addComponent(okButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(cancelButton)) - .addGroup(layout.createSequentialGroup() + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(jLabel1) + .addGroup(layout.createSequentialGroup() + .addComponent(lbOrg) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(hashSetNameTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 303, Short.MAX_VALUE)) + .addComponent(orgComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(orgButton)) .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(jLabel3) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel1) + .addComponent(lbVersion)) + .addGap(2, 2, 2) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(versionTextField) + .addComponent(hashSetNameTextField))) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel3) + .addComponent(jLabel4)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(databasePathTextField))) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(fileTypeRadioButton) + .addGap(26, 26, 26) + .addComponent(centralRepoRadioButton)) + .addComponent(databasePathTextField)))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(openButton)) .addGroup(layout.createSequentialGroup() @@ -210,7 +339,8 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(knownRadioButton) .addComponent(knownBadRadioButton))) - .addComponent(sendIngestMessagesCheckbox)) + .addComponent(sendIngestMessagesCheckbox) + .addComponent(readOnlyCheckbox)) .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()) ); @@ -221,6 +351,11 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(fileTypeRadioButton) + .addComponent(centralRepoRadioButton) + .addComponent(jLabel4)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(openButton) .addComponent(databasePathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -229,23 +364,30 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel1) .addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 119, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(okButton) - .addComponent(cancelButton)) - .addContainerGap()) - .addGroup(layout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabel2) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(knownRadioButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(knownBadRadioButton) - .addGap(18, 18, 18) - .addComponent(sendIngestMessagesCheckbox) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(versionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbVersion)) + .addGap(9, 9, 9) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(orgButton) + .addComponent(orgComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbOrg)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(knownRadioButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(knownBadRadioButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(readOnlyCheckbox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(sendIngestMessagesCheckbox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(okButton) + .addComponent(cancelButton)) + .addContainerGap()) ); pack(); @@ -262,6 +404,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { hashDbFolder.mkdir(); } fileChooser.setCurrentDirectory(hashDbFolder); + updateFileChooserFilter(); if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { File databaseFile = fileChooser.getSelectedFile(); try { @@ -296,6 +439,11 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { this.dispose(); }//GEN-LAST:event_cancelButtonActionPerformed + @NbBundle.Messages({"HashDbImportDatabaseDialog.missingVersion=A version must be entered", + "HashDbImportDatabaseDialog.missingOrg=An organization must be selected", + "HashDbImportDatabaseDialog.duplicateName=A hashset with this name and version already exists", + "HashDbImportDatabaseDialog.databaseLookupError=Error accessing central repository" + }) private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed // Note that the error handlers in this method call return without disposing of the // dialog to allow the user to try again, if desired. @@ -309,6 +457,28 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { JOptionPane.ERROR_MESSAGE); return; } + + if(centralRepoRadioButton.isSelected()){ + if(versionTextField.getText().isEmpty()){ + JOptionPane.showMessageDialog(this, + NbBundle.getMessage(this.getClass(), + "HashDbImportDatabaseDialog.missingVersion"), + NbBundle.getMessage(this.getClass(), + "HashDbImportDatabaseDialog.importHashDbErr"), + JOptionPane.ERROR_MESSAGE); + return; + } + + if(selectedOrg == null){ + JOptionPane.showMessageDialog(this, + NbBundle.getMessage(this.getClass(), + "HashDbImportDatabaseDialog.missingOrg"), + NbBundle.getMessage(this.getClass(), + "HashDbImportDatabaseDialog.importHashDbErr"), + JOptionPane.ERROR_MESSAGE); + return; + } + } if (selectedFilePath.isEmpty()) { JOptionPane.showMessageDialog(this, @@ -338,18 +508,50 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { } String errorMessage = NbBundle.getMessage(this.getClass(), - "HashDbImportDatabaseDialog.errorMessage.failedToOpenHashDbMsg", - selectedFilePath); - try { - selectedHashDb = HashDbManager.getInstance().addExistingHashDatabaseNoSave(hashSetNameTextField.getText(), selectedFilePath, true, sendIngestMessagesCheckbox.isSelected(), type); - } catch (HashDbManagerException ex) { - Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex); - JOptionPane.showMessageDialog(this, - ex.getMessage(), - NbBundle.getMessage(this.getClass(), - "HashDbImportDatabaseDialog.importHashDbErr"), - JOptionPane.ERROR_MESSAGE); - return; + "HashDbImportDatabaseDialog.errorMessage.failedToOpenHashDbMsg", + selectedFilePath); + if(fileTypeRadioButton.isSelected()){ + + try { + selectedHashDb = HashDbManager.getInstance().addExistingHashDatabaseNoSave(hashSetNameTextField.getText(), selectedFilePath, true, sendIngestMessagesCheckbox.isSelected(), type); + } catch (HashDbManagerException ex) { + Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex); + JOptionPane.showMessageDialog(this, + ex.getMessage(), + NbBundle.getMessage(this.getClass(), + "HashDbImportDatabaseDialog.importHashDbErr"), + JOptionPane.ERROR_MESSAGE); + return; + } + } else { + + // Check if a hash set with the same name/version already exists + try{ + if(EamDb.getInstance().referenceSetExists(hashSetNameTextField.getText(), versionTextField.getText())){ + JOptionPane.showMessageDialog(this, + NbBundle.getMessage(this.getClass(), + "HashDbImportDatabaseDialog.duplicateName"), + NbBundle.getMessage(this.getClass(), + "HashDbImportDatabaseDialog.importHashDbErr"), + JOptionPane.ERROR_MESSAGE); + return; + } + } catch (EamDbException ex){ + Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Error looking up reference set", ex); + JOptionPane.showMessageDialog(this, + NbBundle.getMessage(this.getClass(), + "HashDbImportDatabaseDialog.databaseLookupError"), + NbBundle.getMessage(this.getClass(), + "HashDbImportDatabaseDialog.importHashDbErr"), + JOptionPane.ERROR_MESSAGE); + return; + } + + ImportCentralRepoDbProgressDialog progressDialog = new ImportCentralRepoDbProgressDialog(); + progressDialog.importFile(hashSetNameTextField.getText(), versionTextField.getText(), + selectedOrg.getOrgID(), true, sendIngestMessagesCheckbox.isSelected(), type, + this.readOnlyCheckbox.isSelected(), selectedFilePath); + selectedHashDb = progressDialog.getDatabase(); } dispose(); @@ -359,18 +561,58 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { // TODO add your handling code here: }//GEN-LAST:event_sendIngestMessagesCheckboxActionPerformed + private void fileTypeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileTypeRadioButtonActionPerformed + enableComponents(); + }//GEN-LAST:event_fileTypeRadioButtonActionPerformed + + private void centralRepoRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_centralRepoRadioButtonActionPerformed + enableComponents(); + }//GEN-LAST:event_centralRepoRadioButtonActionPerformed + + private void orgButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orgButtonActionPerformed + ManageOrganizationsDialog dialog = new ManageOrganizationsDialog(); + // update the combobox options + if (dialog.isChanged()) { + populateCombobox(); + } + }//GEN-LAST:event_orgButtonActionPerformed + + private void orgComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orgComboBoxActionPerformed + //JComboBox cb = (JComboBox)evt.getSource(); + //String orgName = (String)cb.getSelectedItem(); + + if (null == orgComboBox.getSelectedItem()) return; + String orgName = this.orgComboBox.getSelectedItem().toString(); + for (EamOrganization org : orgs) { + if (org.getName().equals(orgName)) { + selectedOrg = org; + return; + } + } + }//GEN-LAST:event_orgComboBoxActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; private javax.swing.JButton cancelButton; + private javax.swing.JRadioButton centralRepoRadioButton; private javax.swing.JTextField databasePathTextField; + private javax.swing.JRadioButton fileTypeRadioButton; private javax.swing.JTextField hashSetNameTextField; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; private javax.swing.JRadioButton knownBadRadioButton; private javax.swing.JRadioButton knownRadioButton; + private javax.swing.JLabel lbOrg; + private javax.swing.JLabel lbVersion; private javax.swing.JButton okButton; private javax.swing.JButton openButton; + private javax.swing.JButton orgButton; + private javax.swing.JComboBox orgComboBox; + private javax.swing.JCheckBox readOnlyCheckbox; private javax.swing.JCheckBox sendIngestMessagesCheckbox; + private javax.swing.ButtonGroup storageTypeButtonGroup; + private javax.swing.JTextField versionTextField; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 3dd7416872..40cd2230b3 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -129,9 +129,9 @@ public class HashDbIngestModule implements FileIngestModule { private void updateEnabledHashSets(List allHashSets, List enabledHashSets) { enabledHashSets.clear(); for (HashDb db : allHashSets) { - if (settings.isHashSetEnabled(db.getHashSetName())) { + if (settings.isHashSetEnabled(db)) { try { - if (db.hasIndex()) { + if (db.isValid()) { enabledHashSets.add(db); } } catch (TskCoreException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index f10f16e3f9..e8de1893ca 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -38,6 +38,9 @@ import org.apache.commons.io.FilenameUtils; import org.netbeans.api.progress.ProgressHandle; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalSet; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -49,6 +52,7 @@ import org.sleuthkit.datamodel.HashEntry; import org.sleuthkit.datamodel.HashHitInfo; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; /** * This class implements a singleton that manages the set of hash databases used @@ -58,8 +62,7 @@ public class HashDbManager implements PropertyChangeListener { private static final String HASH_DATABASE_FILE_EXTENSON = "kdb"; //NON-NLS private static HashDbManager instance = null; - private List knownHashSets = new ArrayList<>(); - private List knownBadHashSets = new ArrayList<>(); + private List hashSets = new ArrayList<>(); private Set hashSetNames = new HashSet<>(); private Set hashSetPaths = new HashSet<>(); PropertyChangeSupport changeSupport = new PropertyChangeSupport(HashDbManager.class); @@ -230,10 +233,10 @@ public class HashDbManager implements PropertyChangeListener { } return hashDb; } - - private HashDb addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws TskCoreException { + + private SleuthkitHashSet addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws TskCoreException { // Wrap an object around the handle. - HashDb hashDb = new HashDb(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); + SleuthkitHashSet hashDb = new SleuthkitHashSet(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); // Get the indentity data before updating the collections since the // accessor methods may throw. @@ -250,12 +253,8 @@ public class HashDbManager implements PropertyChangeListener { hashSetPaths.add(indexPath); } - // Add the hash database to the appropriate collection for its type. - if (hashDb.getKnownFilesType() == HashDb.KnownFilesType.KNOWN) { - knownHashSets.add(hashDb); - } else { - knownBadHashSets.add(hashDb); - } + // Add the hash database to the collection + hashSets.add(hashDb); // Let any external listeners know that there's a new set try { @@ -269,8 +268,40 @@ public class HashDbManager implements PropertyChangeListener { } return hashDb; } + + CentralRepoHashSet addExistingCentralRepoHashSet(String hashSetName, String version, int referenceSetID, + boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType, + boolean readOnly) throws TskCoreException{ + + if(! EamDb.isEnabled()){ + throw new TskCoreException("Could not load central repository database " + hashSetName + " - central repository is not enabled"); + } + + CentralRepoHashSet db = new CentralRepoHashSet(hashSetName, version, referenceSetID, searchDuringIngest, + sendIngestMessages, knownFilesType, readOnly); + + if(! db.isValid()){ + throw new TskCoreException("Error finding database " + hashSetName + " in central repository"); + } + + // Add the hash database to the collection + hashSets.add(db); - synchronized void indexHashDatabase(HashDb hashDb) { + // Let any external listeners know that there's a new set + try { + changeSupport.firePropertyChange(SetEvt.DB_ADDED.toString(), null, hashSetName); + } catch (Exception e) { + logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS + MessageNotifyUtil.Notify.show( + NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErr"), + NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErrorListeningToUpdatesMsg"), + MessageNotifyUtil.MessageType.ERROR); + } + return db; + + } + + synchronized void indexHashDatabase(SleuthkitHashSet hashDb) { hashDb.addPropertyChangeListener(this); HashDbIndexer creator = new HashDbIndexer(hashDb); creator.execute(); @@ -278,8 +309,8 @@ public class HashDbManager implements PropertyChangeListener { @Override public void propertyChange(PropertyChangeEvent event) { - if (event.getPropertyName().equals(HashDb.Event.INDEXING_DONE.name())) { - HashDb hashDb = (HashDb) event.getNewValue(); + if (event.getPropertyName().equals(SleuthkitHashSet.Event.INDEXING_DONE.name())) { + SleuthkitHashSet hashDb = (SleuthkitHashSet) event.getNewValue(); if (null != hashDb) { try { String indexPath = hashDb.getIndexPath(); @@ -317,27 +348,35 @@ public class HashDbManager implements PropertyChangeListener { // hash set names are used, before undertaking These operations will succeed and constitute // a mostly effective removal, even if the subsequent operations fail. String hashSetName = hashDb.getHashSetName(); - knownHashSets.remove(hashDb); - knownBadHashSets.remove(hashDb); hashSetNames.remove(hashSetName); + hashSets.remove(hashDb); // Now undertake the operations that could throw. - try { - hashSetPaths.remove(hashDb.getIndexPath()); - } catch (TskCoreException ex) { - Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS - } - try { - if (!hashDb.hasIndexOnly()) { - hashSetPaths.remove(hashDb.getDatabasePath()); + + // Indexing is only relevanet for sleuthkit hashsets + if(hashDb instanceof SleuthkitHashSet){ + SleuthkitHashSet hashDatabase = (SleuthkitHashSet)hashDb; + try { + if(hashDatabase.hasIndex()){ + hashSetPaths.remove(hashDatabase.getIndexPath()); + } + } catch (TskCoreException ex) { + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDatabase.getHashSetName() + " hash database when removing the database", ex); //NON-NLS + } + + try { + if (!hashDatabase.hasIndexOnly()) { + hashSetPaths.remove(hashDatabase.getDatabasePath()); + } + } catch (TskCoreException ex) { + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting database path of " + hashDatabase.getHashSetName() + " hash database when removing the database", ex); //NON-NLS + } + + try { + hashDatabase.close(); + } catch (TskCoreException ex) { + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS } - } catch (TskCoreException ex) { - Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting database path of " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS - } - try { - hashDb.close(); - } catch (TskCoreException ex) { - Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS } // Let any external listeners know that a set has been deleted @@ -354,24 +393,30 @@ public class HashDbManager implements PropertyChangeListener { void save() throws HashDbManagerException { try { - if (!HashLookupSettings.writeSettings(new HashLookupSettings(this.knownHashSets, this.knownBadHashSets))) { + if (!HashLookupSettings.writeSettings(new HashLookupSettings(HashLookupSettings.convertHashSetList(this.hashSets)))) { throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.saveErrorExceptionMsg")); } } catch (HashLookupSettings.HashLookupSettingsException ex) { throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.saveErrorExceptionMsg")); } } - + /** * Gets all of the hash databases used to classify files as known or known - * bad. + * bad. Will add any new central repository databases to the list before + * returning it. * * @return A list, possibly empty, of hash databases. */ public synchronized List getAllHashSets() { + try{ + updateHashSetsFromCentralRepository(); + } catch (TskCoreException ex){ + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS + } + List hashDbs = new ArrayList<>(); - hashDbs.addAll(knownHashSets); - hashDbs.addAll(knownBadHashSets); + hashDbs.addAll(this.hashSets); return hashDbs; } @@ -382,7 +427,14 @@ public class HashDbManager implements PropertyChangeListener { */ public synchronized List getKnownFileHashSets() { List hashDbs = new ArrayList<>(); - hashDbs.addAll(knownHashSets); + try{ + updateHashSetsFromCentralRepository(); + } catch (TskCoreException ex){ + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS + } + this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN)).forEach((db) -> { + hashDbs.add(db); + }); return hashDbs; } @@ -393,7 +445,14 @@ public class HashDbManager implements PropertyChangeListener { */ public synchronized List getKnownBadFileHashSets() { List hashDbs = new ArrayList<>(); - hashDbs.addAll(knownBadHashSets); + try{ + updateHashSetsFromCentralRepository(); + } catch (TskCoreException ex){ + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS + } + this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN_BAD)).forEach((db) -> { + hashDbs.add(db); + }); return hashDbs; } @@ -403,13 +462,16 @@ public class HashDbManager implements PropertyChangeListener { * @return A list, possibly empty, of hash databases. */ public synchronized List getUpdateableHashSets() { - List updateableDbs = getUpdateableHashSets(knownHashSets); - updateableDbs.addAll(getUpdateableHashSets(knownBadHashSets)); - return updateableDbs; + return getUpdateableHashSets(this.hashSets); } private List getUpdateableHashSets(List hashDbs) { ArrayList updateableDbs = new ArrayList<>(); + try{ + updateHashSetsFromCentralRepository(); + } catch (TskCoreException ex){ + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS + } for (HashDb db : hashDbs) { try { if (db.isUpdateable()) { @@ -421,14 +483,41 @@ public class HashDbManager implements PropertyChangeListener { } return updateableDbs; } + + private List getCentralRepoHashSetsFromDatabase(){ + List crHashSets = new ArrayList<>(); + if(EamDb.isEnabled()){ + try{ + List crSets = EamDb.getInstance().getAllReferenceSets(); + for(EamGlobalSet globalSet:crSets){ + + // Defaults for fields not stored in the central repository: + // searchDuringIngest: false + // sendIngestMessages: true if the hash set is notable + boolean sendIngestMessages = convertFileKnown(globalSet.getFileKnownStatus()).equals(HashDb.KnownFilesType.KNOWN_BAD); + crHashSets.add(new HashDbInfo(globalSet.getSetName(), globalSet.getVersion(), + globalSet.getGlobalSetID(), convertFileKnown(globalSet.getFileKnownStatus()), globalSet.isReadOnly(), false, sendIngestMessages)); + } + } catch (EamDbException ex){ + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS + } + } + return crHashSets; + } + + private static HashDb.KnownFilesType convertFileKnown(TskData.FileKnown fileKnown){ + if(fileKnown.equals(TskData.FileKnown.BAD)){ + return HashDb.KnownFilesType.KNOWN_BAD; + } + return HashDb.KnownFilesType.KNOWN; + } /** * Restores the last saved hash sets configuration. This supports * cancellation of configuration panels. */ public synchronized void loadLastSavedConfiguration() { - closeHashDatabases(knownHashSets); - closeHashDatabases(knownBadHashSets); + closeHashDatabases(this.hashSets); hashSetNames.clear(); hashSetPaths.clear(); @@ -437,10 +526,12 @@ public class HashDbManager implements PropertyChangeListener { private void closeHashDatabases(List hashDatabases) { for (HashDb database : hashDatabases) { - try { - database.close(); - } catch (TskCoreException ex) { - Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + database.getHashSetName() + " hash database", ex); //NON-NLS + if(database instanceof SleuthkitHashSet){ + try { + ((SleuthkitHashSet)database).close(); + } catch (TskCoreException ex) { + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + database.getHashSetName() + " hash database", ex); //NON-NLS + } } } hashDatabases.clear(); @@ -461,24 +552,48 @@ public class HashDbManager implements PropertyChangeListener { * * @param settings The settings to configure. */ - @Messages({"# {0} - database name", "HashDbManager.noDbPath.message=Couldn't get valid database path for: {0}"}) + @Messages({"# {0} - database name", "HashDbManager.noDbPath.message=Couldn't get valid database path for: {0}", + "HashDbManager.centralRepoLoadError.message=Error loading central repository hash sets"}) private void configureSettings(HashLookupSettings settings) { allDatabasesLoadedCorrectly = true; List hashDbInfoList = settings.getHashDbInfo(); - for (HashDbInfo hashDb : hashDbInfoList) { + for (HashDbInfo hashDbInfo : hashDbInfoList) { try { - String dbPath = this.getValidFilePath(hashDb.getHashSetName(), hashDb.getPath()); - if (dbPath != null) { - addHashDatabase(SleuthkitJNI.openHashDatabase(dbPath), hashDb.getHashSetName(), hashDb.getSearchDuringIngest(), hashDb.getSendIngestMessages(), hashDb.getKnownFilesType()); + if(hashDbInfo.isFileDatabaseType()){ + String dbPath = this.getValidFilePath(hashDbInfo.getHashSetName(), hashDbInfo.getPath()); + if (dbPath != null) { + addHashDatabase(SleuthkitJNI.openHashDatabase(dbPath), hashDbInfo.getHashSetName(), hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType()); + } else { + logger.log(Level.WARNING, Bundle.HashDbManager_noDbPath_message(hashDbInfo.getHashSetName())); + allDatabasesLoadedCorrectly = false; + } } else { - logger.log(Level.WARNING, Bundle.HashDbManager_noDbPath_message(hashDb.getHashSetName())); - allDatabasesLoadedCorrectly = false; + if(EamDb.isEnabled()){ + addExistingCentralRepoHashSet(hashDbInfo.getHashSetName(), hashDbInfo.getVersion(), + hashDbInfo.getReferenceSetID(), + hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), + hashDbInfo.getKnownFilesType(), hashDbInfo.isReadOnly()); + } } } catch (TskCoreException ex) { Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); //NON-NLS JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(), - "HashDbManager.unableToOpenHashDbMsg", hashDb.getHashSetName()), + "HashDbManager.unableToOpenHashDbMsg", hashDbInfo.getHashSetName()), + NbBundle.getMessage(this.getClass(), "HashDbManager.openHashDbErr"), + JOptionPane.ERROR_MESSAGE); + allDatabasesLoadedCorrectly = false; + } + } + + if(EamDb.isEnabled()){ + try{ + updateHashSetsFromCentralRepository(); + } catch (TskCoreException ex){ + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); //NON-NLS + + JOptionPane.showMessageDialog(null, + Bundle.HashDbManager_centralRepoLoadError_message(), NbBundle.getMessage(this.getClass(), "HashDbManager.openHashDbErr"), JOptionPane.ERROR_MESSAGE); allDatabasesLoadedCorrectly = false; @@ -494,7 +609,7 @@ public class HashDbManager implements PropertyChangeListener { will load without errors and the user may think that the problem was solved.*/ if (!allDatabasesLoadedCorrectly && RuntimeProperties.runningWithGUI()) { try { - HashLookupSettings.writeSettings(new HashLookupSettings(this.knownHashSets, this.knownBadHashSets)); + HashLookupSettings.writeSettings(new HashLookupSettings(HashLookupSettings.convertHashSetList(this.hashSets))); allDatabasesLoadedCorrectly = true; } catch (HashLookupSettings.HashLookupSettingsException ex) { allDatabasesLoadedCorrectly = false; @@ -502,6 +617,29 @@ public class HashDbManager implements PropertyChangeListener { } } } + + private void updateHashSetsFromCentralRepository() throws TskCoreException { + if(EamDb.isEnabled()){ + List crHashDbInfoList = getCentralRepoHashSetsFromDatabase(); + for(HashDbInfo hashDbInfo : crHashDbInfoList) { + if(hashDbInfoIsNew(hashDbInfo)){ + addExistingCentralRepoHashSet(hashDbInfo.getHashSetName(), hashDbInfo.getVersion(), + hashDbInfo.getReferenceSetID(), + hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType(), + hashDbInfo.isReadOnly()); + } + } + } + } + + private boolean hashDbInfoIsNew(HashDbInfo dbInfo){ + for(HashDb db:this.hashSets){ + if(dbInfo.matches(db)){ + return false; + } + } + return true; + } private String getValidFilePath(String hashSetName, String configuredPath) { // Check the configured path. @@ -549,13 +687,9 @@ public class HashDbManager implements PropertyChangeListener { } return filePath; } - - /** - * Instances of this class represent hash databases used to classify files - * as known or know bad. - */ - public static class HashDb { - + + public static abstract class HashDb { + /** * Indicates how files with hashes stored in a particular hash database * object should be classified. @@ -582,16 +716,91 @@ public class HashDbManager implements PropertyChangeListener { INDEXING_DONE } + + public abstract String getHashSetName(); + + abstract String getDisplayName(); + + public abstract String getDatabasePath() throws TskCoreException; + + public abstract HashDb.KnownFilesType getKnownFilesType(); + + public abstract boolean getSearchDuringIngest(); + + abstract boolean getDefaultSearchDuringIngest(); + + abstract void setSearchDuringIngest(boolean useForIngest); + + public abstract boolean getSendIngestMessages(); + + abstract void setSendIngestMessages(boolean showInboxMessages); + + /** + * Indicates whether the hash database accepts updates. + * + * @return True if the database accepts updates, false otherwise. + * + * @throws org.sleuthkit.datamodel.TskCoreException + */ + public abstract boolean isUpdateable() throws TskCoreException; + + /** + * Adds hashes of content (if calculated) to the hash database. + * + * @param content The content for which the calculated hashes, if any, + * are to be added to the hash database. + * + * @throws TskCoreException + */ + public abstract void addHashes(Content content) throws TskCoreException; + + public abstract void addHashes(Content content, String comment) throws TskCoreException; + + public abstract void addHashes(List hashes) throws TskCoreException; + + public abstract boolean lookupMD5Quick(Content content) throws TskCoreException; + + public abstract HashHitInfo lookupMD5(Content content) throws TskCoreException; + + /** + * Returns whether this database can be enabled. + * For file type, this is the same as checking that it has an index + * @return true if is valid, false otherwise + * @throws TskCoreException + */ + abstract boolean isValid() throws TskCoreException; + + public abstract String getIndexPath() throws TskCoreException; + + public abstract boolean hasIndexOnly() throws TskCoreException; + + public abstract void firePropertyChange(String propertyName, Object oldValue, Object newValue); + + public abstract void addPropertyChangeListener(PropertyChangeListener pcl); + + public abstract void removePropertyChangeListener(PropertyChangeListener pcl); + + @Override + public abstract String toString(); + + } + + /** + * Instances of this class represent hash databases used to classify files + * as known or know bad. + */ + class SleuthkitHashSet extends HashDb{ + private static final long serialVersionUID = 1L; private final int handle; private final String hashSetName; private boolean searchDuringIngest; private boolean sendIngestMessages; - private final KnownFilesType knownFilesType; + private final HashDb.KnownFilesType knownFilesType; private boolean indexing; private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); - private HashDb(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) { + private SleuthkitHashSet(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) { this.handle = handle; this.hashSetName = hashSetName; this.searchDuringIngest = useForIngest; @@ -602,9 +811,11 @@ public class HashDbManager implements PropertyChangeListener { /** * Adds a listener for the events defined in HashDb.Event. + * Listeners are used during indexing. * * @param pcl */ + @Override public void addPropertyChangeListener(PropertyChangeListener pcl) { propertyChangeSupport.addPropertyChangeListener(pcl); } @@ -614,38 +825,66 @@ public class HashDbManager implements PropertyChangeListener { * * @param pcl */ + @Override public void removePropertyChangeListener(PropertyChangeListener pcl) { propertyChangeSupport.removePropertyChangeListener(pcl); } + + int getHandle(){ + return handle; + } + @Override public String getHashSetName() { return hashSetName; } + + @Override + String getDisplayName(){ + return getHashSetName(); + } + @Override public String getDatabasePath() throws TskCoreException { return SleuthkitJNI.getHashDatabasePath(handle); } + + public void setIndexing(boolean indexing){ + this.indexing = indexing; + } + @Override public String getIndexPath() throws TskCoreException { return SleuthkitJNI.getHashDatabaseIndexPath(handle); } + @Override public KnownFilesType getKnownFilesType() { return knownFilesType; } + @Override public boolean getSearchDuringIngest() { return searchDuringIngest; } + + @Override + boolean getDefaultSearchDuringIngest(){ + // File type hash sets are on by default + return true; + } + @Override void setSearchDuringIngest(boolean useForIngest) { this.searchDuringIngest = useForIngest; } + @Override public boolean getSendIngestMessages() { return sendIngestMessages; } + @Override void setSendIngestMessages(boolean showInboxMessages) { this.sendIngestMessages = showInboxMessages; } @@ -657,6 +896,7 @@ public class HashDbManager implements PropertyChangeListener { * * @throws org.sleuthkit.datamodel.TskCoreException */ + @Override public boolean isUpdateable() throws TskCoreException { return SleuthkitJNI.isUpdateableHashDatabase(this.handle); } @@ -669,6 +909,7 @@ public class HashDbManager implements PropertyChangeListener { * * @throws TskCoreException */ + @Override public void addHashes(Content content) throws TskCoreException { addHashes(content, null); } @@ -683,6 +924,7 @@ public class HashDbManager implements PropertyChangeListener { * * @throws TskCoreException */ + @Override public void addHashes(Content content, String comment) throws TskCoreException { // This only works for AbstractFiles and MD5 hashes at present. assert content instanceof AbstractFile; @@ -701,6 +943,7 @@ public class HashDbManager implements PropertyChangeListener { * * @throws TskCoreException */ + @Override public void addHashes(List hashes) throws TskCoreException { SleuthkitJNI.addToHashDatabase(hashes, handle); } @@ -714,6 +957,7 @@ public class HashDbManager implements PropertyChangeListener { * * @throws TskCoreException */ + @Override public boolean lookupMD5Quick(Content content) throws TskCoreException { boolean result = false; assert content instanceof AbstractFile; @@ -735,6 +979,7 @@ public class HashDbManager implements PropertyChangeListener { * * @throws TskCoreException */ + @Override public HashHitInfo lookupMD5(Content content) throws TskCoreException { HashHitInfo result = null; // This only works for AbstractFiles and MD5 hashes at present. @@ -747,11 +992,23 @@ public class HashDbManager implements PropertyChangeListener { } return result; } + + /** + * Returns whether this database can be enabled. + * For file type, this is the same as checking that it has an index + * @return true if is valid, false otherwise + * @throws TskCoreException + */ + @Override + boolean isValid() throws TskCoreException { + return hasIndex(); + } boolean hasIndex() throws TskCoreException { return SleuthkitJNI.hashDatabaseHasLookupIndex(handle); } + @Override public boolean hasIndexOnly() throws TskCoreException { return SleuthkitJNI.hashDatabaseIsIndexOnly(handle); } @@ -763,10 +1020,21 @@ public class HashDbManager implements PropertyChangeListener { boolean isIndexing() { return indexing; } + + @Override + public void firePropertyChange(String propertyName, Object oldValue, Object newValue){ + this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); + } private void close() throws TskCoreException { SleuthkitJNI.closeHashDatabase(handle); } + + @Override + public String toString(){ + return getHashSetName(); + } + @Override public int hashCode() { @@ -786,16 +1054,10 @@ public class HashDbManager implements PropertyChangeListener { if (getClass() != obj.getClass()) { return false; } - final HashDb other = (HashDb) obj; + final SleuthkitHashSet other = (SleuthkitHashSet) obj; if (!Objects.equals(this.hashSetName, other.hashSetName)) { return false; } - if (this.searchDuringIngest != other.searchDuringIngest) { - return false; - } - if (this.sendIngestMessages != other.sendIngestMessages) { - return false; - } if (this.knownFilesType != other.knownFilesType) { return false; } @@ -803,31 +1065,331 @@ public class HashDbManager implements PropertyChangeListener { } } + /** + * Instances of this class represent hash databases used to classify files + * as known or know bad. + */ + class CentralRepoHashSet extends HashDb{ + + private static final long serialVersionUID = 1L; + private final String hashSetName; + private boolean searchDuringIngest; + private boolean sendIngestMessages; + private final HashDb.KnownFilesType knownFilesType; + private final int referenceSetID; + private final String version; + private String orgName; + private final boolean readOnly; + private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); + + @Messages({"HashDbManager.CentralRepoHashDb.orgError=Error loading organization"}) + private CentralRepoHashSet(String hashSetName, String version, int referenceSetID, + boolean useForIngest, boolean sendHitMessages, HashDb.KnownFilesType knownFilesType, + boolean readOnly) + throws TskCoreException{ + this.hashSetName = hashSetName; + this.version = version; + this.referenceSetID = referenceSetID; + this.searchDuringIngest = useForIngest; + this.sendIngestMessages = sendHitMessages; + this.knownFilesType = knownFilesType; + this.readOnly = readOnly; + + try{ + orgName = EamDb.getInstance().getReferenceSetOrganization(referenceSetID).getName(); + } catch (EamDbException ex){ + Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error looking up central repository organization for reference set " + referenceSetID, ex); //NON-NLS + orgName = Bundle.HashDbManager_CentralRepoHashDb_orgError(); + } + } + + /** + * Adds a listener for the events defined in HashDb.Event. + * Listeners are used during indexing. + * + * @param pcl + */ + @Override + public void addPropertyChangeListener(PropertyChangeListener pcl) { + propertyChangeSupport.addPropertyChangeListener(pcl); + } + + /** + * Removes a listener for the events defined in HashDb.Event. + * + * @param pcl + */ + @Override + public void removePropertyChangeListener(PropertyChangeListener pcl) { + propertyChangeSupport.removePropertyChangeListener(pcl); + } + + @Override + public boolean hasIndexOnly() throws TskCoreException{ + return true; + } + + @Override + public String getHashSetName() { + return hashSetName; + } + + @Override + String getDisplayName(){ + return getHashSetName() + " " + getVersion(); + } + + String getVersion(){ + return version; + } + + String getOrgName(){ + return orgName; + } + + int getReferenceSetID(){ + return referenceSetID; + } + + @Override + public String getDatabasePath() throws TskCoreException { + return ""; + } + + @Override + public String getIndexPath() throws TskCoreException { + return ""; + } + + @Override + public HashDb.KnownFilesType getKnownFilesType() { + return knownFilesType; + } + + @Override + public boolean getSearchDuringIngest() { + return searchDuringIngest; + } + + @Override + boolean getDefaultSearchDuringIngest(){ + // Central repo hash sets are off by default + return false; + } + + @Override + void setSearchDuringIngest(boolean useForIngest) { + this.searchDuringIngest = useForIngest; + } + + @Override + public boolean getSendIngestMessages() { + return sendIngestMessages; + } + + @Override + void setSendIngestMessages(boolean showInboxMessages) { + this.sendIngestMessages = showInboxMessages; + } + + /** + * Indicates whether the hash database accepts updates. + * + * @return True if the database accepts updates, false otherwise. + * + * @throws org.sleuthkit.datamodel.TskCoreException + */ + @Override + public boolean isUpdateable() throws TskCoreException { + return false; + // TEMP this will change as soon as adding to the database is supported + // return (! readOnly); + } + + /** + * Adds hashes of content (if calculated) to the hash database. + * + * @param content The content for which the calculated hashes, if any, + * are to be added to the hash database. + * + * @throws TskCoreException + */ + @Override + public void addHashes(Content content) throws TskCoreException { + addHashes(content, null); + } + + /** + * Adds hashes of content (if calculated) to the hash database. + * + * @param content The content for which the calculated hashes, if any, + * are to be added to the hash database. + * @param comment A comment to associate with the hashes, e.g., the name + * of the case in which the content was encountered. + * + * @throws TskCoreException + */ + @Override + public void addHashes(Content content, String comment) throws TskCoreException { + + } + + /** + * Adds a list of hashes to the hash database at once + * + * @param hashes List of hashes + * + * @throws TskCoreException + */ + @Override + public void addHashes(List hashes) throws TskCoreException { + + } + + /** + * Perform a basic boolean lookup of the file's hash. + * + * @param content + * + * @return True if file's MD5 is in the hash database + * + * @throws TskCoreException + */ + @Override + public boolean lookupMD5Quick(Content content) throws TskCoreException { + // This only works for AbstractFiles and MD5 hashes + assert content instanceof AbstractFile; + if (content instanceof AbstractFile) { + AbstractFile file = (AbstractFile) content; + if (null != file.getMd5Hash()) { + try{ + return EamDb.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID); + } catch (EamDbException ex){ + Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup for hash " + + file.getMd5Hash() + " in reference set " + referenceSetID, ex); //NON-NLS + throw new TskCoreException("Error performing central reposiotry hash lookup", ex); + } + } + } + return false; + } + + /** + * Lookup hash value in DB and provide details on file. + * + * @param content + * + * @return null if file is not in database. + * + * @throws TskCoreException + */ + @Override + public HashHitInfo lookupMD5(Content content) throws TskCoreException { + HashHitInfo result = null; + // This only works for AbstractFiles and MD5 hashes + assert content instanceof AbstractFile; + if (content instanceof AbstractFile) { + AbstractFile file = (AbstractFile) content; + if (null != file.getMd5Hash()) { + try{ + if(EamDb.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID)){ + // Make a bare-bones HashHitInfo for now + result = new HashHitInfo(file.getMd5Hash(), "", ""); + } + } catch (EamDbException ex){ + Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup for hash " + + file.getMd5Hash() + " in reference set " + referenceSetID, ex); //NON-NLS + throw new TskCoreException("Error performing central reposiotry hash lookup", ex); + } + } + } + return result; + } + + /** + * Returns whether this database can be enabled. + * + * @return true if is valid, false otherwise + */ + @Override + boolean isValid() { + if(! EamDb.isEnabled()) { + return false; + } + try{ + return EamDb.getInstance().referenceSetIsValid(this.referenceSetID, this.hashSetName, this.version); + } catch (EamDbException ex){ + Logger.getLogger(CentralRepoHashSet.class.getName()).log(Level.SEVERE, "Error validating hash database " + hashSetName, ex); //NON-NLS + return false; + } + } + + @Override + public void firePropertyChange(String propertyName, Object oldValue, Object newValue){ + this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + @Override + public String toString(){ + return getHashSetName(); + } + + + @Override + public int hashCode() { + int code = 23; + code = 47 * code + Objects.hashCode(this.hashSetName); + code = 47 * code + Objects.hashCode(this.version); + code = 47 * code + Integer.hashCode(this.referenceSetID); + code = 47 * code + Objects.hashCode(this.knownFilesType); + return code; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final CentralRepoHashSet other = (CentralRepoHashSet) obj; + if (!Objects.equals(this.hashSetName, other.hashSetName)) { + return false; + } + if (!Objects.equals(this.version, other.version)) { + return false; + } + if (this.knownFilesType != other.knownFilesType) { + return false; + } + return true; + } + } + /** * Worker thread to make an index of a database */ private class HashDbIndexer extends SwingWorker { private ProgressHandle progress = null; - private HashDb hashDb = null; + private SleuthkitHashSet hashDb = null; - HashDbIndexer(HashDb hashDb) { + HashDbIndexer(SleuthkitHashSet hashDb) { this.hashDb = hashDb; } - ; - @Override protected Object doInBackground() { - hashDb.indexing = true; + hashDb.setIndexing(true); progress = ProgressHandle.createHandle( - NbBundle.getMessage(this.getClass(), "HashDbManager.progress.indexingHashSet", hashDb.hashSetName)); + NbBundle.getMessage(this.getClass(), "HashDbManager.progress.indexingHashSet", hashDb.getHashSetName())); progress.start(); progress.switchToIndeterminate(); try { - SleuthkitJNI.createLookupIndexForHashDatabase(hashDb.handle); + SleuthkitJNI.createLookupIndexForHashDatabase(hashDb.getHandle()); } catch (TskCoreException ex) { - Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error indexing hash database", ex); //NON-NLS + Logger.getLogger(HashDbIndexer.class.getName()).log(Level.SEVERE, "Error indexing hash set " + hashDb.getHashSetName(), ex); //NON-NLS JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(), "HashDbManager.dlgMsg.errorIndexingHashSet", @@ -840,7 +1402,7 @@ public class HashDbManager implements PropertyChangeListener { @Override protected void done() { - hashDb.indexing = false; + hashDb.setIndexing(false); progress.finish(); // see if we got any errors @@ -857,8 +1419,8 @@ public class HashDbManager implements PropertyChangeListener { } try { - hashDb.propertyChangeSupport.firePropertyChange(HashDb.Event.INDEXING_DONE.toString(), null, hashDb); - hashDb.propertyChangeSupport.firePropertyChange(HashDbManager.SetEvt.DB_INDEXED.toString(), null, hashDb.getHashSetName()); + hashDb.firePropertyChange(SleuthkitHashSet.Event.INDEXING_DONE.toString(), null, hashDb); + hashDb.firePropertyChange(HashDbManager.SetEvt.DB_INDEXED.toString(), null, hashDb.getHashSetName()); } catch (Exception e) { logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS MessageNotifyUtil.Notify.show( diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java index 8388367130..2fb515832b 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java @@ -60,18 +60,7 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { @Override public IngestModuleIngestJobSettings getDefaultIngestJobSettings() { // All available hash sets are enabled and always calculate hashes is true by default. - HashDbManager hashDbManager = HashDbManager.getInstance(); - List knownHashSetNames = getHashSetNames(hashDbManager.getKnownFileHashSets()); - List knownBadHashSetNames = getHashSetNames(hashDbManager.getKnownBadFileHashSets()); - return new HashLookupModuleSettings(true, knownHashSetNames, knownBadHashSetNames); - } - - private List getHashSetNames(List hashDbs) { - List hashSetNames = new ArrayList<>(); - for (HashDbManager.HashDb db : hashDbs) { - hashSetNames.add(db.getHashSetName()); - } - return hashSetNames; + return new HashLookupModuleSettings(true, HashDbManager.getInstance().getAllHashSets()); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java index e9f7b6cf8f..3e331cb1da 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java @@ -21,7 +21,13 @@ package org.sleuthkit.autopsy.modules.hashdatabase; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.logging.Level; +import java.io.IOException; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettings.HashDbInfo; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Ingest job settings for the hash lookup module. @@ -29,25 +35,36 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { private static final long serialVersionUID = 1L; - private HashSet namesOfEnabledKnownHashSets; - private HashSet namesOfDisabledKnownHashSets; // Added in version 1.1 - private HashSet namesOfEnabledKnownBadHashSets; - private HashSet namesOfDisabledKnownBadHashSets; // Added in version 1.1 + private HashSet namesOfEnabledKnownHashSets; // The four lists of hash set names are only used for upgrading + private HashSet namesOfDisabledKnownHashSets; // from older settings files. All data should be stored in + private HashSet namesOfEnabledKnownBadHashSets; // the databaseInfoList list. + private HashSet namesOfDisabledKnownBadHashSets; private boolean shouldCalculateHashes = true; + private List databaseInfoList; + HashLookupModuleSettings(boolean shouldCalculateHashes, List hashDbList){ + this.shouldCalculateHashes = shouldCalculateHashes; + try{ + databaseInfoList = HashLookupSettings.convertHashSetList(hashDbList); + } catch (HashLookupSettings.HashLookupSettingsException ex){ + Logger.getLogger(HashLookupModuleSettings.class.getName()).log(Level.SEVERE, "Error creating hash database settings.", ex); //NON-NLS + databaseInfoList = new ArrayList<>(); + } + } + /** - * Constructs ingest job settings for the hash lookup module. - * - * @param shouldCalculateHashes Whether or not hashes should be - * calculated. - * @param namesOfEnabledKnownHashSets A list of enabled known hash sets. - * @param namesOfEnabledKnownBadHashSets A list of enabled notable hash - * sets. + * This overrides the default deserialization code so we can + * copy the enabled/disabled status into the DatabaseType objects. + * Ignore the Netbeans warning that this method is unused. + * @param stream + * @throws IOException + * @throws ClassNotFoundException */ - HashLookupModuleSettings(boolean shouldCalculateHashes, - List namesOfEnabledKnownHashSets, - List namesOfEnabledKnownBadHashSets) { - this(shouldCalculateHashes, namesOfEnabledKnownHashSets, namesOfEnabledKnownBadHashSets, new ArrayList<>(), new ArrayList<>()); + private void readObject(java.io.ObjectInputStream stream) + throws IOException, ClassNotFoundException { + + stream.defaultReadObject(); + upgradeFromOlderVersions(); } /** @@ -55,24 +72,34 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { * * @param shouldCalculateHashes Whether or not hashes should be * calculated. - * @param namesOfEnabledKnownHashSets A list of enabled known hash sets. - * @param namesOfEnabledKnownBadHashSets A list of enabled notable hash - * sets. - * @param namesOfDisabledKnownHashSets A list of disabled known hash - * sets. - * @param namesOfDisabledKnownBadHashSets A list of disabled notable hash - * sets. + * @param enabledHashSets A list of enabled hash sets. + * @param disabledHashSets A list of disabled hash sets. */ HashLookupModuleSettings(boolean shouldCalculateHashes, - List namesOfEnabledKnownHashSets, - List namesOfEnabledKnownBadHashSets, - List namesOfDisabledKnownHashSets, - List namesOfDisabledKnownBadHashSets) { + List enabledHashSets, + List disabledHashSets) { this.shouldCalculateHashes = shouldCalculateHashes; - this.namesOfEnabledKnownHashSets = new HashSet<>(namesOfEnabledKnownHashSets); - this.namesOfEnabledKnownBadHashSets = new HashSet<>(namesOfEnabledKnownBadHashSets); - this.namesOfDisabledKnownHashSets = new HashSet<>(namesOfDisabledKnownHashSets); - this.namesOfDisabledKnownBadHashSets = new HashSet<>(namesOfDisabledKnownBadHashSets); + + databaseInfoList = new ArrayList<>(); + for(HashDb db:enabledHashSets){ + try{ + HashDbInfo dbInfo = new HashDbInfo(db); + dbInfo.setSearchDuringIngest(true); + databaseInfoList.add(dbInfo); + } catch (TskCoreException ex){ + Logger.getLogger(HashLookupModuleSettings.class.getName()).log(Level.SEVERE, "Error creating hash database settings for " + db.getHashSetName(), ex); //NON-NLS + } + } + for(HashDb db:disabledHashSets){ + try{ + HashDbInfo dbInfo = new HashDbInfo(db); + dbInfo.setSearchDuringIngest(false); + databaseInfoList.add(dbInfo); + } catch (TskCoreException ex){ + Logger.getLogger(HashLookupModuleSettings.class.getName()).log(Level.SEVERE, "Error creating hash database settings for " + db.getHashSetName(), ex); //NON-NLS + } + } + } /** @@ -80,7 +107,6 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { */ @Override public long getVersionNumber() { - this.upgradeFromOlderVersions(); return HashLookupModuleSettings.serialVersionUID; } @@ -91,61 +117,26 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { * @return True if hashes are to be calculated, false otherwise. */ boolean shouldCalculateHashes() { - this.upgradeFromOlderVersions(); return this.shouldCalculateHashes; } /** * Checks whether or not a hash set is enabled. If there is no setting for - * the requested hash set, it is deemed to be enabled. + * the requested hash set, return the default value * - * @param hashSetName The name of the hash set to check. + * @param db The hash set to check. * * @return True if the hash set is enabled, false otherwise. */ - boolean isHashSetEnabled(String hashSetName) { - this.upgradeFromOlderVersions(); - return !(this.namesOfDisabledKnownHashSets.contains(hashSetName) || this.namesOfDisabledKnownBadHashSets.contains(hashSetName)); - } - - /** - * Get the names of all explicitly enabled known files hash sets. - * - * @return The list of names. - */ - List getNamesOfEnabledKnownHashSets() { - this.upgradeFromOlderVersions(); - return new ArrayList<>(this.namesOfEnabledKnownHashSets); - } - - /** - * Get the names of all explicitly disabled known files hash sets. - * - * @return The list of names. - */ - List getNamesOfDisabledKnownHashSets() { - this.upgradeFromOlderVersions(); - return new ArrayList<>(namesOfDisabledKnownHashSets); - } - - /** - * Get the names of all explicitly enabled notable files hash sets. - * - * @return The list of names. - */ - List getNamesOfEnabledKnownBadHashSets() { - this.upgradeFromOlderVersions(); - return new ArrayList<>(this.namesOfEnabledKnownBadHashSets); - } - - /** - * Get the names of all explicitly disabled notable files hash sets. - * - * @return The list of names. - */ - List getNamesOfDisabledKnownBadHashSets() { - this.upgradeFromOlderVersions(); - return new ArrayList<>(this.namesOfDisabledKnownBadHashSets); + boolean isHashSetEnabled(HashDb db) { + for(HashDbInfo dbInfo:databaseInfoList){ + if(dbInfo.matches(db)){ + return dbInfo.getSearchDuringIngest(); + } + } + + // We didn't find it, so use the default value + return db.getDefaultSearchDuringIngest(); } /** @@ -153,12 +144,38 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { * compatible, version of this class is de-serialized. */ private void upgradeFromOlderVersions() { - if (null == this.namesOfDisabledKnownHashSets) { - this.namesOfDisabledKnownHashSets = new HashSet<>(); + + if(databaseInfoList != null){ + return; } - if (null == this.namesOfDisabledKnownBadHashSets) { - this.namesOfDisabledKnownBadHashSets = new HashSet<>(); + + try{ + databaseInfoList = HashLookupSettings.convertHashSetList(HashDbManager.getInstance().getAllHashSets()); + } catch (HashLookupSettings.HashLookupSettingsException ex){ + Logger.getLogger(HashLookupModuleSettings.class.getName()).log(Level.SEVERE, "Error updating hash database settings.", ex); //NON-NLS + return; } + + List disabledHashSetNames = new ArrayList<>(); + if(namesOfDisabledKnownHashSets != null){ + disabledHashSetNames.addAll(namesOfDisabledKnownHashSets); + } + if(namesOfDisabledKnownBadHashSets != null){ + disabledHashSetNames.addAll(namesOfDisabledKnownBadHashSets); + } + + for(HashLookupSettings.HashDbInfo db:databaseInfoList){ + if(db.isFileDatabaseType() && disabledHashSetNames.contains(db.getHashSetName())){ + db.setSearchDuringIngest(false); + } else { + db.setSearchDuringIngest(true); + } + } + + namesOfDisabledKnownHashSets = null; + namesOfDisabledKnownBadHashSets = null; + namesOfEnabledKnownHashSets = null; + namesOfEnabledKnownBadHashSets = null; } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java index 2a78b2b5b5..bbe2a4e7d9 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java @@ -21,9 +21,7 @@ package org.sleuthkit.autopsy.modules.hashdatabase; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.logging.Level; import javax.swing.JScrollPane; import javax.swing.JTable; @@ -32,8 +30,9 @@ import javax.swing.table.TableColumn; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; + /** * Ingest job settings panel for hash lookup file ingest modules. @@ -61,8 +60,7 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe private void initializeHashSetModels(HashLookupModuleSettings settings, List hashDbs, List hashSetModels) { hashSetModels.clear(); for (HashDb db : hashDbs) { - String name = db.getHashSetName(); - hashSetModels.add(new HashSetModel(name, settings.isHashSetEnabled(name), isHashDbIndexed(db))); + hashSetModels.add(new HashSetModel(db, settings.isHashSetEnabled(db), isHashDbValid(db))); } } @@ -102,23 +100,20 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe @Override public IngestModuleIngestJobSettings getSettings() { - List enabledKnownHashSetNames = new ArrayList<>(); - List disabledKnownHashSetNames = new ArrayList<>(); - List enabledKnownBadHashSetNames = new ArrayList<>(); - List disabledKnownBadHashSetNames = new ArrayList<>(); - getHashSetNames(knownHashSetModels, enabledKnownHashSetNames, disabledKnownHashSetNames); - getHashSetNames(knownBadHashSetModels, enabledKnownBadHashSetNames, disabledKnownBadHashSetNames); + List enabledHashSets = new ArrayList<>(); + List disabledHashSets = new ArrayList<>(); + addHashSets(knownHashSetModels, enabledHashSets, disabledHashSets); + addHashSets(knownBadHashSetModels, enabledHashSets, disabledHashSets); return new HashLookupModuleSettings(alwaysCalcHashesCheckbox.isSelected(), - enabledKnownHashSetNames, enabledKnownBadHashSetNames, - disabledKnownHashSetNames, disabledKnownBadHashSetNames); + enabledHashSets, disabledHashSets); } - private void getHashSetNames(List hashSetModels, List enabledHashSetNames, List disabledHashSetNames) { + private void addHashSets(List hashSetModels, List enabledHashSets, List disabledHashSets) { for (HashSetModel model : hashSetModels) { - if (model.isEnabled() && model.isIndexed()) { - enabledHashSetNames.add(model.getName()); + if (model.isEnabled() && model.isValid()) { + enabledHashSets.add(model.getDatabase()); } else { - disabledHashSetNames.add(model.getName()); + disabledHashSets.add(model.getDatabase()); } } } @@ -135,20 +130,22 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } void updateHashSetModels(List hashDbs, List hashSetModels) { - Map hashSetDbs = new HashMap<>(); - for (HashDb db : hashDbs) { - hashSetDbs.put(db.getHashSetName(), db); - } - + + List hashDatabases = new ArrayList<>(hashDbs); + // Update the hash sets and detect deletions. List deletedHashSetModels = new ArrayList<>(); for (HashSetModel model : hashSetModels) { - String hashSetName = model.getName(); - if (hashSetDbs.containsKey(hashSetName)) { - HashDb db = hashSetDbs.get(hashSetName); - model.setIndexed(isHashDbIndexed(db)); - hashSetDbs.remove(hashSetName); - } else { + boolean foundDatabase = false; + for(HashDb db : hashDatabases){ + if(model.getDatabase().equals(db)){ + model.setValid(isHashDbValid(db)); + hashDatabases.remove(db); + foundDatabase = true; + break; + } + } + if(! foundDatabase){ deletedHashSetModels.add(model); } } @@ -159,9 +156,8 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } // Add any new hash sets. All new sets are enabled by default. - for (HashDb db : hashSetDbs.values()) { - String name = db.getHashSetName(); - hashSetModels.add(new HashSetModel(name, true, isHashDbIndexed(db))); + for (HashDb db : hashDatabases) { + hashSetModels.add(new HashSetModel(db, true, isHashDbValid(db))); } } @@ -172,30 +168,34 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe knownBadHashSetsTableModel.fireTableDataChanged(); } - private boolean isHashDbIndexed(HashDb hashDb) { - boolean indexed = false; + private boolean isHashDbValid(HashDb hashDb) { + boolean isValid = false; try { - indexed = hashDb.hasIndex(); + isValid = hashDb.isValid(); } catch (TskCoreException ex) { - Logger.getLogger(HashLookupModuleSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting indexed status info for hash set (name = " + hashDb.getHashSetName() + ")", ex); //NON-NLS + Logger.getLogger(HashLookupModuleSettingsPanel.class.getName()).log(Level.SEVERE, "Error checking validity for hash set (name = " + hashDb.getHashSetName() + ")", ex); //NON-NLS } - return indexed; + return isValid; } private static final class HashSetModel { - private final String name; - private boolean indexed; + private final HashDb db; + private boolean valid; private boolean enabled; - HashSetModel(String name, boolean enabled, boolean indexed) { - this.name = name; + HashSetModel(HashDb db, boolean enabled, boolean valid) { + this.db = db; this.enabled = enabled; - this.indexed = indexed; + this.valid = valid; + } + + HashDb getDatabase(){ + return db; } String getName() { - return name; + return db.getDisplayName(); } void setEnabled(boolean enabled) { @@ -206,12 +206,12 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe return enabled; } - void setIndexed(boolean indexed) { - this.indexed = indexed; + void setValid(boolean valid) { + this.valid = valid; } - boolean isIndexed() { - return indexed; + boolean isValid() { + return valid; } } @@ -245,7 +245,7 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe @Override public boolean isCellEditable(int rowIndex, int columnIndex) { - return (columnIndex == 0 && hashSets.get(rowIndex).isIndexed()); + return (columnIndex == 0 && hashSets.get(rowIndex).isValid()); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java index 1adcab7a35..948f18451d 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.logging.Level; import javax.swing.JOptionPane; import org.apache.commons.io.FileUtils; @@ -35,10 +36,13 @@ import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashSet; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.SleuthkitHashSet; import org.sleuthkit.datamodel.TskCoreException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Class to represent the settings to be serialized for hash lookup. @@ -69,40 +73,17 @@ final class HashLookupSettings implements Serializable { HashLookupSettings(List hashDbInfoList) { this.hashDbInfoList = hashDbInfoList; } - - /** - * Constructs a settings object to be serialized for hash lookups - * - * @param knownHashSets The list known hash sets for the settings. - * @param knownBadHashSets The list of notable hash sets for the settings. - */ - HashLookupSettings(List knownHashSets, List knownBadHashSets) throws HashLookupSettingsException { - hashDbInfoList = new ArrayList<>(); - this.addHashesToList(knownHashSets); - this.addHashesToList(knownBadHashSets); - } - - /** - * Adds each HashDb to the settings. - * - * @param hashSetList The list of HashDb to add to the settings - * - * @throws * pacannot be obtained - */ - private void addHashesToList(List hashSetList) throws HashLookupSettingsException { - for (HashDbManager.HashDb hashDb : hashSetList) { - try { - String dbPath; - if (hashDb.hasIndexOnly()) { - dbPath = hashDb.getIndexPath(); - } else { - dbPath = hashDb.getDatabasePath(); - } - hashDbInfoList.add(new HashDbInfo(hashDb.getHashSetName(), hashDb.getKnownFilesType(), hashDb.getSearchDuringIngest(), hashDb.getSendIngestMessages(), dbPath)); - } catch (TskCoreException ex) { - throw new HashLookupSettingsException("Couldn't add hash database named: " + hashDb.getHashSetName(), ex); + + static List convertHashSetList(List hashSets) throws HashLookupSettingsException{ + List dbInfoList = new ArrayList<>(); + for(HashDbManager.HashDb db:hashSets){ + try{ + dbInfoList.add(new HashDbInfo(db)); + } catch (TskCoreException ex){ + logger.log(Level.SEVERE, "Could not load database settings for {0}", db.getHashSetName()); } } + return dbInfoList; } /** @@ -299,11 +280,12 @@ final class HashLookupSettings implements Serializable { * @return Whether or not the settings were written successfully */ static boolean writeSettings(HashLookupSettings settings) { + try (NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(SERIALIZATION_FILE_PATH))) { out.writeObject(settings); return true; } catch (Exception ex) { - logger.log(Level.SEVERE, "Could not wtite hash database settings."); + logger.log(Level.SEVERE, "Could not write hash database settings."); return false; } } @@ -314,16 +296,25 @@ final class HashLookupSettings implements Serializable { * hash lookups. */ static final class HashDbInfo implements Serializable { - + + enum DatabaseType{ + FILE, + CENTRAL_REPOSITORY + }; + private static final long serialVersionUID = 1L; private final String hashSetName; private final HashDbManager.HashDb.KnownFilesType knownFilesType; - private final boolean searchDuringIngest; + private boolean searchDuringIngest; private final boolean sendIngestMessages; private final String path; + private final String version; + private final boolean readOnly; + private final int referenceSetID; + private DatabaseType dbType; /** - * Constructs a HashDbInfo object + * Constructs a HashDbInfo object for files type * * @param hashSetName The name of the hash set * @param knownFilesType The known files type @@ -338,6 +329,52 @@ final class HashLookupSettings implements Serializable { this.searchDuringIngest = searchDuringIngest; this.sendIngestMessages = sendIngestMessages; this.path = path; + this.referenceSetID = -1; + this.version = ""; + this.readOnly = false; + this.dbType = DatabaseType.FILE; + } + + HashDbInfo(String hashSetName, String version, int referenceSetID, HashDbManager.HashDb.KnownFilesType knownFilesType, boolean readOnly, boolean searchDuringIngest, boolean sendIngestMessages){ + this.hashSetName = hashSetName; + this.version = version; + this.referenceSetID = referenceSetID; + this.knownFilesType = knownFilesType; + this.readOnly = readOnly; + this.searchDuringIngest = searchDuringIngest; + this.sendIngestMessages = sendIngestMessages; + this.path = ""; + dbType = DatabaseType.CENTRAL_REPOSITORY; + } + + HashDbInfo(HashDbManager.HashDb db) throws TskCoreException{ + if(db instanceof HashDbManager.SleuthkitHashSet){ + HashDbManager.SleuthkitHashSet fileTypeDb = (HashDbManager.SleuthkitHashSet)db; + this.hashSetName = fileTypeDb.getHashSetName(); + this.knownFilesType = fileTypeDb.getKnownFilesType(); + this.searchDuringIngest = fileTypeDb.getSearchDuringIngest(); + this.sendIngestMessages = fileTypeDb.getSendIngestMessages(); + this.referenceSetID = -1; + this.version = ""; + this.readOnly = false; + this.dbType = DatabaseType.FILE; + if (fileTypeDb.hasIndexOnly()) { + this.path = fileTypeDb.getIndexPath(); + } else { + this.path = fileTypeDb.getDatabasePath(); + } + } else { + HashDbManager.CentralRepoHashSet centralRepoDb = (HashDbManager.CentralRepoHashSet)db; + this.hashSetName = centralRepoDb.getHashSetName(); + this.version = centralRepoDb.getVersion(); + this.knownFilesType = centralRepoDb.getKnownFilesType(); + this.readOnly = ! centralRepoDb.isUpdateable(); + this.searchDuringIngest = centralRepoDb.getSearchDuringIngest(); + this.sendIngestMessages = centralRepoDb.getSendIngestMessages(); + this.path = ""; + this.referenceSetID = centralRepoDb.getReferenceSetID(); + this.dbType = DatabaseType.CENTRAL_REPOSITORY; + } } /** @@ -348,6 +385,22 @@ final class HashLookupSettings implements Serializable { String getHashSetName() { return hashSetName; } + + /** + * Get the version for the hash set + * @return version + */ + String getVersion(){ + return version; + } + + /** + * Get whether the hash set is read only (only applies to central repo) + * @return readOnly + */ + boolean isReadOnly(){ + return readOnly; + } /** * Gets the known files type setting. @@ -366,6 +419,14 @@ final class HashLookupSettings implements Serializable { boolean getSearchDuringIngest() { return searchDuringIngest; } + + /** + * Sets the search during ingest setting. + * + */ + void setSearchDuringIngest(boolean searchDuringIngest) { + this.searchDuringIngest = searchDuringIngest; + } /** * Gets the send ingest messages setting. @@ -384,6 +445,111 @@ final class HashLookupSettings implements Serializable { String getPath() { return path; } + + int getReferenceSetID(){ + return referenceSetID; + } + + /** + * Returns whether the database is a normal file type. + * @return true if database is type FILE + */ + boolean isFileDatabaseType(){ + return dbType == DatabaseType.FILE; + } + + boolean isCentralRepoDatabaseType(){ + return dbType == DatabaseType.CENTRAL_REPOSITORY; + } + + boolean matches(HashDb hashDb){ + if(hashDb == null){ + return false; + } + + if( ! this.knownFilesType.equals(hashDb.getKnownFilesType())){ + return false; + } + + if((this.dbType == DatabaseType.CENTRAL_REPOSITORY) && (! (hashDb instanceof CentralRepoHashSet)) + || (this.dbType == DatabaseType.FILE) && (! (hashDb instanceof SleuthkitHashSet))){ + return false; + } + + if( ! this.hashSetName.equals(hashDb.getHashSetName())){ + return false; + } + + if(hashDb instanceof CentralRepoHashSet){ + CentralRepoHashSet crDb = (CentralRepoHashSet) hashDb; + if(this.referenceSetID != crDb.getReferenceSetID()){ + return false; + } + + if(! version.equals(crDb.getVersion())){ + return false; + } + } + + return true; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + final HashDbInfo other = (HashDbInfo) obj; + + if(! this.dbType.equals(other.dbType)){ + return false; + } + + if(this.dbType.equals(DatabaseType.FILE)){ + // For files, we expect the name and known type to match + return (this.hashSetName.equals(other.hashSetName) + && this.knownFilesType.equals(other.knownFilesType)); + } else { + // For central repo, the name, index, and known files type should match + return (this.hashSetName.equals(other.hashSetName) + && (this.referenceSetID == other.referenceSetID) + && this.knownFilesType.equals(other.knownFilesType)); + } + } + + @Override + public int hashCode() { + int hash = 5; + hash = 89 * hash + Objects.hashCode(this.hashSetName); + hash = 89 * hash + Objects.hashCode(this.knownFilesType); + hash = 89 * hash + Objects.hashCode(this.dbType); + if(this.dbType.equals(DatabaseType.CENTRAL_REPOSITORY)){ + hash = 89 * hash + this.referenceSetID; + } + + return hash; + } + + /** + * This overrides the default deserialization code so we can + * properly set the dbType enum given an old settings file. + * @param stream + * @throws IOException + * @throws ClassNotFoundException + */ + private void readObject(java.io.ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + + if(dbType == null){ + dbType = DatabaseType.FILE; + } + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form index c089bea77b..5be552d274 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form @@ -94,7 +94,7 @@ - + @@ -102,29 +102,24 @@ - - - - - - - - + + + - + - - - + + + @@ -132,22 +127,45 @@ + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + - + @@ -199,6 +217,21 @@ + + + + + + + + + + + + + + + @@ -208,12 +241,12 @@ - + - + @@ -582,6 +615,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java index 7d2b782ec1..d4a77883d6 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -38,14 +38,18 @@ import javax.swing.table.TableCellRenderer; import org.netbeans.spi.options.OptionsPanelController; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.SleuthkitHashSet; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashSet; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Instances of this class provide a comprehensive UI for managing the hash sets @@ -61,6 +65,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan .getMessage(HashLookupSettingsPanel.class, "HashDbConfigPanel.errorGettingIndexStatusText"); private final HashDbManager hashSetManager = HashDbManager.getInstance(); private final HashSetTableModel hashSetTableModel = new HashSetTableModel(); + private final List newReferenceSetIDs = new ArrayList<>(); public HashLookupSettingsPanel() { initComponents(); @@ -118,7 +123,11 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan hashDbNameLabel.setText(NO_SELECTION_TEXT); hashDbTypeLabel.setText(NO_SELECTION_TEXT); hashDbLocationLabel.setText(NO_SELECTION_TEXT); + hashDbVersionLabel.setText(NO_SELECTION_TEXT); + hashDbOrgLabel.setText(NO_SELECTION_TEXT); + hashDbReadOnlyLabel.setText(NO_SELECTION_TEXT); indexPathLabel.setText(NO_SELECTION_TEXT); + // Update indexing components. hashDbIndexStatusLabel.setText(NO_SELECTION_TEXT); @@ -142,25 +151,26 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan ingestWarningLabel.setVisible(ingestIsRunning); } + @NbBundle.Messages({"HashLookupSettingsPanel.readOnly=Read only", + "HashLookupSettingsPanel.editable=Editable", + "HashLookupSettingsPanel.updateStatusError=Error reading status", + "HashLookupSettingsPanel.notApplicable=N/A", + "HashLookupSettingsPanel.centralRepo=Central Repository" + }) private void updateComponentsForSelection(HashDb db) { boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning(); // Update descriptive labels. hashDbNameLabel.setText(db.getHashSetName()); - hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); - - try { - hashDbLocationLabel.setText(shortenPath(db.getDatabasePath())); - } catch (TskCoreException ex) { - Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting database path of " + db.getHashSetName() + " hash database", ex); //NON-NLS - hashDbLocationLabel.setText(ERROR_GETTING_PATH_TEXT); - } - - try { - indexPathLabel.setText(shortenPath(db.getIndexPath())); - } catch (TskCoreException ex) { - Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index path of " + db.getHashSetName() + " hash database", ex); //NON-NLS - indexPathLabel.setText(ERROR_GETTING_PATH_TEXT); + hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); + try{ + if(db.isUpdateable()){ + hashDbReadOnlyLabel.setText(Bundle.HashLookupSettingsPanel_editable()); + } else { + hashDbReadOnlyLabel.setText(Bundle.HashLookupSettingsPanel_readOnly()); + } + } catch (TskCoreException ex){ + hashDbReadOnlyLabel.setText(Bundle.HashLookupSettingsPanel_updateStatusError()); } try { @@ -170,45 +180,83 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan addHashesToDatabaseButton.setEnabled(false); } - // Update indexing components. - try { - if (db.isIndexing()) { - indexButton.setText( - NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.indexing")); - hashDbIndexStatusLabel.setText( - NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexGen")); - hashDbIndexStatusLabel.setForeground(Color.black); - indexButton.setEnabled(false); - } else if (db.hasIndex()) { - if (db.hasIndexOnly()) { - hashDbIndexStatusLabel.setText( - NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexOnly")); - } else { - hashDbIndexStatusLabel.setText( - NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexed")); - } - hashDbIndexStatusLabel.setForeground(Color.black); - if (db.canBeReIndexed()) { + if(db instanceof SleuthkitHashSet){ + SleuthkitHashSet hashDb = (SleuthkitHashSet)db; + + // Disable the central repo fields + hashDbVersionLabel.setText(Bundle.HashLookupSettingsPanel_notApplicable()); + hashDbOrgLabel.setText(Bundle.HashLookupSettingsPanel_notApplicable()); + + // Enable the delete button if ingest is not running + deleteDatabaseButton.setEnabled(!ingestIsRunning); + + try { + hashDbLocationLabel.setText(shortenPath(db.getDatabasePath())); + } catch (TskCoreException ex) { + Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting database path of " + db.getHashSetName() + " hash database", ex); //NON-NLS + hashDbLocationLabel.setText(ERROR_GETTING_PATH_TEXT); + } + + try { + indexPathLabel.setText(shortenPath(hashDb.getIndexPath())); + } catch (TskCoreException ex) { + Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index path of " + db.getHashSetName() + " hash database", ex); //NON-NLS + indexPathLabel.setText(ERROR_GETTING_PATH_TEXT); + } + + // Update indexing components. + try { + if (hashDb.isIndexing()) { indexButton.setText( - NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.reIndex")); - indexButton.setEnabled(true); - } else { - indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index")); + NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.indexing")); + hashDbIndexStatusLabel.setText( + NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexGen")); + hashDbIndexStatusLabel.setForeground(Color.black); indexButton.setEnabled(false); + } else if (hashDb.hasIndex()) { + if (hashDb.hasIndexOnly()) { + hashDbIndexStatusLabel.setText( + NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexOnly")); + } else { + hashDbIndexStatusLabel.setText( + NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.indexed")); + } + hashDbIndexStatusLabel.setForeground(Color.black); + if (hashDb.canBeReIndexed()) { + indexButton.setText( + NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.reIndex")); + indexButton.setEnabled(true); + } else { + indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index")); + indexButton.setEnabled(false); + } + } else { + hashDbIndexStatusLabel.setText( + NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.noIndex")); + hashDbIndexStatusLabel.setForeground(Color.red); + indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index")); + indexButton.setEnabled(true); } - } else { - hashDbIndexStatusLabel.setText( - NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexStatusText.noIndex")); + } catch (TskCoreException ex) { + Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index state of hash database", ex); //NON-NLS + hashDbIndexStatusLabel.setText(ERROR_GETTING_INDEX_STATUS_TEXT); hashDbIndexStatusLabel.setForeground(Color.red); indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index")); - indexButton.setEnabled(true); + indexButton.setEnabled(false); } - } catch (TskCoreException ex) { - Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index state of hash database", ex); //NON-NLS - hashDbIndexStatusLabel.setText(ERROR_GETTING_INDEX_STATUS_TEXT); - hashDbIndexStatusLabel.setForeground(Color.red); - indexButton.setText(NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.indexButtonText.index")); + } else { + + // Disable the file type fields/buttons + indexPathLabel.setText(Bundle.HashLookupSettingsPanel_notApplicable()); + hashDbIndexStatusLabel.setText(Bundle.HashLookupSettingsPanel_notApplicable()); + hashDbLocationLabel.setText(Bundle.HashLookupSettingsPanel_centralRepo()); indexButton.setEnabled(false); + deleteDatabaseButton.setEnabled(false); + + CentralRepoHashSet crDb = (CentralRepoHashSet)db; + + hashDbVersionLabel.setText(crDb.getVersion()); + hashDbOrgLabel.setText(crDb.getOrgName()); } // Disable the indexing button if ingest is in progress. @@ -218,14 +266,13 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan // Update ingest option components. sendIngestMessagesCheckBox.setSelected(db.getSendIngestMessages()); - sendIngestMessagesCheckBox.setEnabled(!ingestIsRunning && db.getSearchDuringIngest() && db.getKnownFilesType().equals(KnownFilesType.KNOWN_BAD)); + sendIngestMessagesCheckBox.setEnabled(!ingestIsRunning && db.getKnownFilesType().equals(KnownFilesType.KNOWN_BAD)); optionsLabel.setEnabled(!ingestIsRunning); optionsSeparator.setEnabled(!ingestIsRunning); // Update database action buttons. createDatabaseButton.setEnabled(true); importDatabaseButton.setEnabled(true); - deleteDatabaseButton.setEnabled(!ingestIsRunning); // Update ingest in progress warning label. ingestWarningLabel.setVisible(ingestIsRunning); @@ -255,16 +302,19 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan @Override @Messages({"HashLookupSettingsPanel.saveFail.message=Couldn't save hash db settings.", "HashLookupSettingsPanel.saveFail.title=Save Fail"}) - public void saveSettings() { + public void saveSettings() { //Checking for for any unindexed databases - List unindexed = new ArrayList<>(); - for (HashDb hashSet : hashSetManager.getAllHashSets()) { - try { - if (!hashSet.hasIndex()) { - unindexed.add(hashSet); + List unindexed = new ArrayList<>(); + for (HashDb db : hashSetManager.getAllHashSets()) { + if(db instanceof SleuthkitHashSet){ + try { + SleuthkitHashSet hashDatabase = (SleuthkitHashSet)db; + if (!hashDatabase.hasIndex()) { + unindexed.add(hashDatabase); + } + } catch (TskCoreException ex) { + Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex); //NON-NLS } - } catch (TskCoreException ex) { - Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex); //NON-NLS } } @@ -274,8 +324,10 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } else if (unindexed.size() > 1) { showInvalidIndex(true, unindexed); } + try { hashSetManager.save(); + newReferenceSetIDs.clear(); } catch (HashDbManager.HashDbManagerException ex) { SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(null, Bundle.HashLookupSettingsPanel_saveFail_message(), Bundle.HashLookupSettingsPanel_saveFail_title(), JOptionPane.ERROR_MESSAGE); @@ -301,13 +353,28 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan * closed while they are still being used. */ if (IngestManager.getInstance().isIngestRunning() == false) { + // Remove any new central repo hash sets from the database + for(int refID:newReferenceSetIDs){ + try{ + if(EamDb.isEnabled()){ + EamDb.getInstance().deleteReferenceSet(refID); + } else { + // This is the case where the user imported a database, then switched over to the central + // repo panel and disabled it before cancelling. We can't delete the database at this point. + Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.WARNING, "Error reverting central repository hash sets"); //NON-NLS + } + } catch (EamDbException ex){ + Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error reverting central repository hash sets", ex); //NON-NLS + } + } + HashDbManager.getInstance().loadLastSavedConfiguration(); } } @Messages({"# {0} - hash lookup name", "HashLookupSettingsPanel.removeDatabaseFailure.message=Failed to remove hash lookup: {0}"}) - void removeThese(List toRemove) { - for (HashDb hashDb : toRemove) { + void removeThese(List toRemove) { + for (SleuthkitHashSet hashDb : toRemove) { try { hashSetManager.removeHashDatabaseNoSave(hashDb); } catch (HashDbManager.HashDbManagerException ex) { @@ -325,7 +392,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan * @param plural Whether or not there are multiple unindexed databases * @param unindexed The list of unindexed databases. Can be of size 1. */ - private void showInvalidIndex(boolean plural, List unindexed) { + private void showInvalidIndex(boolean plural, List unindexed) { String total = ""; String message; for (HashDb hdb : unindexed) { @@ -372,7 +439,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan // Give the user a visual indication of any hash sets with a hash // database that needs to be indexed by displaying the hash set name // in red. - if (hashSetTableModel.indexExists(row)) { + if (hashSetTableModel.isValid(row)) { cellRenderer.setForeground(Color.black); } else { cellRenderer.setForeground(Color.red); @@ -390,7 +457,12 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan getSelectionModel().setSelectionInterval(index, index); } } + + public void selectRowByDatabase(HashDb db){ + setSelection(hashSetTableModel.getIndexByDatabase(db)); + } + @Deprecated public void selectRowByName(String name) { setSelection(hashSetTableModel.getIndexByName(name)); } @@ -424,9 +496,9 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan return hashSets.get(rowIndex).getHashSetName(); } - private boolean indexExists(int rowIndex) { + private boolean isValid(int rowIndex) { try { - return hashSets.get(rowIndex).hasIndex(); + return hashSets.get(rowIndex).isValid(); } catch (TskCoreException ex) { Logger.getLogger(HashSetTableModel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex); //NON-NLS return false; @@ -457,6 +529,16 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } } + int getIndexByDatabase(HashDb db){ + for (int i = 0; i < hashSets.size(); ++i) { + if (hashSets.get(i).equals(db)) { + return i; + } + } + return -1; + } + + @Deprecated int getIndexByName(String name) { for (int i = 0; i < hashSets.size(); ++i) { if (hashSets.get(i).getHashSetName().equals(name)) { @@ -514,6 +596,12 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan indexPathLabelLabel = new javax.swing.JLabel(); indexPathLabel = new javax.swing.JLabel(); addHashesToDatabaseButton = new javax.swing.JButton(); + versionLabel = new javax.swing.JLabel(); + hashDbVersionLabel = new javax.swing.JLabel(); + orgLabel = new javax.swing.JLabel(); + hashDbOrgLabel = new javax.swing.JLabel(); + readOnlyLabel = new javax.swing.JLabel(); + hashDbReadOnlyLabel = new javax.swing.JLabel(); jLabel2.setFont(jLabel2.getFont().deriveFont(jLabel2.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.jLabel2.text")); // NOI18N @@ -652,6 +740,18 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } }); + org.openide.awt.Mnemonics.setLocalizedText(versionLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.versionLabel.text_1")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(hashDbVersionLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDbVersionLabel.text_1")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(orgLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.orgLabel.text_1")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(hashDbOrgLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDbOrgLabel.text_1")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(readOnlyLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.readOnlyLabel.text_1")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(hashDbReadOnlyLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDbReadOnlyLabel.text_1")); // NOI18N + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( @@ -669,41 +769,54 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan .addGap(309, 309, 309)) .addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() - .addComponent(optionsLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(optionsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 334, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(jPanel1Layout.createSequentialGroup() .addGap(10, 10, 10) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(locationLabel) - .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 120, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(typeLabel) - .addComponent(indexLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(indexPathLabelLabel)) - .addGap(10, 10, 10) + .addComponent(versionLabel) + .addComponent(orgLabel) + .addComponent(readOnlyLabel)) + .addGap(55, 55, 55) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(hashDbTypeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(hashDbLocationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(indexPathLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(hashDbIndexStatusLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(addHashesToDatabaseButton))) + .addComponent(hashDbVersionLabel) + .addComponent(hashDbOrgLabel) + .addComponent(hashDbReadOnlyLabel))) .addGroup(jPanel1Layout.createSequentialGroup() .addComponent(nameLabel) .addGap(53, 53, 53) - .addComponent(hashDbNameLabel)))) + .addComponent(hashDbNameLabel)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(indexLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(indexPathLabelLabel)) + .addGap(64, 64, 64) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(indexPathLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(hashDbIndexStatusLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 120, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(10, 10, 10) + .addComponent(addHashesToDatabaseButton)))) .addGroup(jPanel1Layout.createSequentialGroup() .addGap(70, 70, 70) .addComponent(informationSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 305, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(10, 10, 10) - .addComponent(ingestWarningLabel)) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(25, 25, 25) - .addComponent(sendIngestMessagesCheckBox))) - .addGap(50, 50, 50)))) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addComponent(optionsLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(optionsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 334, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(25, 25, 25) + .addComponent(sendIngestMessagesCheckBox)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(ingestWarningLabel)))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) .addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(hashDatabasesLabel) @@ -741,6 +854,18 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan .addComponent(locationLabel) .addComponent(hashDbLocationLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(versionLabel) + .addComponent(hashDbVersionLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(orgLabel) + .addComponent(hashDbOrgLabel)) + .addGap(7, 7, 7) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(readOnlyLabel) + .addComponent(hashDbReadOnlyLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(indexPathLabelLabel) .addComponent(indexPathLabel)) @@ -748,11 +873,11 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(indexLabel) .addComponent(hashDbIndexStatusLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(indexButton) .addComponent(addHashesToDatabaseButton)) - .addGap(18, 18, 18) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(optionsLabel) .addComponent(optionsSeparator, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) @@ -796,7 +921,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan HashDb hashDb = new HashDbCreateDatabaseDialog().getHashDatabase(); if (null != hashDb) { hashSetTableModel.refreshModel(); - ((HashSetTable) hashSetTable).selectRowByName(hashDb.getHashSetName()); + ((HashSetTable) hashSetTable).selectRowByDatabase(hashDb); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } }//GEN-LAST:event_createDatabaseButtonActionPerformed @@ -810,15 +935,17 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan }//GEN-LAST:event_sendIngestMessagesCheckBoxActionPerformed private void indexButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexButtonActionPerformed - final HashDb hashDb = ((HashSetTable) hashSetTable).getSelection(); - assert hashDb != null; + final HashDb hashDatabase = ((HashSetTable) hashSetTable).getSelection(); + assert hashDatabase != null; + assert hashDatabase instanceof SleuthkitHashSet; // Add a listener for the INDEXING_DONE event. This listener will update // the UI. + SleuthkitHashSet hashDb = (SleuthkitHashSet)hashDatabase; hashDb.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) { + if (evt.getPropertyName().equals(SleuthkitHashSet.Event.INDEXING_DONE.toString())) { HashDb selectedHashDb = ((HashSetTable) hashSetTable).getSelection(); if (selectedHashDb != null && hashDb != null && hashDb.equals(selectedHashDb)) { updateComponents(); @@ -842,8 +969,13 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan private void importDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importDatabaseButtonActionPerformed HashDb hashDb = new HashDbImportDatabaseDialog().getHashDatabase(); if (null != hashDb) { + if(hashDb instanceof CentralRepoHashSet){ + int newReferenceSetID = ((CentralRepoHashSet)hashDb).getReferenceSetID(); + newReferenceSetIDs.add(newReferenceSetID); + } + hashSetTableModel.refreshModel(); - ((HashSetTable) hashSetTable).selectRowByName(hashDb.getHashSetName()); + ((HashSetTable) hashSetTable).selectRowByDatabase(hashDb); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } }//GEN-LAST:event_importDatabaseButtonActionPerformed @@ -892,7 +1024,10 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan private javax.swing.JLabel hashDbIndexStatusLabel; private javax.swing.JLabel hashDbLocationLabel; private javax.swing.JLabel hashDbNameLabel; + private javax.swing.JLabel hashDbOrgLabel; + private javax.swing.JLabel hashDbReadOnlyLabel; private javax.swing.JLabel hashDbTypeLabel; + private javax.swing.JLabel hashDbVersionLabel; private javax.swing.JTable hashSetTable; private javax.swing.JButton importDatabaseButton; private javax.swing.JButton indexButton; @@ -913,7 +1048,10 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan private javax.swing.JLabel nameLabel; private javax.swing.JLabel optionsLabel; private javax.swing.JSeparator optionsSeparator; + private javax.swing.JLabel orgLabel; + private javax.swing.JLabel readOnlyLabel; private javax.swing.JCheckBox sendIngestMessagesCheckBox; private javax.swing.JLabel typeLabel; + private javax.swing.JLabel versionLabel; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.form new file mode 100644 index 0000000000..4d2ada136b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.form @@ -0,0 +1,108 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java new file mode 100644 index 0000000000..880feabcb7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java @@ -0,0 +1,395 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2016 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.modules.hashdatabase; + +import java.awt.Cursor; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeEvent; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import javax.swing.JFrame; +import javax.swing.SwingWorker; +import javax.swing.WindowConstants; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.Executors; +import javax.swing.JOptionPane; +import org.openide.util.NbBundle; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalFileInstance; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalSet; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; + +/** + * + */ +class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements PropertyChangeListener{ + + private CentralRepoImportWorker worker; + + /** + * + * @param hashSetName + * @param version + * @param orgId + * @param searchDuringIngest + * @param sendIngestMessages + * @param knownFilesType + * @param importFile + */ + @NbBundle.Messages({"ImportCentralRepoDbProgressDialog.title.text=Central Repository Import Progress", + }) + ImportCentralRepoDbProgressDialog() { + super((JFrame) WindowManager.getDefault().getMainWindow(), + Bundle.ImportCentralRepoDbProgressDialog_title_text(), + true); + + initComponents(); + customizeComponents(); + } + + private void customizeComponents(){ + setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + bnOk.setEnabled(false); + } + + void importFile(String hashSetName, String version, int orgId, + boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.HashDb.KnownFilesType knownFilesType, + boolean readOnly, String importFileName){ + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + File importFile = new File(importFileName); + worker = new ImportIDXWorker(hashSetName, version, orgId, searchDuringIngest, sendIngestMessages, + knownFilesType, readOnly, importFile); + worker.addPropertyChangeListener(this); + worker.execute(); + + setLocationRelativeTo((JFrame) WindowManager.getDefault().getMainWindow()); + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + this.setVisible(true); + } + + HashDbManager.HashDb getDatabase(){ + if(worker != null){ + return worker.getDatabase(); + } + return null; + } + + @NbBundle.Messages({"ImportCentralRepoDbProgressDialog.linesProcessed= lines processed"}) + @Override + public void propertyChange(PropertyChangeEvent evt) { + + if("progress".equals(evt.getPropertyName())){ + progressBar.setValue(worker.getProgressPercentage()); + lbProgress.setText(getProgressString()); + } else if ("state".equals(evt.getPropertyName()) + && (SwingWorker.StateValue.DONE.equals(evt.getNewValue()))) { + // Disable cancel and enable ok + bnCancel.setEnabled(false); + bnOk.setEnabled(true); + + progressBar.setValue(progressBar.getMaximum()); + lbProgress.setText(getProgressString()); + } + } + + private String getProgressString(){ + return worker.getLinesProcessed() + Bundle.ImportCentralRepoDbProgressDialog_linesProcessed(); + } + + private interface CentralRepoImportWorker{ + + void execute(); + boolean cancel(boolean mayInterruptIfRunning); + void addPropertyChangeListener(PropertyChangeListener dialog); + int getProgressPercentage(); + long getLinesProcessed(); + HashDbManager.HashDb getDatabase(); + } + + class ImportIDXWorker extends SwingWorker implements CentralRepoImportWorker{ + + private final int HASH_IMPORT_THRESHOLD = 10000; + private final String hashSetName; + private final String version; + private final int orgId; + private final boolean searchDuringIngest; + private final boolean sendIngestMessages; + private final HashDbManager.HashDb.KnownFilesType knownFilesType; + private final boolean readOnly; + private final File importFile; + private final long totalLines; + private int referenceSetID = -1; + private HashDbManager.CentralRepoHashSet newHashDb = null; + private final AtomicLong numLines = new AtomicLong(); + + ImportIDXWorker(String hashSetName, String version, int orgId, + boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.HashDb.KnownFilesType knownFilesType, + boolean readOnly, File importFile){ + + this.hashSetName = hashSetName; + this.version = version; + this.orgId = orgId; + this.searchDuringIngest = searchDuringIngest; + this.sendIngestMessages = sendIngestMessages; + this.knownFilesType = knownFilesType; + this.readOnly = readOnly; + this.importFile = importFile; + this.numLines.set(0); + + this.totalLines = getEstimatedTotalHashes(); + } + + /** + * Doing an actual count of the number of lines in a large idx file (such + * as the nsrl) is slow, so just get something in the general area for the + * progress bar. + * @return Approximate number of hashes in the file + */ + final long getEstimatedTotalHashes(){ + long fileSize = importFile.length(); + return (fileSize / 0x33 + 1); // IDX file lines are generally 0x33 bytes long, and we don't want this to be zero + } + + @Override + public HashDbManager.HashDb getDatabase(){ + return newHashDb; + } + + @Override + public long getLinesProcessed(){ + return numLines.get(); + } + + @Override + public int getProgressPercentage(){ + return this.getProgress(); + } + + @Override + protected Void doInBackground() throws Exception { + + TskData.FileKnown knownStatus; + if (knownFilesType.equals(HashDbManager.HashDb.KnownFilesType.KNOWN)) { + knownStatus = TskData.FileKnown.KNOWN; + } else { + knownStatus = TskData.FileKnown.BAD; + } + + // Create an empty hashset in the central repository + referenceSetID = EamDb.getInstance().newReferenceSet(new EamGlobalSet(orgId, hashSetName, version, knownStatus, readOnly)); + + EamDb dbManager = EamDb.getInstance(); + CorrelationAttribute.Type contentType = dbManager.getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID); // get "FILES" type + BufferedReader reader = new BufferedReader(new FileReader(importFile)); + String line; + Set globalInstances = new HashSet<>(); + + while ((line = reader.readLine()) != null) { + if(isCancelled()){ + return null; + } + + String[] parts = line.split("\\|"); + + // Header lines start with a 41 character dummy hash, 1 character longer than a SHA-1 hash + if (parts.length != 2 || parts[0].length() == 41) { + continue; + } + + EamGlobalFileInstance eamGlobalFileInstance = new EamGlobalFileInstance( + referenceSetID, + parts[0].toLowerCase(), + knownStatus, + ""); + + globalInstances.add(eamGlobalFileInstance); + numLines.incrementAndGet(); + + if(numLines.get() % HASH_IMPORT_THRESHOLD == 0){ + dbManager.bulkInsertReferenceTypeEntries(globalInstances, contentType); + globalInstances.clear(); + + int progress = (int)(numLines.get() * 100 / totalLines); + if(progress < 100){ + this.setProgress(progress); + } else { + this.setProgress(99); + } + } + } + + dbManager.bulkInsertReferenceTypeEntries(globalInstances, contentType); + this.setProgress(100); + + return null; + } + + private void deleteIncompleteSet(int idToDelete){ + if(idToDelete >= 0){ + + // This can be slow on large reference sets + Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override + public void run() { + try{ + EamDb.getInstance().deleteReferenceSet(idToDelete); + } catch (EamDbException ex2){ + Logger.getLogger(ImportCentralRepoDbProgressDialog.class.getName()).log(Level.SEVERE, "Error deleting incomplete hash set from central repository", ex2); + } + } + }); + } + } + + @NbBundle.Messages({"ImportCentralRepoDbProgressDialog.addDbError.message=Error adding new hash set"}) + @Override + protected void done() { + if(isCancelled()){ + // If the user hit cancel, delete this incomplete hash set from the central repo + deleteIncompleteSet(referenceSetID); + return; + } + + try { + get(); + try{ + newHashDb = HashDbManager.getInstance().addExistingCentralRepoHashSet(hashSetName, version, + referenceSetID, + searchDuringIngest, sendIngestMessages, knownFilesType, readOnly); + } catch (TskCoreException ex){ + JOptionPane.showMessageDialog(null, Bundle.ImportCentralRepoDbProgressDialog_addDbError_message()); + Logger.getLogger(ImportCentralRepoDbProgressDialog.class.getName()).log(Level.SEVERE, "Error adding imported hash set", ex); + } + } catch (Exception ex) { + // Delete this incomplete hash set from the central repo + if(referenceSetID >= 0){ + try{ + EamDb.getInstance().deleteReferenceSet(referenceSetID); + } catch (EamDbException ex2){ + Logger.getLogger(ImportCentralRepoDbProgressDialog.class.getName()).log(Level.SEVERE, "Error deleting incomplete hash set from central repository", ex); + } + } + } + } + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + progressBar = new javax.swing.JProgressBar(); + lbProgress = new javax.swing.JLabel(); + bnOk = new javax.swing.JButton(); + bnCancel = new javax.swing.JButton(); + jLabel1 = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + + org.openide.awt.Mnemonics.setLocalizedText(lbProgress, org.openide.util.NbBundle.getMessage(ImportCentralRepoDbProgressDialog.class, "ImportCentralRepoDbProgressDialog.lbProgress.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(bnOk, org.openide.util.NbBundle.getMessage(ImportCentralRepoDbProgressDialog.class, "ImportCentralRepoDbProgressDialog.bnOk.text")); // NOI18N + bnOk.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnOkActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(bnCancel, org.openide.util.NbBundle.getMessage(ImportCentralRepoDbProgressDialog.class, "ImportCentralRepoDbProgressDialog.bnCancel.text")); // NOI18N + bnCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnCancelActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(ImportCentralRepoDbProgressDialog.class, "ImportCentralRepoDbProgressDialog.jLabel1.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(progressBar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel1) + .addComponent(lbProgress)) + .addGap(0, 172, Short.MAX_VALUE)))) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnCancel) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(lbProgress) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bnCancel) + .addComponent(bnOk)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void bnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnCancelActionPerformed + this.worker.cancel(true); + this.dispose(); + }//GEN-LAST:event_bnCancelActionPerformed + + private void bnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOkActionPerformed + this.dispose(); + }//GEN-LAST:event_bnOkActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton bnCancel; + private javax.swing.JButton bnOk; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel lbProgress; + private javax.swing.JProgressBar progressBar; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java index 33f65488d2..41a9fe4fe8 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java @@ -26,7 +26,7 @@ import java.util.List; import javax.swing.JOptionPane; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.SleuthkitHashSet; /** * This class exists as a stop-gap measure to force users to have an indexed @@ -43,8 +43,8 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; */ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListener { - List unindexed; - HashDb toIndex; + List unindexed; + SleuthkitHashSet toIndex; HashLookupSettingsPanel hdbmp; int length = 0; int currentcount = 1; @@ -58,7 +58,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed the list of unindexed databases to index. */ - ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, List unindexed) { + ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, List unindexed) { super(parent, NbBundle.getMessage(ModalNoButtons.class, "ModalNoButtons.indexingDbsTitle"), true); this.unindexed = unindexed; this.toIndex = null; @@ -75,7 +75,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed The unindexed database to index. */ - ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, HashDb unindexed) { + ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, SleuthkitHashSet unindexed) { super(parent, NbBundle.getMessage(ModalNoButtons.class, "ModalNoButtons.indexingDbTitle"), true); this.unindexed = null; this.toIndex = unindexed; @@ -183,7 +183,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen "ModalNoButtons.dlgTitle.unfinishedIndexing"), JOptionPane.YES_NO_OPTION); if (res == JOptionPane.YES_OPTION) { - List remove = new ArrayList<>(); + List remove = new ArrayList<>(); if (this.toIndex == null) { remove = this.unindexed; } else { @@ -230,7 +230,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen private void indexThese() { length = this.unindexed.size(); this.INDEXING_PROGBAR.setIndeterminate(true); - for (HashDb db : this.unindexed) { + for (SleuthkitHashSet db : this.unindexed) { currentDb = db.getHashSetName(); this.CURRENTDB_LABEL.setText("(" + currentDb + ")"); this.CURRENTLYON_LABEL.setText( @@ -255,7 +255,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * this dialog if all indexing is complete. */ public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.name())) { + if (evt.getPropertyName().equals(SleuthkitHashSet.Event.INDEXING_DONE.name())) { if (currentcount >= length) { this.INDEXING_PROGBAR.setValue(100); this.setModal(false); diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form index 377dad7826..dfe9ba921e 100755 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form @@ -124,7 +124,7 @@ - +
diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java old mode 100755 new mode 100644 index 1066973f58..4dd665b890 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java @@ -22,7 +22,6 @@ import java.awt.Component; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -41,6 +40,7 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettingsPanel; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; + /** * Instances of this class are used to configure the report module plug in that * provides a convenient way to add content hashes to hash set databases. @@ -48,12 +48,10 @@ import org.sleuthkit.datamodel.TskCoreException; class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private final static String NO_DATABASES_TEXT = "No updateable hash sets"; private List tagNames; private final Map tagNameSelections = new LinkedHashMap<>(); private final TagNamesListModel tagsNamesListModel = new TagNamesListModel(); private final TagsNamesListCellRenderer tagsNamesRenderer = new TagsNamesListCellRenderer(); - private final Map hashSets = new HashMap<>(); private HashDb selectedHashSet = null; AddTaggedHashesToHashDbConfigPanel() { @@ -105,7 +103,6 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { private void populateHashSetComponents() { // Clear the components because this method is called both during construction // and when the user changes the hash set configuration. - hashSets.clear(); hashSetsComboBox.removeAllItems(); // Get the updateable hash databases and add their hash set names to the @@ -113,12 +110,10 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { List updateableHashSets = HashDbManager.getInstance().getUpdateableHashSets(); if (!updateableHashSets.isEmpty()) { for (HashDb hashDb : updateableHashSets) { - hashSets.put(hashDb.getHashSetName(), hashDb); - hashSetsComboBox.addItem(hashDb.getHashSetName()); + hashSetsComboBox.addItem(hashDb); } hashSetsComboBox.setEnabled(true); } else { - hashSetsComboBox.addItem(NO_DATABASES_TEXT); hashSetsComboBox.setEnabled(false); } } @@ -291,8 +286,7 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { }//GEN-LAST:event_selectAllButtonActionPerformed private void hashSetsComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hashSetsComboBoxActionPerformed - String key = (String)hashSetsComboBox.getSelectedItem(); - selectedHashSet = hashSets.get(key); + selectedHashSet = (HashDb)hashSetsComboBox.getSelectedItem(); }//GEN-LAST:event_hashSetsComboBoxActionPerformed private void deselectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deselectAllButtonActionPerformed @@ -317,7 +311,7 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton configureHashDatabasesButton; private javax.swing.JButton deselectAllButton; - private javax.swing.JComboBox hashSetsComboBox; + private javax.swing.JComboBox hashSetsComboBox; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JScrollPane jScrollPane1; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java index ccb2e49e54..1720b4b647 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java @@ -1122,7 +1122,7 @@ public class SharedConfiguration { try { HashDbManager hashDbManager = HashDbManager.getInstance(); hashDbManager.loadLastSavedConfiguration(); - for (HashDb hashDb : hashDbManager.getAllHashSets()) { + for (HashDbManager.HashDb hashDb : hashDbManager.getAllHashSets()) { if (hashDb.hasIndexOnly()) { results.add(hashDb.getIndexPath()); } else {