diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml
index 2158785ecc..37af0be24b 100644
--- a/Core/nbproject/project.xml
+++ b/Core/nbproject/project.xml
@@ -340,6 +340,7 @@
org.sleuthkit.autopsy.reportorg.sleuthkit.autopsy.textextractorsorg.sleuthkit.autopsy.textextractors.extractionconfigs
+ org.sleuthkit.autopsy.texttranslationorg.sleuthkit.datamodel
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
index 0080ade4fb..191d1c3bc6 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
@@ -430,13 +430,14 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
CorrelationCase corCase = EamDb.getInstance().getCase(Case.getCurrentCase());
try {
ret.add(new CorrelationAttributeInstance(
- md5,
aType,
+ md5,
corCase,
CorrelationDataSource.fromTSKDataSource(corCase, file.getDataSource()),
file.getParentPath() + file.getName(),
"",
- file.getKnown()));
+ file.getKnown(),
+ file.getId()));
} catch (CorrelationAttributeNormalizationException ex) {
LOGGER.log(Level.INFO, String.format("Unable to check create CorrelationAttribtueInstance for value %s and type %s.", md5, aType.toString()), ex);
}
@@ -458,8 +459,8 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
.filter(attrType -> attrType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID)
.findAny()
.get();
-
- ret.add(new CorrelationAttributeInstance(fileAttributeType, md5));
+ //The Central Repository is not enabled
+ ret.add(new CorrelationAttributeInstance(fileAttributeType, md5, null, null, "", "", TskData.FileKnown.UNKNOWN, this.file.getId()));
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
} catch (CorrelationAttributeNormalizationException ex) {
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java
index e1e87024f0..cf37286b39 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java
@@ -71,7 +71,7 @@ abstract class AbstractSqlEamDb implements EamDb {
private static final Cache caseCacheById = CacheBuilder.newBuilder()
.expireAfterWrite(CASE_CACHE_TIMEOUT, TimeUnit.MINUTES).
build();
- private static final Cache dataSourceCacheByDeviceId = CacheBuilder.newBuilder()
+ private static final Cache dataSourceCacheByDsObjectId = CacheBuilder.newBuilder()
.expireAfterWrite(DATA_SOURCE_CACHE_TIMEOUT, TimeUnit.MINUTES).
build();
private static final Cache dataSourceCacheById = CacheBuilder.newBuilder()
@@ -95,7 +95,7 @@ abstract class AbstractSqlEamDb implements EamDb {
defaultCorrelationTypes = CorrelationAttributeInstance.getDefaultCorrelationTypes();
defaultCorrelationTypes.forEach((type) -> {
- bulkArtifacts.put(type.getDbTableName(), new ArrayList<>());
+ bulkArtifacts.put(EamDbUtil.correlationTypeToInstanceTableName(type), new ArrayList<>());
});
}
@@ -133,6 +133,24 @@ abstract class AbstractSqlEamDb implements EamDb {
}
+ @Override
+ public void addDataSourceObjectId(int rowId, long dataSourceObjectId) throws EamDbException {
+ Connection conn = connect();
+ PreparedStatement preparedStatement = null;
+ String sql = "UPDATE data_sources SET datasource_obj_id=? WHERE id=?";
+ try {
+ preparedStatement = conn.prepareStatement(sql);
+ preparedStatement.setLong(1, dataSourceObjectId);
+ preparedStatement.setInt(2, rowId);
+ preparedStatement.executeUpdate();
+ } catch (SQLException ex) {
+ throw new EamDbException("Error updating data source object id for data_sources row " + rowId, ex);
+ } finally {
+ EamDbUtil.closeStatement(preparedStatement);
+ EamDbUtil.closeConnection(conn);
+ }
+ }
+
/**
* Get the value for the given name from the name/value db_info table.
*
@@ -175,7 +193,7 @@ abstract class AbstractSqlEamDb implements EamDb {
typeCache.invalidateAll();
caseCacheByUUID.invalidateAll();
caseCacheById.invalidateAll();
- dataSourceCacheByDeviceId.invalidateAll();
+ dataSourceCacheByDsObjectId.invalidateAll();
dataSourceCacheById.invalidateAll();
}
@@ -551,16 +569,17 @@ abstract class AbstractSqlEamDb implements EamDb {
}
/**
- * Create a key to the DataSourceCacheByDeviceId
+ * Create a key to the dataSourceCacheByDsObjectId
*
* @param caseId - the id of the CorrelationCase in the Central
* Repository
- * @param dataSourceDeviceId - the device Id of the data source
+ * @param dataSourceObjectId - the object id if of the data source in the
+ * case db
*
- * @return a String to be used as a key for the dataSourceCacheByDeviceId
+ * @return a String to be used as a key for the dataSourceCacheByDsObjectId
*/
- private static String getDataSourceByDeviceIdCacheKey(int caseId, String dataSourceDeviceId) {
- return "Case" + caseId + "DeviceId" + dataSourceDeviceId; //NON-NLS
+ private static String getDataSourceByDSObjectIdCacheKey(int caseId, Long dataSourceObjectId) {
+ return "Case" + caseId + "DsObjectId" + dataSourceObjectId; //NON-NLS
}
/**
@@ -582,18 +601,18 @@ abstract class AbstractSqlEamDb implements EamDb {
* @param eamDataSource the data source to add
*/
@Override
- public void newDataSource(CorrelationDataSource eamDataSource) throws EamDbException {
+ public CorrelationDataSource newDataSource(CorrelationDataSource eamDataSource) throws EamDbException {
if (eamDataSource.getCaseID() == -1) {
throw new EamDbException("Case ID is -1");
} else if (eamDataSource.getID() != -1) {
// This data source is already in the central repo
- return;
+ return eamDataSource;
}
Connection conn = connect();
PreparedStatement preparedStatement = null;
- String sql = "INSERT INTO data_sources(device_id, case_id, name) VALUES (?, ?, ?) "
+ String sql = "INSERT INTO data_sources(device_id, case_id, name, datasource_obj_id) VALUES (?, ?, ?, ?) "
+ getConflictClause();
ResultSet resultSet = null;
try {
@@ -602,6 +621,7 @@ abstract class AbstractSqlEamDb implements EamDb {
preparedStatement.setString(1, eamDataSource.getDeviceID());
preparedStatement.setInt(2, eamDataSource.getCaseID());
preparedStatement.setString(3, eamDataSource.getName());
+ preparedStatement.setLong(4, eamDataSource.getDataSourceObjectID());
preparedStatement.executeUpdate();
resultSet = preparedStatement.getGeneratedKeys();
@@ -609,9 +629,10 @@ abstract class AbstractSqlEamDb implements EamDb {
throw new EamDbException(String.format("Failed to INSERT data source %s in central repo", eamDataSource.getName()));
}
int dataSourceId = resultSet.getInt(1); //last_insert_rowid()
- CorrelationDataSource dataSource = new CorrelationDataSource(eamDataSource.getCaseID(), dataSourceId, eamDataSource.getDeviceID(), eamDataSource.getName());
- dataSourceCacheByDeviceId.put(getDataSourceByDeviceIdCacheKey(dataSource.getCaseID(), dataSource.getDeviceID()), dataSource);
+ CorrelationDataSource dataSource = new CorrelationDataSource(eamDataSource.getCaseID(), dataSourceId, eamDataSource.getDeviceID(), eamDataSource.getName(), eamDataSource.getDataSourceObjectID());
+ dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(dataSource.getCaseID(), dataSource.getDataSourceObjectID()), dataSource);
dataSourceCacheById.put(getDataSourceByIdCacheKey(dataSource.getCaseID(), dataSource.getID()), dataSource);
+ return dataSource;
} catch (SQLException ex) {
throw new EamDbException("Error inserting new data source.", ex); // NON-NLS
} finally {
@@ -622,24 +643,24 @@ abstract class AbstractSqlEamDb implements EamDb {
}
/**
- * Retrieves Data Source details based on data source device ID
+ * Retrieves Data Source details based on data source object ID
*
* @param correlationCase the current CorrelationCase used for ensuring
* uniqueness of DataSource
- * @param dataSourceDeviceId the data source device ID number
+ * @param dataSourceObjectId the object id of the data source
*
* @return The data source
*
* @throws EamDbException
*/
@Override
- public CorrelationDataSource getDataSource(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException {
+ public CorrelationDataSource getDataSource(CorrelationCase correlationCase, Long dataSourceObjectId) throws EamDbException {
if (correlationCase == null) {
throw new EamDbException("Correlation case is null");
}
try {
- return dataSourceCacheByDeviceId.get(getDataSourceByDeviceIdCacheKey(correlationCase.getID(), dataSourceDeviceId), () -> getDataSourceFromCr(correlationCase, dataSourceDeviceId));
+ return dataSourceCacheByDsObjectId.get(getDataSourceByDSObjectIdCacheKey(correlationCase.getID(), dataSourceObjectId), () -> getDataSourceFromCr(correlationCase, dataSourceObjectId));
} catch (CacheLoader.InvalidCacheLoadException ignored) {
//lambda valueloader returned a null value and cache can not store null values this is normal if the dataSource does not exist in the central repo yet
return null;
@@ -654,24 +675,24 @@ abstract class AbstractSqlEamDb implements EamDb {
*
* @param correlationCase the current CorrelationCase used for ensuring
* uniqueness of DataSource
- * @param dataSourceDeviceId the data source device ID number
+ * @param dataSourceDeviceId the object id of the data source
*
* @return The data source
*
* @throws EamDbException
*/
- private CorrelationDataSource getDataSourceFromCr(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException {
+ private CorrelationDataSource getDataSourceFromCr(CorrelationCase correlationCase, Long dataSourceObjectId) throws EamDbException {
Connection conn = connect();
CorrelationDataSource eamDataSourceResult = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
- String sql = "SELECT * FROM data_sources WHERE device_id=? AND case_id=?"; // NON-NLS
+ String sql = "SELECT * FROM data_sources WHERE datasource_obj_id=? AND case_id=?"; // NON-NLS
try {
preparedStatement = conn.prepareStatement(sql);
- preparedStatement.setString(1, dataSourceDeviceId);
+ preparedStatement.setLong(1, dataSourceObjectId);
preparedStatement.setInt(2, correlationCase.getID());
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
@@ -742,7 +763,7 @@ abstract class AbstractSqlEamDb implements EamDb {
eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
}
if (eamDataSourceResult != null) {
- dataSourceCacheByDeviceId.put(getDataSourceByDeviceIdCacheKey(correlationCase.getID(), eamDataSourceResult.getDeviceID()), eamDataSourceResult);
+ dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(correlationCase.getID(), eamDataSourceResult.getDataSourceObjectID()), eamDataSourceResult);
}
} catch (SQLException ex) {
throw new EamDbException("Error getting data source.", ex); // NON-NLS
@@ -808,27 +829,26 @@ abstract class AbstractSqlEamDb implements EamDb {
String sql
= "INSERT INTO "
+ tableName
- + "(case_id, data_source_id, value, file_path, known_status, comment) "
- + "VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), "
- + "(SELECT id FROM data_sources WHERE device_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?) "
+ + "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
+ + "VALUES (?, ?, ?, ?, ?, ?, ?) "
+ getConflictClause();
try {
preparedStatement = conn.prepareStatement(sql);
if (!eamArtifact.getCorrelationValue().isEmpty()) {
+ preparedStatement.setInt(1, eamArtifact.getCorrelationCase().getID());
+ preparedStatement.setInt(2, eamArtifact.getCorrelationDataSource().getID());
+ preparedStatement.setString(3, eamArtifact.getCorrelationValue());
+ preparedStatement.setString(4, eamArtifact.getFilePath().toLowerCase());
+ preparedStatement.setByte(5, eamArtifact.getKnownStatus().getFileKnownValue());
- preparedStatement.setString(1, eamArtifact.getCorrelationCase().getCaseUUID());
- preparedStatement.setString(2, eamArtifact.getCorrelationDataSource().getDeviceID());
- preparedStatement.setInt(3, eamArtifact.getCorrelationDataSource().getCaseID());
- preparedStatement.setString(4, eamArtifact.getCorrelationValue());
- preparedStatement.setString(5, eamArtifact.getFilePath().toLowerCase());
- preparedStatement.setByte(6, eamArtifact.getKnownStatus().getFileKnownValue());
if ("".equals(eamArtifact.getComment())) {
- preparedStatement.setNull(7, Types.INTEGER);
+ preparedStatement.setNull(6, Types.INTEGER);
} else {
- preparedStatement.setString(7, eamArtifact.getComment());
+ preparedStatement.setString(6, eamArtifact.getComment());
}
+ preparedStatement.setLong(7, eamArtifact.getFileObjectId());
preparedStatement.executeUpdate();
}
@@ -900,7 +920,9 @@ abstract class AbstractSqlEamDb implements EamDb {
+ ".id,"
+ tableName
+ ".value,"
- + " cases.case_name, cases.case_uid, data_sources.id AS data_source_id, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id FROM "
+ + tableName
+ + ".file_obj_id,"
+ + " cases.case_name, cases.case_uid, data_sources.id AS data_source_id, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id, data_sources.datasource_obj_id FROM "
+ tableName
+ " LEFT JOIN cases ON "
+ tableName
@@ -963,7 +985,9 @@ abstract class AbstractSqlEamDb implements EamDb {
+ ".id, "
+ tableName
+ ".value,"
- + " cases.case_name, cases.case_uid, data_sources.id AS data_source_id, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id FROM "
+ + tableName
+ + ".file_obj_id,"
+ + " cases.case_name, cases.case_uid, data_sources.id AS data_source_id, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id, data_sources.datasource_obj_id FROM "
+ tableName
+ " LEFT JOIN cases ON "
+ tableName
@@ -1133,7 +1157,7 @@ abstract class AbstractSqlEamDb implements EamDb {
* dataSource
*/
@Override
- public Long getCountArtifactInstancesByCaseDataSource(String caseUUID, String dataSourceID) throws EamDbException {
+ public Long getCountArtifactInstancesByCaseDataSource(CorrelationDataSource correlationDataSource) throws EamDbException {
Connection conn = connect();
Long instanceCount = 0L;
@@ -1141,26 +1165,19 @@ abstract class AbstractSqlEamDb implements EamDb {
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
- // Figure out sql variables or subqueries
+ //Create query to get count of all instances in the database for the specified case specific data source
String sql = "SELECT 0 ";
for (CorrelationAttributeInstance.Type type : artifactTypes) {
String table_name = EamDbUtil.correlationTypeToInstanceTableName(type);
-
sql
+= "+ (SELECT count(*) FROM "
+ table_name
- + " WHERE data_source_id=(SELECT data_sources.id FROM cases INNER JOIN data_sources ON cases.id = data_sources.case_id WHERE case_uid=? and device_id=?))";
+ + " WHERE data_source_id=" + correlationDataSource.getID() + ")";
}
-
try {
preparedStatement = conn.prepareStatement(sql);
- for (int i = 0; i < artifactTypes.size(); ++i) {
- preparedStatement.setString(2 * i + 1, caseUUID);
- preparedStatement.setString(2 * i + 2, dataSourceID);
- }
-
resultSet = preparedStatement.executeQuery();
resultSet.next();
instanceCount = resultSet.getLong(1);
@@ -1190,7 +1207,7 @@ abstract class AbstractSqlEamDb implements EamDb {
}
synchronized (bulkArtifacts) {
- bulkArtifacts.get(eamArtifact.getCorrelationType().getDbTableName()).add(eamArtifact);
+ bulkArtifacts.get(EamDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())).add(eamArtifact);
bulkArtifactsCount++;
if (bulkArtifactsCount >= bulkArtifactsThreshold) {
@@ -1223,20 +1240,19 @@ abstract class AbstractSqlEamDb implements EamDb {
return;
}
- for (CorrelationAttributeInstance.Type type : artifactTypes) {
+ for (String tableName : bulkArtifacts.keySet()) {
- String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
String sql
= "INSERT INTO "
+ tableName
- + " (case_id, data_source_id, value, file_path, known_status, comment) "
+ + " (case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
+ "VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), "
- + "(SELECT id FROM data_sources WHERE device_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?) "
+ + "(SELECT id FROM data_sources WHERE datasource_obj_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?, ?) "
+ getConflictClause();
bulkPs = conn.prepareStatement(sql);
- Collection eamArtifacts = bulkArtifacts.get(type.getDbTableName());
+ Collection eamArtifacts = bulkArtifacts.get(tableName);
for (CorrelationAttributeInstance eamArtifact : eamArtifacts) {
if (!eamArtifact.getCorrelationValue().isEmpty()) {
@@ -1265,7 +1281,7 @@ abstract class AbstractSqlEamDb implements EamDb {
if (eamArtifact.getCorrelationValue().length() < MAX_VALUE_LENGTH) {
bulkPs.setString(1, eamArtifact.getCorrelationCase().getCaseUUID());
- bulkPs.setString(2, eamArtifact.getCorrelationDataSource().getDeviceID());
+ bulkPs.setLong(2, eamArtifact.getCorrelationDataSource().getDataSourceObjectID());
bulkPs.setInt(3, eamArtifact.getCorrelationDataSource().getCaseID());
bulkPs.setString(4, eamArtifact.getCorrelationValue());
bulkPs.setString(5, eamArtifact.getFilePath());
@@ -1275,6 +1291,7 @@ abstract class AbstractSqlEamDb implements EamDb {
} else {
bulkPs.setString(7, eamArtifact.getComment());
}
+ bulkPs.setLong(8, eamArtifact.getFileObjectId());
bulkPs.addBatch();
} else {
logger.log(Level.WARNING, ("Artifact value too long for central repository."
@@ -1291,7 +1308,7 @@ abstract class AbstractSqlEamDb implements EamDb {
}
bulkPs.executeBatch();
- bulkArtifacts.get(type.getDbTableName()).clear();
+ bulkArtifacts.get(tableName).clear();
}
TimingMetric timingMetric = HealthMonitor.getTimingMetric("Correlation Engine: Bulk insert");
@@ -1409,25 +1426,23 @@ abstract class AbstractSqlEamDb implements EamDb {
if (eamArtifact.getCorrelationDataSource() == null) {
throw new EamDbException("Correlation data source is null");
}
-
Connection conn = connect();
PreparedStatement preparedQuery = null;
String tableName = EamDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
-
String sqlUpdate
= "UPDATE "
+ tableName
+ " SET comment=? "
- + "WHERE case_id=(SELECT id FROM cases WHERE case_uid=?) "
- + "AND data_source_id=(SELECT id FROM data_sources WHERE device_id=?) "
+ + "WHERE case_id=? "
+ + "AND data_source_id=? "
+ "AND value=? "
+ "AND file_path=?";
try {
preparedQuery = conn.prepareStatement(sqlUpdate);
preparedQuery.setString(1, eamArtifact.getComment());
- preparedQuery.setString(2, eamArtifact.getCorrelationCase().getCaseUUID());
- preparedQuery.setString(3, eamArtifact.getCorrelationDataSource().getDeviceID());
+ preparedQuery.setInt(2, eamArtifact.getCorrelationCase().getID());
+ preparedQuery.setInt(3, eamArtifact.getCorrelationDataSource().getID());
preparedQuery.setString(4, eamArtifact.getCorrelationValue());
preparedQuery.setString(5, eamArtifact.getFilePath().toLowerCase());
preparedQuery.executeUpdate();
@@ -1439,6 +1454,68 @@ abstract class AbstractSqlEamDb implements EamDb {
}
}
+ /**
+ * Find a correlation attribute in the Central Repository database given the
+ * instance type, case, data source, object id.
+ *
+ * @param type The type of instance.
+ * @param correlationCase The case tied to the instance.
+ * @param correlationDataSource The data source tied to the instance.
+ * @param objectID The object id of the file tied to the
+ * instance.
+ *
+ * @return The correlation attribute if it exists; otherwise null.
+ *
+ * @throws EamDbException
+ */
+ @Override
+ public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
+ CorrelationDataSource correlationDataSource, long objectID) throws EamDbException, CorrelationAttributeNormalizationException {
+
+ if (correlationCase == null) {
+ throw new EamDbException("Correlation case is null");
+ }
+
+ Connection conn = connect();
+
+ PreparedStatement preparedStatement = null;
+ ResultSet resultSet = null;
+ CorrelationAttributeInstance correlationAttributeInstance = null;
+
+ try {
+
+ String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
+ String sql
+ = "SELECT id, value, file_path, known_status, comment FROM "
+ + tableName
+ + " WHERE case_id=?"
+ + " AND file_obj_id=?";
+
+ preparedStatement = conn.prepareStatement(sql);
+ preparedStatement.setInt(1, correlationCase.getID());
+ preparedStatement.setInt(2, (int) objectID);
+ resultSet = preparedStatement.executeQuery();
+ if (resultSet.next()) {
+ int instanceId = resultSet.getInt(1);
+ String value = resultSet.getString(2);
+ String filePath = resultSet.getString(3);
+ int knownStatus = resultSet.getInt(4);
+ String comment = resultSet.getString(5);
+
+ correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
+ instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), objectID);
+ }
+ } catch (SQLException ex) {
+ throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
+ } finally {
+ EamDbUtil.closeStatement(preparedStatement);
+ EamDbUtil.closeResultSet(resultSet);
+ EamDbUtil.closeConnection(conn);
+ }
+
+ return correlationAttributeInstance;
+ }
+
/**
* Find a correlation attribute in the Central Repository database given the
* instance type, case, data source, value, and file path.
@@ -1495,9 +1572,9 @@ abstract class AbstractSqlEamDb implements EamDb {
int instanceId = resultSet.getInt(1);
int knownStatus = resultSet.getInt(2);
String comment = resultSet.getString(3);
-
+ //null objectId used because we only fall back to using this method when objectID was not available
correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
- instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus));
+ instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), null);
}
} catch (SQLException ex) {
throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
@@ -1547,8 +1624,8 @@ abstract class AbstractSqlEamDb implements EamDb {
String sqlQuery
= "SELECT id FROM "
+ tableName
- + " WHERE case_id=(SELECT id FROM cases WHERE case_uid=?) "
- + "AND data_source_id=(SELECT id FROM data_sources WHERE device_id=?) "
+ + " WHERE case_id=? "
+ + "AND data_source_id=? "
+ "AND value=? "
+ "AND file_path=?";
@@ -1560,8 +1637,8 @@ abstract class AbstractSqlEamDb implements EamDb {
try {
preparedQuery = conn.prepareStatement(sqlQuery);
- preparedQuery.setString(1, eamArtifact.getCorrelationCase().getCaseUUID());
- preparedQuery.setString(2, eamArtifact.getCorrelationDataSource().getDeviceID());
+ preparedQuery.setInt(1, eamArtifact.getCorrelationCase().getID());
+ preparedQuery.setInt(2, eamArtifact.getCorrelationDataSource().getID());
preparedQuery.setString(3, eamArtifact.getCorrelationValue());
preparedQuery.setString(4, eamArtifact.getFilePath());
resultSet = preparedQuery.executeQuery();
@@ -1591,8 +1668,7 @@ abstract class AbstractSqlEamDb implements EamDb {
if (null == correlationCaseWithId) {
correlationCaseWithId = newCase(eamArtifact.getCorrelationCase());
}
-
- if (null == getDataSource(correlationCaseWithId, eamArtifact.getCorrelationDataSource().getDeviceID())) {
+ if (null == getDataSource(correlationCaseWithId, eamArtifact.getCorrelationDataSource().getDataSourceObjectID())) {
newDataSource(eamArtifact.getCorrelationDataSource());
}
eamArtifact.setKnownStatus(knownStatus);
@@ -1637,7 +1713,9 @@ abstract class AbstractSqlEamDb implements EamDb {
+ ".id, "
+ tableName
+ ".value, "
- + "cases.case_name, cases.case_uid, data_sources.id AS data_source_id, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id FROM "
+ + tableName
+ + ".file_obj_id,"
+ + "cases.case_name, cases.case_uid, data_sources.id AS data_source_id, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id, data_sources.datasource_obj_id FROM "
+ tableName
+ " LEFT JOIN cases ON "
+ tableName
@@ -1694,7 +1772,7 @@ abstract class AbstractSqlEamDb implements EamDb {
String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
String sql
- = "SELECT cases.case_name, cases.case_uid, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id, id, value FROM "
+ = "SELECT cases.case_name, cases.case_uid, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id, id, value, file_obj_id, data_sources.datasource_obj_id FROM "
+ tableName
+ " LEFT JOIN cases ON "
+ tableName
@@ -2976,7 +3054,8 @@ abstract class AbstractSqlEamDb implements EamDb {
resultSet.getInt("case_id"),
resultSet.getInt("id"),
resultSet.getString("device_id"),
- resultSet.getString("name")
+ resultSet.getString("name"),
+ resultSet.getLong("datasource_obj_id")
);
return eamDataSource;
@@ -3017,11 +3096,11 @@ abstract class AbstractSqlEamDb implements EamDb {
resultSet.getString("value"),
resultSet.getInt("id"),
new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), resultSet.getString("case_name")),
- new CorrelationDataSource(resultSet.getInt("case_id"), resultSet.getInt("data_source_id"), resultSet.getString("device_id"), resultSet.getString("name")),
+ new CorrelationDataSource(resultSet.getInt("case_id"), resultSet.getInt("data_source_id"), resultSet.getString("device_id"), resultSet.getString("name"), resultSet.getLong("datasource_obj_id")),
resultSet.getString("file_path"),
resultSet.getString("comment"),
- TskData.FileKnown.valueOf(resultSet.getByte("known_status"))
- );
+ TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
+ resultSet.getLong("file_obj_id"));
}
private EamOrganization getEamOrganizationFromResultSet(ResultSet resultSet) throws SQLException {
@@ -3069,6 +3148,18 @@ abstract class AbstractSqlEamDb implements EamDb {
);
}
+ /**
+ * Determine if a specific column already exists in a specific table
+ *
+ * @param tableName the table to check for the specified column
+ * @param columnName the name of the column to check for
+ *
+ * @return true if the column exists, false if the column does not exist
+ *
+ * @throws EamDbException
+ */
+ abstract boolean doesColumnExist(Connection conn, String tableName, String columnName) throws SQLException;
+
/**
* Upgrade the schema of the database (if needed)
*
@@ -3132,53 +3223,125 @@ abstract class AbstractSqlEamDb implements EamDb {
}
//Update to 1.2
if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) {
- //update central repository to be able to store new correlation attributes
EamDbPlatformEnum selectedPlatform = EamDbPlatformEnum.getSelectedPlatform();
+ final String addIntegerColumnTemplate = "ALTER TABLE %s ADD COLUMN %s INTEGER;"; //NON-NLS
final String addSsidTableTemplate;
final String addCaseIdIndexTemplate;
final String addDataSourceIdIndexTemplate;
final String addValueIndexTemplate;
final String addKnownStatusIndexTemplate;
+ final String addObjectIdIndexTemplate;
+
final String addAttributeSql;
//get the data base specific code for creating a new _instance table
switch (selectedPlatform) {
case POSTGRESQL:
- addAttributeSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause();
+ addAttributeSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause(); //NON-NLS
+
addSsidTableTemplate = PostgresEamDbSettings.getCreateArtifactInstancesTableTemplate();
addCaseIdIndexTemplate = PostgresEamDbSettings.getAddCaseIdIndexTemplate();
addDataSourceIdIndexTemplate = PostgresEamDbSettings.getAddDataSourceIdIndexTemplate();
addValueIndexTemplate = PostgresEamDbSettings.getAddValueIndexTemplate();
addKnownStatusIndexTemplate = PostgresEamDbSettings.getAddKnownStatusIndexTemplate();
+ addObjectIdIndexTemplate = PostgresEamDbSettings.getAddObjectIdIndexTemplate();
break;
case SQLITE:
- addAttributeSql = "INSERT OR IGNORE INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?)";
+ addAttributeSql = "INSERT OR IGNORE INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?)"; //NON-NLS
+
addSsidTableTemplate = SqliteEamDbSettings.getCreateArtifactInstancesTableTemplate();
addCaseIdIndexTemplate = SqliteEamDbSettings.getAddCaseIdIndexTemplate();
addDataSourceIdIndexTemplate = SqliteEamDbSettings.getAddDataSourceIdIndexTemplate();
addValueIndexTemplate = SqliteEamDbSettings.getAddValueIndexTemplate();
addKnownStatusIndexTemplate = SqliteEamDbSettings.getAddKnownStatusIndexTemplate();
+ addObjectIdIndexTemplate = SqliteEamDbSettings.getAddObjectIdIndexTemplate();
break;
default:
throw new EamDbException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.");
}
- final String wirelessNetworsDbTableName = "wireless_networks";
- final String wirelessNetworksTableInstanceName = wirelessNetworsDbTableName + "_instances";
+ final String dataSourcesTableName = "data_sources";
+ final String dataSourceObjectIdColumnName = "datasource_obj_id";
+ if (!doesColumnExist(conn, dataSourcesTableName, dataSourceObjectIdColumnName)) {
+ statement.execute(String.format(addIntegerColumnTemplate, dataSourcesTableName, dataSourceObjectIdColumnName)); //NON-NLS
+ }
+ final String dataSourceObjectIdIndexTemplate = "CREATE INDEX IF NOT EXISTS datasource_object_id ON data_sources (%s)";
+ statement.execute(String.format(dataSourceObjectIdIndexTemplate, dataSourceObjectIdColumnName));
+ List instaceTablesToAdd = new ArrayList<>();
+ //update central repository to be able to store new correlation attributes
+ final String wirelessNetworksDbTableName = "wireless_networks";
+ instaceTablesToAdd.add(wirelessNetworksDbTableName + "_instances");
+ final String macAddressDbTableName = "mac_address";
+ instaceTablesToAdd.add(macAddressDbTableName + "_instances");
+ final String imeiNumberDbTableName = "imei_number";
+ instaceTablesToAdd.add(imeiNumberDbTableName + "_instances");
+ final String iccidNumberDbTableName = "iccid_number";
+ instaceTablesToAdd.add(iccidNumberDbTableName + "_instances");
+ final String imsiNumberDbTableName = "imsi_number";
+ instaceTablesToAdd.add(imsiNumberDbTableName + "_instances");
+
//add the wireless_networks attribute to the correlation_types table
preparedStatement = conn.prepareStatement(addAttributeSql);
preparedStatement.setInt(1, CorrelationAttributeInstance.SSID_TYPE_ID);
preparedStatement.setString(2, Bundle.CorrelationType_SSID_displayName());
- preparedStatement.setString(3, wirelessNetworsDbTableName);
+ preparedStatement.setString(3, wirelessNetworksDbTableName);
preparedStatement.setInt(4, 1);
preparedStatement.setInt(5, 1);
preparedStatement.execute();
- //create a new wireless_networks_instances table and add indexes for its columns
- statement.execute(String.format(addSsidTableTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
- statement.execute(String.format(addCaseIdIndexTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
- statement.execute(String.format(addDataSourceIdIndexTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
- statement.execute(String.format(addValueIndexTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
- statement.execute(String.format(addKnownStatusIndexTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
+ //add the mac_address attribute to the correlation_types table
+ preparedStatement = conn.prepareStatement(addAttributeSql);
+ preparedStatement.setInt(1, CorrelationAttributeInstance.MAC_TYPE_ID);
+ preparedStatement.setString(2, Bundle.CorrelationType_MAC_displayName());
+ preparedStatement.setString(3, macAddressDbTableName);
+ preparedStatement.setInt(4, 1);
+ preparedStatement.setInt(5, 1);
+ preparedStatement.execute();
+ //add the imei_number attribute to the correlation_types table
+ preparedStatement = conn.prepareStatement(addAttributeSql);
+ preparedStatement.setInt(1, CorrelationAttributeInstance.IMEI_TYPE_ID);
+ preparedStatement.setString(2, Bundle.CorrelationType_IMEI_displayName());
+ preparedStatement.setString(3, imeiNumberDbTableName);
+ preparedStatement.setInt(4, 1);
+ preparedStatement.setInt(5, 1);
+ preparedStatement.execute();
+
+ //add the imsi_number attribute to the correlation_types table
+ preparedStatement = conn.prepareStatement(addAttributeSql);
+ preparedStatement.setInt(1, CorrelationAttributeInstance.IMSI_TYPE_ID);
+ preparedStatement.setString(2, Bundle.CorrelationType_IMSI_displayName());
+ preparedStatement.setString(3, imsiNumberDbTableName);
+ preparedStatement.setInt(4, 1);
+ preparedStatement.setInt(5, 1);
+ preparedStatement.execute();
+
+ //add the iccid_number attribute to the correlation_types table
+ preparedStatement = conn.prepareStatement(addAttributeSql);
+ preparedStatement.setInt(1, CorrelationAttributeInstance.ICCID_TYPE_ID);
+ preparedStatement.setString(2, Bundle.CorrelationType_ICCID_displayName());
+ preparedStatement.setString(3, iccidNumberDbTableName);
+ preparedStatement.setInt(4, 1);
+ preparedStatement.setInt(5, 1);
+ preparedStatement.execute();
+
+ //create a new _instances tables and add indexes for their columns
+ for (String tableName : instaceTablesToAdd) {
+ statement.execute(String.format(addSsidTableTemplate, tableName, tableName));
+ statement.execute(String.format(addCaseIdIndexTemplate, tableName, tableName));
+ statement.execute(String.format(addDataSourceIdIndexTemplate, tableName, tableName));
+ statement.execute(String.format(addValueIndexTemplate, tableName, tableName));
+ statement.execute(String.format(addKnownStatusIndexTemplate, tableName, tableName));
+ }
+
+ //add file_obj_id column to _instances table which do not already have it
+ String instance_type_dbname;
+ final String objectIdColumnName = "file_obj_id";
+ for (CorrelationAttributeInstance.Type type : CorrelationAttributeInstance.getDefaultCorrelationTypes()) {
+ instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
+ if (!doesColumnExist(conn, instance_type_dbname, objectIdColumnName)) {
+ statement.execute(String.format(addIntegerColumnTemplate, instance_type_dbname, objectIdColumnName)); //NON-NLS
+ }
+ statement.execute(String.format(addObjectIdIndexTemplate, instance_type_dbname, instance_type_dbname));
+ }
}
if (!updateSchemaVersion(conn)) {
throw new EamDbException("Error updating schema version");
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java
index 20845ff447..f5885f9ce4 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java
@@ -48,46 +48,18 @@ public class CorrelationAttributeInstance implements Serializable {
private String filePath;
private String comment;
private TskData.FileKnown knownStatus;
+ private Long objectId;
public CorrelationAttributeInstance(
- String correlationValue,
CorrelationAttributeInstance.Type correlationType,
- CorrelationCase eamCase,
- CorrelationDataSource eamDataSource,
- String filePath
- ) throws EamDbException, CorrelationAttributeNormalizationException {
- this(correlationType, correlationValue, -1, eamCase, eamDataSource, filePath, null, TskData.FileKnown.UNKNOWN);
- }
-
- public CorrelationAttributeInstance(
String correlationValue,
- CorrelationAttributeInstance.Type correlationType,
CorrelationCase eamCase,
CorrelationDataSource eamDataSource,
String filePath,
String comment,
- TskData.FileKnown knownStatus
- ) throws EamDbException, CorrelationAttributeNormalizationException {
- this(correlationType, correlationValue, -1, eamCase, eamDataSource, filePath, comment, knownStatus);
- }
-
- public CorrelationAttributeInstance(
- Type correlationType,
- String correlationValue,
- CorrelationCase correlationCase,
- CorrelationDataSource fromTSKDataSource,
- String string) throws EamDbException, CorrelationAttributeNormalizationException {
- this(correlationType, correlationValue, -1, correlationCase, fromTSKDataSource, string, "", TskData.FileKnown.UNKNOWN);
- }
-
- /**
- * NOTE: Only used for when EamDB is NOT enabled.
- *
- * @param aType CorrelationAttributeInstance.Type
- * @param value correlation value
- */
- public CorrelationAttributeInstance(Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
- this(aType, value, -1, null, null, "", "", TskData.FileKnown.UNKNOWN);
+ TskData.FileKnown knownStatus,
+ long fileObjectId) throws EamDbException, CorrelationAttributeNormalizationException {
+ this(correlationType, correlationValue, -1, eamCase, eamDataSource, filePath, comment, knownStatus, fileObjectId);
}
CorrelationAttributeInstance(
@@ -98,7 +70,8 @@ public class CorrelationAttributeInstance implements Serializable {
CorrelationDataSource eamDataSource,
String filePath,
String comment,
- TskData.FileKnown knownStatus
+ TskData.FileKnown knownStatus,
+ Long fileObjectId
) throws EamDbException, CorrelationAttributeNormalizationException {
if (filePath == null) {
throw new EamDbException("file path is null");
@@ -113,6 +86,7 @@ public class CorrelationAttributeInstance implements Serializable {
this.filePath = filePath.toLowerCase();
this.comment = comment;
this.knownStatus = knownStatus;
+ this.objectId = fileObjectId;
}
public Boolean equals(CorrelationAttributeInstance otherInstance) {
@@ -145,14 +119,6 @@ public class CorrelationAttributeInstance implements Serializable {
return correlationValue;
}
- /**
- * @param correlationValue the correlationValue to set
- */
- public void setCorrelationValue(String correlationValue) {
- // Lower-case all values to normalize and improve correlation hits, going forward make sure this makes sense for all correlation types
- this.correlationValue = correlationValue.toLowerCase();
- }
-
/**
* @return the correlation Type
*/
@@ -160,13 +126,6 @@ public class CorrelationAttributeInstance implements Serializable {
return correlationType;
}
- /**
- * @param correlationType the correlation Type to set
- */
- public void setCorrelationType(Type correlationType) {
- this.correlationType = correlationType;
- }
-
/**
* Is this a database instance?
*
@@ -240,6 +199,16 @@ public class CorrelationAttributeInstance implements Serializable {
this.knownStatus = knownStatus;
}
+ /**
+ * Get the objectId of the file associated with the correlation attribute or
+ * NULL if the objectId is not available.
+ *
+ * @return the objectId of the file
+ */
+ public Long getFileObjectId() {
+ return objectId;
+ }
+
// Type ID's for Default Correlation Types
public static final int FILES_TYPE_ID = 0;
public static final int DOMAIN_TYPE_ID = 1;
@@ -247,6 +216,10 @@ public class CorrelationAttributeInstance implements Serializable {
public static final int PHONE_TYPE_ID = 3;
public static final int USBID_TYPE_ID = 4;
public static final int SSID_TYPE_ID = 5;
+ public static final int MAC_TYPE_ID = 6;
+ public static final int IMEI_TYPE_ID = 7;
+ public static final int IMSI_TYPE_ID = 8;
+ public static final int ICCID_TYPE_ID = 9;
/**
* Load the default correlation types
@@ -259,7 +232,11 @@ public class CorrelationAttributeInstance implements Serializable {
"CorrelationType.EMAIL.displayName=Email Addresses",
"CorrelationType.PHONE.displayName=Phone Numbers",
"CorrelationType.USBID.displayName=USB Devices",
- "CorrelationType.SSID.displayName=Wireless Networks"})
+ "CorrelationType.SSID.displayName=Wireless Networks",
+ "CorrelationType.MAC.displayName=MAC Addresses",
+ "CorrelationType.IMEI.displayName=IMEI Number",
+ "CorrelationType.IMSI.displayName=IMSI Number",
+ "CorrelationType.ICCID.displayName=ICCID Number"})
public static List getDefaultCorrelationTypes() throws EamDbException {
List DEFAULT_CORRELATION_TYPES = new ArrayList<>();
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(FILES_TYPE_ID, Bundle.CorrelationType_FILES_displayName(), "file", true, true)); // NON-NLS
@@ -268,6 +245,10 @@ public class CorrelationAttributeInstance implements Serializable {
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(PHONE_TYPE_ID, Bundle.CorrelationType_PHONE_displayName(), "phone_number", true, true)); // NON-NLS
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(USBID_TYPE_ID, Bundle.CorrelationType_USBID_displayName(), "usb_devices", true, true)); // NON-NLS
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(SSID_TYPE_ID, Bundle.CorrelationType_SSID_displayName(), "wireless_networks", true, true)); // NON-NLS
+ DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(MAC_TYPE_ID, Bundle.CorrelationType_MAC_displayName(), "mac_address", true, true)); //NON-NLS
+ DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(IMEI_TYPE_ID, Bundle.CorrelationType_IMEI_displayName(), "imei_number", true, true)); //NON-NLS
+ DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(IMSI_TYPE_ID, Bundle.CorrelationType_IMSI_displayName(), "imsi_number", true, true)); //NON-NLS
+ DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(ICCID_TYPE_ID, Bundle.CorrelationType_ICCID_displayName(), "iccid_number", true, true)); //NON-NLS
return DEFAULT_CORRELATION_TYPES;
}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java
index 4ce04769c8..11a8e2249b 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java
@@ -65,6 +65,14 @@ final public class CorrelationAttributeNormalizer {
return normalizeUsbId(data);
case CorrelationAttributeInstance.SSID_TYPE_ID:
return data;
+ case CorrelationAttributeInstance.MAC_TYPE_ID:
+ return data;
+ case CorrelationAttributeInstance.IMEI_TYPE_ID:
+ return data;
+ case CorrelationAttributeInstance.IMSI_TYPE_ID:
+ return data;
+ case CorrelationAttributeInstance.ICCID_TYPE_ID:
+ return data;
default:
final String errorMessage = String.format(
"Validator function not found for attribute type: %s",
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationDataSource.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationDataSource.java
index 84dce834a1..b1d48d07b2 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationDataSource.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationDataSource.java
@@ -36,38 +36,49 @@ public class CorrelationDataSource implements Serializable {
private final int caseID; //the value in the id column of the case table in the central repo
private final int dataSourceID; //< Id in the central repo
+ private final Long dataSourceObjectID; //< Id for data source in the caseDB
private final String deviceID; //< Unique to its associated case (not necessarily globally unique)
private final String name;
/**
- * @param correlationCase CorrelationCase object data source is associated with. Must have been created by EamDB and have a valid ID.
- * @param deviceId User specified case-specific ID
- * @param name Display name of data source
+ * Create a CorrelationDataSource object, the object will not have the data
+ * source id for the row in the central repository.
+ *
+ * @param correlationCase CorrelationCase object data source is
+ * associated with. Must have been created by
+ * EamDB and have a valid ID.
+ * @param deviceId User specified case-specific ID
+ * @param name Display name of data source
+ * @param dataSourceObjectId The object ID for the datasource
*/
- public CorrelationDataSource(CorrelationCase correlationCase, String deviceId, String name) {
- this(correlationCase.getID(), -1, deviceId, name);
- }
-
+ public CorrelationDataSource(CorrelationCase correlationCase, String deviceId, String name, long dataSourceObjectId) {
+ this(correlationCase.getID(), -1, deviceId, name, dataSourceObjectId);
+ }
+
/**
- *
- * @param caseId Row ID for Case in DB
- * @param dataSourceId Row ID for this data source in DB (or -1)
- * @param deviceId User specified ID for device (unique per case)
- * @param name User specified name
+ * Create a CorrelationDataSource object.
+ *
+ * @param caseId Row ID for Case in DB
+ * @param dataSourceId Row ID for this data source in DB (or -1)
+ * @param deviceId User specified ID for device (unique per case)
+ * @param name User specified name
+ * @param dataSourceObjectId The object ID for the datasource
*/
CorrelationDataSource(int caseId,
int dataSourceId,
String deviceId,
- String name) {
+ String name,
+ Long dataSourceObjectId) {
this.caseID = caseId;
this.dataSourceID = dataSourceId;
this.deviceID = deviceId;
this.name = name;
+ this.dataSourceObjectID = dataSourceObjectId;
}
/**
- * Create a CorrelationDataSource object from a TSK Content object.
- * This will add it to the central repository.
+ * Create a CorrelationDataSource object from a TSK Content object. This
+ * will add it to the central repository.
*
* @param correlationCase the current CorrelationCase used for ensuring
* uniqueness of DataSource
@@ -85,21 +96,24 @@ public class CorrelationDataSource implements Serializable {
} catch (NoCurrentCaseException ex) {
throw new EamDbException("Autopsy case is closed");
}
- String deviceId;
- try {
- deviceId = curCase.getSleuthkitCase().getDataSource(dataSource.getId()).getDeviceId();
- } catch (TskDataException | TskCoreException ex) {
- throw new EamDbException("Error getting data source info: " + ex.getMessage());
- }
-
+
CorrelationDataSource correlationDataSource = null;
- if (EamDbUtil.useCentralRepo()) {
- correlationDataSource = EamDb.getInstance().getDataSource(correlationCase, deviceId);
+ boolean useCR = EamDbUtil.useCentralRepo();
+ if (useCR) {
+ correlationDataSource = EamDb.getInstance().getDataSource(correlationCase, dataSource.getId());
}
+
if (correlationDataSource == null) {
- correlationDataSource = new CorrelationDataSource(correlationCase, deviceId, dataSource.getName());
- if (EamDbUtil.useCentralRepo()) {
- EamDb.getInstance().newDataSource(correlationDataSource);
+ String deviceId;
+ try {
+ deviceId = curCase.getSleuthkitCase().getDataSource(dataSource.getId()).getDeviceId();
+ } catch (TskDataException | TskCoreException ex) {
+ throw new EamDbException("Error getting data source info: " + ex.getMessage());
+ }
+ correlationDataSource = new CorrelationDataSource(correlationCase, deviceId, dataSource.getName(), dataSource.getId());
+ if (useCR) {
+ //add the correlation data source to the central repository and fill in the Central repository data source id in the object
+ correlationDataSource = EamDb.getInstance().newDataSource(correlationDataSource);
}
}
return correlationDataSource;
@@ -144,6 +158,15 @@ public class CorrelationDataSource implements Serializable {
return caseID;
}
+ /**
+ * Get the object id for the data source in the case db
+ *
+ * @return dataSourceObjectID or NULL if not available
+ */
+ public Long getDataSourceObjectID() {
+ return dataSourceObjectID;
+ }
+
/**
* @return the name
*/
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/DataSourceUpdateService.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/DataSourceUpdateService.java
new file mode 100644
index 0000000000..16cc5b58c7
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/DataSourceUpdateService.java
@@ -0,0 +1,68 @@
+/*
+ * Central Repository
+ *
+ * Copyright 2018 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.datamodel;
+
+import org.openide.util.NbBundle;
+import org.openide.util.lookup.ServiceProvider;
+import org.sleuthkit.autopsy.appservices.AutopsyService;
+import org.sleuthkit.datamodel.Content;
+import org.sleuthkit.datamodel.DataSource;
+import org.sleuthkit.datamodel.TskCoreException;
+
+/**
+ * Class which updates the data sources in the central repository to include the
+ * object id which ties them to the current case.
+ *
+ */
+@ServiceProvider(service = AutopsyService.class)
+public class DataSourceUpdateService implements AutopsyService {
+
+ @Override
+ @NbBundle.Messages({"DataSourceUpdateService.serviceName.text=Update Central Repository Data Sources"})
+ public String getServiceName() {
+ return Bundle.DataSourceUpdateService_serviceName_text();
+ }
+
+ @Override
+ public void openCaseResources(CaseContext context) throws AutopsyServiceException {
+ if (EamDb.isEnabled()) {
+ try {
+ EamDb centralRepository = EamDb.getInstance();
+ CorrelationCase correlationCase = centralRepository.getCase(context.getCase());
+ //if the case isn't in the central repository yet there won't be data sources in it to update
+ if (correlationCase != null) {
+ for (CorrelationDataSource correlationDataSource : centralRepository.getDataSources()) {
+ //ResultSet.getLong has a value of 0 when the value is null
+ if (correlationDataSource.getCaseID() == correlationCase.getID() && correlationDataSource.getDataSourceObjectID() == 0) {
+ for (Content dataSource : context.getCase().getDataSources()) {
+ if (((DataSource) dataSource).getDeviceId().equals(correlationDataSource.getDeviceID())) {
+ centralRepository.addDataSourceObjectId(correlationDataSource.getID(), dataSource.getId());
+ break;
+ }
+ }
+ }
+ }
+ }
+ } catch (EamDbException | TskCoreException ex) {
+ throw new AutopsyServiceException("Unabe to update datasources in central repository", ex);
+ }
+ }
+ }
+
+}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java
index aca0471345..6b9275365a 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java
@@ -28,6 +28,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
+import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.HashUtility;
import org.sleuthkit.datamodel.TskCoreException;
@@ -54,119 +55,108 @@ public class EamArtifactUtil {
* EamArtifact with a single EamArtifactInstance within. If not, return
* null.
*
- * @param bbArtifact BlackboardArtifact to examine
+ * @param artifact BlackboardArtifact to examine
* @param checkEnabled If true, only create a CorrelationAttribute if it is
* enabled
*
* @return List of EamArtifacts
*/
- public static List makeInstancesFromBlackboardArtifact(BlackboardArtifact bbArtifact,
+ public static List makeInstancesFromBlackboardArtifact(BlackboardArtifact artifact,
boolean checkEnabled) {
-
List eamArtifacts = new ArrayList<>();
-
try {
- // Cycle through the types and see if there is a correlation attribute that works
- // for the given blackboard artifact
- //
- // @@@ This seems ineffecient. Instead of cycling based on correlation type, we should just
- // have switch based on artifact type
- for (CorrelationAttributeInstance.Type aType : EamDb.getInstance().getDefinedCorrelationTypes()) {
- if ((checkEnabled && aType.isEnabled()) || !checkEnabled) {
- // Now always adds the instance details associated with this occurance.
- CorrelationAttributeInstance correlationAttribute = EamArtifactUtil.makeInstanceFromBlackboardArtifact(aType, bbArtifact);
- if (correlationAttribute != null) {
- eamArtifacts.add(correlationAttribute);
+ BlackboardArtifact artifactForInstance = null;
+ if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifact.getArtifactTypeID()) {
+ // Get the associated artifactForInstance
+ BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
+ if (attribute != null) {
+ artifactForInstance = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
+ }
+ } else {
+ artifactForInstance = artifact;
+ }
+ if (artifactForInstance != null) {
+ switch (BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactForInstance.getArtifactTypeID())) {
+ case TSK_KEYWORD_HIT: {
+ BlackboardAttribute setNameAttr = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
+ if (setNameAttr != null
+ && EamArtifactUtil.getEmailAddressAttrString().equals(setNameAttr.getValueString())) {
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID);
+ }
+ break;
}
+ case TSK_WEB_BOOKMARK:
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID);
+ break;
+ case TSK_WEB_COOKIE:
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID);
+ break;
+ case TSK_WEB_DOWNLOAD:
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID);
+ break;
+ case TSK_WEB_HISTORY:
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID);
+ break;
+ case TSK_CONTACT:
+ //generates the same correlation attrs as tsk_message
+ case TSK_CALLLOG:
+ //generates the same correlation attrs as tsk_message
+ case TSK_MESSAGE: {
+ String value = null;
+ if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) {
+ value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString();
+ } else if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) {
+ value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString();
+ } else if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) {
+ value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString();
+ }
+ // Remove all non-numeric symbols to semi-normalize phone numbers, preserving leading "+" character
+ if (value != null) {
+ String newValue = value.replaceAll("\\D", "");
+ if (value.startsWith("+")) {
+ newValue = "+" + newValue;
+ }
+ value = newValue;
+ // Only add the correlation attribute if the resulting phone number large enough to be of use
+ // (these 3-5 digit numbers can be valid, but are not useful for correlation)
+ if (value.length() > 5) {
+ eamArtifacts.add(makeCorrelationAttributeInstanceUsingTypeValue(artifactForInstance, EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value));
+ }
+ }
+ break;
+ }
+ case TSK_DEVICE_ATTACHED:
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID);
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID);
+ break;
+ case TSK_WIFI_NETWORK:
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID);
+ break;
+ case TSK_WIFI_NETWORK_ADAPTER:
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID);
+ break;
+ case TSK_BLUETOOTH_PAIRING:
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID);
+ break;
+ case TSK_BLUETOOTH_ADAPTER:
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID);
+ break;
+ case TSK_DEVICE_INFO:
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID);
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID);
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID);
+ break;
+ case TSK_SIM_ATTACHED:
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID);
+ addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID);
+ break;
+ default:
+ break;
}
}
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error getting defined correlation types.", ex); // NON-NLS
return eamArtifacts;
- }
-
- return eamArtifacts;
- }
-
- /**
- * Create an EamArtifact of type correlationType if one can be generated
- * based on the data in the blackboard artifact.
- *
- * @param correlationType The Central Repository artifact type to create
- * @param bbArtifact The blackboard artifact to pull data from
- *
- * @return the new EamArtifact, or null if one was not created because
- * bbArtifact did not contain the needed data
- */
- private static CorrelationAttributeInstance makeInstanceFromBlackboardArtifact(CorrelationAttributeInstance.Type correlationType,
- BlackboardArtifact bbArtifact) throws EamDbException {
- String value = null;
- int artifactTypeID = bbArtifact.getArtifactTypeID();
-
- try {
- if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifactTypeID) {
- // Get the associated artifact
- BlackboardAttribute attribute = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
- if (attribute != null) {
- BlackboardArtifact associatedArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
- return EamArtifactUtil.makeInstanceFromBlackboardArtifact(correlationType, associatedArtifact);
- }
-
- } else if (correlationType.getId() == CorrelationAttributeInstance.EMAIL_TYPE_ID
- && BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() == artifactTypeID) {
-
- BlackboardAttribute setNameAttr = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
- if (setNameAttr != null
- && EamArtifactUtil.getEmailAddressAttrString().equals(setNameAttr.getValueString())) {
- value = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD)).getValueString();
- }
- } else if (correlationType.getId() == CorrelationAttributeInstance.DOMAIN_TYPE_ID
- && (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() == artifactTypeID
- || BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() == artifactTypeID
- || BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() == artifactTypeID
- || BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() == artifactTypeID)) {
-
- // Lower-case this to normalize domains
- BlackboardAttribute attribute = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN));
- if (attribute != null) {
- value = attribute.getValueString();
- }
- } else if (correlationType.getId() == CorrelationAttributeInstance.PHONE_TYPE_ID
- && (BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID() == artifactTypeID
- || BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() == artifactTypeID
- || BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() == artifactTypeID)) {
-
- if (null != bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) {
- value = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString();
- } else if (null != bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) {
- value = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString();
- } else if (null != bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) {
- value = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString();
- }
-
- // Remove all non-numeric symbols to semi-normalize phone numbers, preserving leading "+" character
- if (value != null) {
- String newValue = value.replaceAll("\\D", "");
- if (value.startsWith("+")) {
- newValue = "+" + newValue;
- }
-
- value = newValue;
-
- // If the resulting phone number is too small to be of use, return null
- // (these 3-5 digit numbers can be valid, but are not useful for correlation)
- if (value.length() <= 5) {
- return null;
- }
- }
- } else if (correlationType.getId() == CorrelationAttributeInstance.USBID_TYPE_ID
- && BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID() == artifactTypeID) {
-
- value = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID)).getValueString();
- } else if (correlationType.getId() == CorrelationAttributeInstance.SSID_TYPE_ID
- && BlackboardArtifact.ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID() == artifactTypeID) {
- value = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID)).getValueString();
- }
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS
return null;
@@ -174,11 +164,34 @@ public class EamArtifactUtil {
logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
return null;
}
+ return eamArtifacts;
+ }
- if ((null != value) && (value.isEmpty() == false)) {
- return makeCorrelationAttributeInstanceUsingTypeValue(bbArtifact, correlationType, value);
- } else {
- return null;
+ /**
+ * Add a CorrelationAttributeInstance of the specified type to the provided
+ list if the artifactForInstance has an Attribute of the given type with a non empty
+ value.
+ *
+ * @param eamArtifacts the list of CorrelationAttributeInstance objects
+ * which should be added to
+ * @param artifact the blackboard artifactForInstance which we are creating a
+ CorrelationAttributeInstance for
+ * @param bbAttributeType the type of BlackboardAttribute we expect to exist
+ * for a CorrelationAttributeInstance of this type
+ * generated from this Blackboard Artifact
+ * @param typeId the integer type id of the
+ * CorrelationAttributeInstance type
+ *
+ * @throws EamDbException
+ * @throws TskCoreException
+ */
+ private static void addCorrelationAttributeToList(List eamArtifacts, BlackboardArtifact artifact, ATTRIBUTE_TYPE bbAttributeType, int typeId) throws EamDbException, TskCoreException {
+ BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(bbAttributeType));
+ if (attribute != null) {
+ String value = attribute.getValueString();
+ if ((null != value) && (value.isEmpty() == false)) {
+ eamArtifacts.add(makeCorrelationAttributeInstanceUsingTypeValue(artifact, EamDb.getInstance().getCorrelationTypeById(typeId), value));
+ }
}
}
@@ -186,9 +199,9 @@ public class EamArtifactUtil {
* Uses the determined type and vallue, then looks up instance details to
* create proper CorrelationAttributeInstance.
*
- * @param bbArtifact the blackboard artifact
+ * @param bbArtifact the blackboard artifactForInstance
* @param correlationType the given type
- * @param value the artifact value
+ * @param value the artifactForInstance value
*
* @return CorrelationAttributeInstance from details
*/
@@ -207,14 +220,14 @@ public class EamArtifactUtil {
correlationCase = EamDb.getInstance().newCase(Case.getCurrentCaseThrows());
}
return new CorrelationAttributeInstance(
- value,
correlationType,
+ value,
correlationCase,
CorrelationDataSource.fromTSKDataSource(correlationCase, bbSourceFile.getDataSource()),
bbSourceFile.getParentPath() + bbSourceFile.getName(),
"",
- TskData.FileKnown.UNKNOWN
- );
+ TskData.FileKnown.UNKNOWN,
+ bbSourceFile.getId());
} catch (TskCoreException | EamDbException | CorrelationAttributeNormalizationException ex) {
logger.log(Level.SEVERE, "Error creating artifact instance.", ex); // NON-NLS
@@ -247,8 +260,6 @@ public class EamArtifactUtil {
CorrelationAttributeInstance.Type type;
CorrelationCase correlationCase;
CorrelationDataSource correlationDataSource;
- String value;
- String filePath;
try {
type = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID);
@@ -258,8 +269,6 @@ public class EamArtifactUtil {
return null;
}
correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, file.getDataSource());
- value = file.getMd5Hash();
- filePath = (file.getParentPath() + file.getName()).toLowerCase();
} catch (TskCoreException | EamDbException ex) {
logger.log(Level.SEVERE, "Error retrieving correlation attribute.", ex);
return null;
@@ -270,25 +279,38 @@ public class EamArtifactUtil {
CorrelationAttributeInstance correlationAttributeInstance;
try {
- correlationAttributeInstance = EamDb.getInstance().getCorrelationAttributeInstance(type, correlationCase, correlationDataSource, value, filePath);
+ correlationAttributeInstance = EamDb.getInstance().getCorrelationAttributeInstance(type, correlationCase, correlationDataSource, file.getId());
} catch (EamDbException | CorrelationAttributeNormalizationException ex) {
logger.log(Level.WARNING, String.format(
"Correlation attribute could not be retrieved for '%s' (id=%d): %s",
content.getName(), content.getId(), ex.getMessage()));
return null;
}
+ //if there was no correlation attribute found for the item using object_id then check for attributes added with schema 1,1 which lack object_id
+ if (correlationAttributeInstance == null) {
+ String value = file.getMd5Hash();
+ String filePath = (file.getParentPath() + file.getName()).toLowerCase();
+ try {
+ correlationAttributeInstance = EamDb.getInstance().getCorrelationAttributeInstance(type, correlationCase, correlationDataSource, value, filePath);
+ } catch (EamDbException | CorrelationAttributeNormalizationException ex) {
+ logger.log(Level.WARNING, String.format(
+ "Correlation attribute could not be retrieved for '%s' (id=%d): %s",
+ content.getName(), content.getId(), ex.getMessage()));
+ return null;
+ }
+ }
return correlationAttributeInstance;
}
/**
* Create an EamArtifact from the given Content. Will return null if an
- * artifact can not be created - this is not necessarily an error case, it
- * just means an artifact can't be made. If creation fails due to an error
- * (and not that the file is the wrong type or it has no hash), the error
- * will be logged before returning.
- *
- * Does not add the artifact to the database.
+ artifactForInstance can not be created - this is not necessarily an error case, it
+ just means an artifactForInstance can't be made. If creation fails due to an error
+ (and not that the file is the wrong type or it has no hash), the error
+ will be logged before returning.
+
+ Does not add the artifactForInstance to the database.
*
* @param content The content object
*
@@ -306,7 +328,7 @@ public class EamArtifactUtil {
return null;
}
- // We need a hash to make the artifact
+ // We need a hash to make the artifactForInstance
String md5 = af.getMd5Hash();
if (md5 == null || md5.isEmpty() || HashUtility.isNoDataMd5(md5)) {
return null;
@@ -324,7 +346,10 @@ public class EamArtifactUtil {
af.getMd5Hash(),
correlationCase,
CorrelationDataSource.fromTSKDataSource(correlationCase, af.getDataSource()),
- af.getParentPath() + af.getName());
+ af.getParentPath() + af.getName(),
+ "",
+ TskData.FileKnown.UNKNOWN,
+ af.getId());
} catch (TskCoreException | EamDbException | CorrelationAttributeNormalizationException ex) {
logger.log(Level.SEVERE, "Error making correlation attribute.", ex);
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java
index 418181d8ab..9f5dae9e27 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java
@@ -34,8 +34,7 @@ public interface EamDb {
public static final int SCHEMA_VERSION = 2;
public static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
= new CaseDbSchemaVersionNumber(1, 2);
-
-
+
/**
* Get the instance
*
@@ -111,6 +110,16 @@ public interface EamDb {
*/
public void newDbInfo(String name, String value) throws EamDbException;
+ /**
+ * Set the data source object id for a specific entry in the data_sources
+ * table
+ *
+ * @param rowId - the row id for the data_sources table entry
+ * @param dataSourceObjectId - the object id for the data source from the
+ * caseDb
+ */
+ void addDataSourceObjectId(int rowId, long dataSourceObjectId) throws EamDbException;
+
/**
* Get the value for the given name from the name/value db_info table.
*
@@ -183,43 +192,45 @@ public interface EamDb {
* @return The retrieved case
*/
CorrelationCase getCaseById(int caseId) throws EamDbException;
+
/**
* Retrieves cases that are in DB.
*
* @return List of cases
*/
List getCases() throws EamDbException;
-
+
/**
* Creates new Data Source in the database
*
* @param eamDataSource the data source to add
+ *
+ * @return - A CorrelationDataSource object with data source's central repository id
*/
- void newDataSource(CorrelationDataSource eamDataSource) throws EamDbException;
+ CorrelationDataSource newDataSource(CorrelationDataSource eamDataSource) throws EamDbException;
/**
* Retrieves Data Source details based on data source device ID
*
* @param correlationCase the current CorrelationCase used for ensuring
* uniqueness of DataSource
- * @param dataSourceDeviceId the data source device ID number
+ * @param caseDbDataSourceId the data source device ID number
*
* @return The data source
*/
- CorrelationDataSource getDataSource(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException;
+ CorrelationDataSource getDataSource(CorrelationCase correlationCase, Long caseDbDataSourceId) throws EamDbException;
-
/**
* Retrieves Data Source details based on data source ID
*
- * @param correlationCase the current CorrelationCase used for ensuring
- * uniqueness of DataSource
- * @param dataSourceId the data source ID number
+ * @param correlationCase the current CorrelationCase used for ensuring
+ * uniqueness of DataSource
+ * @param dataSourceId the data source ID number
*
* @return The data source
*/
CorrelationDataSource getDataSourceById(CorrelationCase correlationCase, int dataSourceId) throws EamDbException;
-
+
/**
* Retrieves data sources that are in DB
*
@@ -245,7 +256,7 @@ public interface EamDb {
* @return List of artifact instances for a given type/value
*/
List getArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException;
-
+
/**
* Retrieves eamArtifact instances from the database that are associated
* with the aType and filePath
@@ -301,21 +312,19 @@ public interface EamDb {
/**
* Retrieves number of eamArtifact instances in the database that are
- * associated with the caseDisplayName and dataSource of the given
- * eamArtifact instance.
+ * associated with the given data source.
*
- * @param caseUUID Case ID to search for
- * @param dataSourceID Data source ID to search for
+ * @param correlationDataSource Data source to search for
*
* @return Number of artifact instances having caseDisplayName and
* dataSource
*/
- Long getCountArtifactInstancesByCaseDataSource(String caseUUID, String dataSourceID) throws EamDbException;
+ Long getCountArtifactInstancesByCaseDataSource(CorrelationDataSource correlationDataSource) throws EamDbException;
/**
* Adds an eamArtifact to an internal list to be later added to DB. Artifact
- can have 1 or more Artifact Instances. Insert will be triggered by a
- threshold or a call to commitAttributeInstancesBulk().
+ * can have 1 or more Artifact Instances. Insert will be triggered by a
+ * threshold or a call to commitAttributeInstancesBulk().
*
* @param eamArtifact The artifact to add
*/
@@ -323,7 +332,7 @@ public interface EamDb {
/**
* Executes a bulk insert of the eamArtifacts added from the
- addAttributeInstanceBulk() method
+ * addAttributeInstanceBulk() method
*/
void commitAttributeInstancesBulk() throws EamDbException;
@@ -347,6 +356,9 @@ public interface EamDb {
* Find a correlation attribute in the Central Repository database given the
* instance type, case, data source, value, and file path.
*
+ * Method exists to support instances added using Central Repository version
+ * 1,1 and older
+ *
* @param type The type of instance.
* @param correlationCase The case tied to the instance.
* @param correlationDataSource The data source tied to the instance.
@@ -360,6 +372,23 @@ public interface EamDb {
CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
CorrelationDataSource correlationDataSource, String value, String filePath) throws EamDbException, CorrelationAttributeNormalizationException;
+ /**
+ * Find a correlation attribute in the Central Repository database given the
+ * instance type, case, data source, object id.
+ *
+ * @param type The type of instance.
+ * @param correlationCase The case tied to the instance.
+ * @param correlationDataSource The data source tied to the instance.
+ * @param objectID The object id of the file tied to the
+ * instance.
+ *
+ * @return The correlation attribute if it exists; otherwise null.
+ *
+ * @throws EamDbException
+ */
+ CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
+ CorrelationDataSource correlationDataSource, long objectID) throws EamDbException, CorrelationAttributeNormalizationException;
+
/**
* Sets an eamArtifact instance to the given known status. If eamArtifact
* exists, it is updated. If eamArtifact does not exist nothing happens
@@ -383,12 +412,15 @@ public interface EamDb {
/**
* Gets list of matching eamArtifact instances that have knownStatus =
* "Bad".
- *
+ *
* @param aType EamArtifact.Type to search for
+ *
* @return List with 0 or more matching eamArtifact instances.
+ *
* @throws EamDbException
*/
List getArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType) throws EamDbException;
+
/**
* Count matching eamArtifacts instances that have knownStatus = "Bad".
*
@@ -490,7 +522,7 @@ public interface EamDb {
*
* @param eamOrg The organization to add
*
- * @return The organization with the org ID set.
+ * @return The organization with the org ID set.
*
* @throws EamDbException
*/
@@ -700,18 +732,20 @@ public interface EamDb {
/**
* Process the Artifact instance in the EamDb
*
- * @param type EamArtifact.Type to search for
+ * @param type EamArtifact.Type to search for
* @param instanceTableCallback callback to process the instance
+ *
* @throws EamDbException
*/
void processInstanceTable(CorrelationAttributeInstance.Type type, InstanceTableCallback instanceTableCallback) throws EamDbException;
-
+
/**
* Process the Artifact instance in the EamDb
*
- * @param type EamArtifact.Type to search for
+ * @param type EamArtifact.Type to search for
* @param instanceTableCallback callback to process the instance
- * @param whereClause query string to execute
+ * @param whereClause query string to execute
+ *
* @throws EamDbException
*/
void processInstanceTableWhere(CorrelationAttributeInstance.Type type, String whereClause, InstanceTableCallback instanceTableCallback) throws EamDbException;
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java
index 97abd1dec9..769b49bfd3 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java
@@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.centralrepository.datamodel;
import java.sql.Connection;
+import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.TimeUnit;
@@ -29,8 +30,7 @@ import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
- * Central Repository database implementation using Postgres as a
- * backend
+ * Central Repository database implementation using Postgres as a backend
*/
final class PostgresEamDb extends AbstractSqlEamDb {
@@ -47,10 +47,11 @@ final class PostgresEamDb extends AbstractSqlEamDb {
/**
* Get the singleton instance of PostgresEamDb
- *
+ *
* @return the singleton instance of PostgresEamDb
- *
- * @throws EamDbException if one or more default correlation type(s) have an invalid db table name.
+ *
+ * @throws EamDbException if one or more default correlation type(s) have an
+ * invalid db table name.
*/
public synchronized static PostgresEamDb getInstance() throws EamDbException {
if (instance == null) {
@@ -61,9 +62,10 @@ final class PostgresEamDb extends AbstractSqlEamDb {
}
/**
- *
- * @throws EamDbException if the AbstractSqlEamDb class has one or more default
- * correlation type(s) having an invalid db table name.
+ *
+ * @throws EamDbException if the AbstractSqlEamDb class has one or more
+ * default correlation type(s) having an invalid db
+ * table name.
*/
private PostgresEamDb() throws EamDbException {
dbSettings = new PostgresEamDbSettings();
@@ -73,8 +75,8 @@ final class PostgresEamDb extends AbstractSqlEamDb {
@Override
public void shutdownConnections() throws EamDbException {
try {
- synchronized(this) {
- if(connectionPool != null){
+ synchronized (this) {
+ if (connectionPool != null) {
connectionPool.close();
connectionPool = null; // force it to be re-created on next connect()
}
@@ -148,7 +150,7 @@ final class PostgresEamDb extends AbstractSqlEamDb {
connectionURL.append(dbSettings.getPort());
connectionURL.append("/");
connectionURL.append(dbSettings.getDbName());
-
+
connectionPool.setUrl(connectionURL.toString());
connectionPool.setUsername(dbSettings.getUserName());
connectionPool.setPassword(dbSettings.getPassword());
@@ -189,31 +191,34 @@ final class PostgresEamDb extends AbstractSqlEamDb {
protected String getConflictClause() {
return CONFLICT_CLAUSE;
}
-
+
/**
- * Gets an exclusive lock (if applicable).
- * Will return the lock if successful, null if unsuccessful because locking
- * isn't supported, and throw an exception if we should have been able to get the
- * lock but failed (meaning the database is in use).
+ * Gets an exclusive lock (if applicable). Will return the lock if
+ * successful, null if unsuccessful because locking isn't supported, and
+ * throw an exception if we should have been able to get the lock but failed
+ * (meaning the database is in use).
+ *
* @return the lock, or null if locking is not supported
- * @throws EamDbException if the coordination service is running but we fail to get the lock
+ *
+ * @throws EamDbException if the coordination service is running but we fail
+ * to get the lock
*/
@Override
- public CoordinationService.Lock getExclusiveMultiUserDbLock() throws EamDbException{
+ public CoordinationService.Lock getExclusiveMultiUserDbLock() throws EamDbException {
try {
// First check if multi user mode is enabled - if not there's no point trying to get a lock
- if( ! UserPreferences.getIsMultiUserModeEnabled()){
+ if (!UserPreferences.getIsMultiUserModeEnabled()) {
return null;
}
-
+
String databaseNodeName = dbSettings.getHost() + "_" + dbSettings.getDbName();
CoordinationService.Lock lock = CoordinationService.getInstance().tryGetExclusiveLock(CoordinationService.CategoryNode.CENTRAL_REPO, databaseNodeName, 5, TimeUnit.MINUTES);
- if(lock != null){
+ if (lock != null) {
return lock;
}
throw new EamDbException("Error acquiring database lock");
- } catch (InterruptedException ex){
+ } catch (InterruptedException ex) {
throw new EamDbException("Error acquiring database lock");
} catch (CoordinationService.CoordinationServiceException ex) {
// This likely just means the coordination service isn't running, which is ok
@@ -221,4 +226,23 @@ final class PostgresEamDb extends AbstractSqlEamDb {
}
}
+ @Override
+ boolean doesColumnExist(Connection conn, String tableName, String columnName) throws SQLException {
+ final String objectIdColumnExistsTemplate = "SELECT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='%s' AND column_name='%s')"; //NON-NLS
+ ResultSet resultSet = null;
+ Statement statement = null;
+ boolean columnExists = false;
+ try {
+ statement = conn.createStatement();
+ resultSet = statement.executeQuery(String.format(objectIdColumnExistsTemplate, tableName, columnName));
+ if (resultSet.next()) {
+ columnExists = resultSet.getBoolean(1);
+ }
+ } finally {
+ EamDbUtil.closeResultSet(resultSet);
+ EamDbUtil.closeStatement(statement);
+ }
+ return columnExists;
+ }
+
}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java
index 6ee454f915..3be19c9c0e 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java
@@ -344,11 +344,13 @@ public final class PostgresEamDbSettings {
createDataSourcesTable.append("case_id integer NOT NULL,");
createDataSourcesTable.append("device_id text NOT NULL,");
createDataSourcesTable.append("name text NOT NULL,");
+ createDataSourcesTable.append("datasource_obj_id integer,");
createDataSourcesTable.append("foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,");
createDataSourcesTable.append("CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name)");
createDataSourcesTable.append(")");
String dataSourceIdx1 = "CREATE INDEX IF NOT EXISTS data_sources_name ON data_sources (name)";
+ String dataSourceIdx2 = "CREATE INDEX IF NOT EXISTS data_sources_object_id ON data_sources (datasource_obj_id)";
StringBuilder createReferenceSetsTable = new StringBuilder();
createReferenceSetsTable.append("CREATE TABLE IF NOT EXISTS reference_sets (");
@@ -394,11 +396,11 @@ public final class PostgresEamDbSettings {
String createArtifactInstancesTableTemplate = getCreateArtifactInstancesTableTemplate();
- String instancesIdx1 = getAddCaseIdIndexTemplate();
- String instancesIdx2 = getAddDataSourceIdIndexTemplate();
-
- String instancesIdx3 = getAddValueIndexTemplate();
- String instancesIdx4 = getAddKnownStatusIndexTemplate();
+ String instancesCaseIdIdx = getAddCaseIdIndexTemplate();
+ String instancesDatasourceIdIdx = getAddDataSourceIdIndexTemplate();
+ String instancesValueIdx = getAddValueIndexTemplate();
+ String instancesKnownStatusIdx = getAddKnownStatusIndexTemplate();
+ String instancesObjectIdIdx = getAddObjectIdIndexTemplate();
StringBuilder createDbInfoTable = new StringBuilder();
createDbInfoTable.append("CREATE TABLE IF NOT EXISTS db_info (");
@@ -425,7 +427,8 @@ public final class PostgresEamDbSettings {
stmt.execute(createDataSourcesTable.toString());
stmt.execute(dataSourceIdx1);
-
+ stmt.execute(dataSourceIdx2);
+
stmt.execute(createReferenceSetsTable.toString());
stmt.execute(referenceSetsIdx1);
@@ -443,10 +446,11 @@ public final class PostgresEamDbSettings {
instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx1, instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx2, instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx3, instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx4, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesCaseIdIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesDatasourceIdIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesValueIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesKnownStatusIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesObjectIdIdx, instance_type_dbname, instance_type_dbname));
// FUTURE: allow more than the FILES type
if (type.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) {
@@ -486,6 +490,7 @@ public final class PostgresEamDbSettings {
createArtifactInstancesTableTemplate.append("file_path text NOT NULL,");
createArtifactInstancesTableTemplate.append("known_status integer NOT NULL,");
createArtifactInstancesTableTemplate.append("comment text,");
+ createArtifactInstancesTableTemplate.append("file_obj_id integer,");
createArtifactInstancesTableTemplate.append("CONSTRAINT %s_multi_unique_ UNIQUE (data_source_id, value, file_path),");
createArtifactInstancesTableTemplate.append("foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,");
createArtifactInstancesTableTemplate.append("foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL");
@@ -545,6 +550,19 @@ public final class PostgresEamDbSettings {
return "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)";
}
+ /**
+ * Get the template for creating an index on the file_obj_id column of an
+ * instance table. %s will exist in the template where the name of the new
+ * table will be addedd.
+ *
+ * @return a String which is a template for adding an index to the file_obj_id
+ * column of a _instances table
+ */
+ static String getAddObjectIdIndexTemplate() {
+ // Each "%s" will be replaced with the relevant TYPE_instances table name.
+ return "CREATE INDEX IF NOT EXISTS %s_file_obj_id ON %s (file_obj_id)";
+ }
+
public boolean insertDefaultDatabaseContent() {
Connection conn = getEphemeralConnection(false);
if (null == conn) {
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java
index a75f4648ff..36484d2f2d 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java
@@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.centralrepository.datamodel;
import java.sql.Connection;
+import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
@@ -57,7 +58,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* @return the singleton instance of SqliteEamDb
*
* @throws EamDbException if one or more default correlation type(s) have an
- * invalid db table name.
+ * invalid db table name.
*/
public synchronized static SqliteEamDb getInstance() throws EamDbException {
if (instance == null) {
@@ -70,7 +71,8 @@ final class SqliteEamDb extends AbstractSqlEamDb {
/**
*
* @throws EamDbException if the AbstractSqlEamDb class has one or more
- * default correlation type(s) having an invalid db table name.
+ * default correlation type(s) having an invalid db
+ * table name.
*/
private SqliteEamDb() throws EamDbException {
dbSettings = new SqliteEamDbSettings();
@@ -205,7 +207,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
/**
* Add a new name/value pair in the db_info table.
*
- * @param name Key to set
+ * @param name Key to set
* @param value Value to set
*
* @throws EamDbException
@@ -242,7 +244,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
/**
* Update the value for a name in the name/value db_info table.
*
- * @param name Name to find
+ * @param name Name to find
* @param value Value to assign to name.
*
* @throws EamDbException
@@ -272,6 +274,16 @@ final class SqliteEamDb extends AbstractSqlEamDb {
}
}
+ @Override
+ public void addDataSourceObjectId(int rowId, long dataSourceObjectId) throws EamDbException{
+ try {
+ acquireExclusiveLock();
+ super.addDataSourceObjectId(rowId, dataSourceObjectId);
+ } finally {
+ releaseExclusiveLock();
+ }
+ }
+
/**
* Creates new Case in the database
*
@@ -360,10 +372,10 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* @param eamDataSource the data source to add
*/
@Override
- public void newDataSource(CorrelationDataSource eamDataSource) throws EamDbException {
+ public CorrelationDataSource newDataSource(CorrelationDataSource eamDataSource) throws EamDbException {
try {
acquireExclusiveLock();
- super.newDataSource(eamDataSource);
+ return super.newDataSource(eamDataSource);
} finally {
releaseExclusiveLock();
}
@@ -372,28 +384,28 @@ final class SqliteEamDb extends AbstractSqlEamDb {
/**
* Retrieves Data Source details based on data source device ID
*
- * @param correlationCase the current CorrelationCase used for ensuring
- * uniqueness of DataSource
+ * @param correlationCase the current CorrelationCase used for ensuring
+ * uniqueness of DataSource
* @param dataSourceDeviceId the data source device ID number
*
* @return The data source
*/
@Override
- public CorrelationDataSource getDataSource(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException {
+ public CorrelationDataSource getDataSource(CorrelationCase correlationCase, Long caseDbDataSourceId) throws EamDbException {
try {
acquireSharedLock();
- return super.getDataSource(correlationCase, dataSourceDeviceId);
+ return super.getDataSource(correlationCase, caseDbDataSourceId);
} finally {
releaseSharedLock();
}
}
-
+
/**
* Retrieves Data Source details based on data source ID
*
- * @param correlationCase the current CorrelationCase used for ensuring
- * uniqueness of DataSource
- * @param dataSourceId the data source ID number
+ * @param correlationCase the current CorrelationCase used for ensuring
+ * uniqueness of DataSource
+ * @param dataSourceId the data source ID number
*
* @return The data source
*/
@@ -461,7 +473,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* Retrieves eamArtifact instances from the database that are associated
* with the aType and filePath
*
- * @param aType EamArtifact.Type to search for
+ * @param aType EamArtifact.Type to search for
* @param filePath File path to search for
*
* @return List of 0 or more EamArtifactInstances
@@ -486,7 +498,8 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* @param value The value to search for
*
* @return Number of artifact instances having ArtifactType and
- * ArtifactValue.
+ * ArtifactValue.
+ *
* @throws EamDbException
*/
@Override
@@ -518,6 +531,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* @param value The value to search for
*
* @return Number of unique tuples
+ *
* @throws EamDbException
*/
@Override
@@ -545,17 +559,17 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* associated with the caseDisplayName and dataSource of the given
* eamArtifact instance.
*
- * @param caseUUID Case ID to search for
+ * @param caseUUID Case ID to search for
* @param dataSourceID Data source ID to search for
*
* @return Number of artifact instances having caseDisplayName and
- * dataSource
+ * dataSource
*/
@Override
- public Long getCountArtifactInstancesByCaseDataSource(String caseUUID, String dataSourceID) throws EamDbException {
+ public Long getCountArtifactInstancesByCaseDataSource(CorrelationDataSource correlationDataSource) throws EamDbException {
try {
acquireSharedLock();
- return super.getCountArtifactInstancesByCaseDataSource(caseUUID, dataSourceID);
+ return super.getCountArtifactInstancesByCaseDataSource(correlationDataSource);
} finally {
releaseSharedLock();
}
@@ -563,7 +577,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
/**
* Executes a bulk insert of the eamArtifacts added from the
- addAttributeInstanceBulk() method
+ * addAttributeInstanceBulk() method
*/
@Override
public void commitAttributeInstancesBulk() throws EamDbException {
@@ -596,7 +610,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
*
* @param eamArtifact Artifact containing exactly one (1) ArtifactInstance.
* @param knownStatus The status to change the artifact to. Should never be
- * KNOWN
+ * KNOWN
*/
@Override
public void setAttributeInstanceKnownStatus(CorrelationAttributeInstance eamArtifact, TskData.FileKnown knownStatus) throws EamDbException {
@@ -633,7 +647,9 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* "Bad".
*
* @param aType EamArtifact.Type to search for
+ *
* @return List with 0 or more matching eamArtifact instances.
+ *
* @throws EamDbException
*/
@Override
@@ -672,7 +688,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* @param value Value to search for
*
* @return List of cases containing this artifact with instances marked as
- * bad
+ * bad
*
* @throws EamDbException
*/
@@ -690,6 +706,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* Remove a reference set and all values contained in it.
*
* @param referenceSetID
+ *
* @throws EamDbException
*/
@Override
@@ -708,6 +725,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* @param value
* @param referenceSetID
* @param correlationTypeID
+ *
* @return true if the hash is found in the reference set
*/
@Override
@@ -723,8 +741,9 @@ final class SqliteEamDb extends AbstractSqlEamDb {
/**
* Process the Artifact instance in the EamDb
*
- * @param type EamArtifact.Type to search for
+ * @param type EamArtifact.Type to search for
* @param instanceTableCallback callback to process the instance
+ *
* @throws EamDbException
*/
@Override
@@ -736,12 +755,13 @@ final class SqliteEamDb extends AbstractSqlEamDb {
releaseSharedLock();
}
}
-
+
/**
* Process the Artifact instance in the EamDb
*
- * @param type EamArtifact.Type to search for
+ * @param type EamArtifact.Type to search for
* @param instanceTableCallback callback to process the instance
+ *
* @throws EamDbException
*/
@Override
@@ -752,7 +772,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
} finally {
releaseSharedLock();
}
- }
+ }
/**
* Check whether a reference set with the given name/version is in the
@@ -761,7 +781,9 @@ final class SqliteEamDb extends AbstractSqlEamDb {
*
* @param referenceSetName
* @param version
+ *
* @return true if a matching set is found
+ *
* @throws EamDbException
*/
@Override
@@ -928,7 +950,8 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* Add a new reference instance
*
* @param eamGlobalFileInstance The reference instance to add
- * @param correlationType Correlation Type that this Reference Instance is
+ * @param correlationType Correlation Type that this Reference
+ * Instance is
*
* @throws EamDbException
*/
@@ -960,7 +983,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
/**
* Get all reference entries having a given correlation type and value
*
- * @param aType Type to use for matching
+ * @param aType Type to use for matching
* @param aValue Value to use for matching
*
* @return List of all global file instances with a type and value
@@ -1001,7 +1024,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* artifacts.
*
* @return List of EamArtifact.Type's. If none are defined in the database,
- * the default list will be returned.
+ * the default list will be returned.
*
* @throws EamDbException
*/
@@ -1020,7 +1043,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* artifacts.
*
* @return List of enabled EamArtifact.Type's. If none are defined in the
- * database, the default list will be returned.
+ * database, the default list will be returned.
*
* @throws EamDbException
*/
@@ -1039,7 +1062,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* correlate artifacts.
*
* @return List of supported EamArtifact.Type's. If none are defined in the
- * database, the default list will be returned.
+ * database, the default list will be returned.
*
* @throws EamDbException
*/
@@ -1111,8 +1134,9 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* (meaning the database is in use).
*
* @return the lock, or null if locking is not supported
+ *
* @throws EamDbException if the coordination service is running but we fail
- * to get the lock
+ * to get the lock
*/
@Override
public CoordinationService.Lock getExclusiveMultiUserDbLock() throws EamDbException {
@@ -1156,4 +1180,26 @@ final class SqliteEamDb extends AbstractSqlEamDb {
rwLock.readLock().unlock();
}
+ @Override
+ boolean doesColumnExist(Connection conn, String tableName, String columnName) throws SQLException {
+ final String tableInfoQueryTemplate = "PRAGMA table_info(%s)"; //NON-NLS
+ ResultSet resultSet = null;
+ Statement statement = null;
+ boolean columnExists = false;
+ try {
+ statement = conn.createStatement();
+ resultSet = statement.executeQuery(String.format(tableInfoQueryTemplate, tableName));
+ while (resultSet.next()) {
+ // the second value ( 2 ) is the column name
+ if (resultSet.getString(2).equals(columnName)) {
+ columnExists = true;
+ break;
+ }
+ }
+ } finally {
+ EamDbUtil.closeResultSet(resultSet);
+ EamDbUtil.closeStatement(statement);
+ }
+ return columnExists;
+ }
}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java
index 615e49e523..5a967155bf 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java
@@ -287,11 +287,13 @@ public final class SqliteEamDbSettings {
createDataSourcesTable.append("case_id integer NOT NULL,");
createDataSourcesTable.append("device_id text NOT NULL,");
createDataSourcesTable.append("name text NOT NULL,");
+ createDataSourcesTable.append("datasource_obj_id integer,");
createDataSourcesTable.append("foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,");
createDataSourcesTable.append("CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name)");
createDataSourcesTable.append(")");
String dataSourceIdx1 = "CREATE INDEX IF NOT EXISTS data_sources_name ON data_sources (name)";
+ String dataSourceIdx2 = "CREATE INDEX IF NOT EXISTS data_sources_object_id ON data_sources (datasource_obj_id)";
StringBuilder createReferenceSetsTable = new StringBuilder();
createReferenceSetsTable.append("CREATE TABLE IF NOT EXISTS reference_sets (");
@@ -337,12 +339,12 @@ public final class SqliteEamDbSettings {
String createArtifactInstancesTableTemplate = getCreateArtifactInstancesTableTemplate();
- String instancesIdx1 = getAddCaseIdIndexTemplate();
- String instancesIdx2 = getAddDataSourceIdIndexTemplate();
-
- String instancesIdx3 = getAddValueIndexTemplate();
- String instancesIdx4 = getAddKnownStatusIndexTemplate();
-
+ String instancesCaseIdIdx = getAddCaseIdIndexTemplate();
+ String instancesDatasourceIdIdx = getAddDataSourceIdIndexTemplate();
+ String instancesValueIdx = getAddValueIndexTemplate();
+ String instancesKnownStatusIdx = getAddKnownStatusIndexTemplate();
+ String instancesObjectIdIdx = getAddObjectIdIndexTemplate();
+
StringBuilder createDbInfoTable = new StringBuilder();
createDbInfoTable.append("CREATE TABLE IF NOT EXISTS db_info (");
createDbInfoTable.append("id integer primary key NOT NULL,");
@@ -374,6 +376,7 @@ public final class SqliteEamDbSettings {
stmt.execute(createDataSourcesTable.toString());
stmt.execute(dataSourceIdx1);
+ stmt.execute(dataSourceIdx2);
stmt.execute(createReferenceSetsTable.toString());
stmt.execute(referenceSetsIdx1);
@@ -392,10 +395,11 @@ public final class SqliteEamDbSettings {
instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx1, instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx2, instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx3, instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx4, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesCaseIdIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesDatasourceIdIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesValueIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesKnownStatusIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesObjectIdIdx, instance_type_dbname, instance_type_dbname));
// FUTURE: allow more than the FILES type
if (type.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) {
@@ -434,6 +438,7 @@ public final class SqliteEamDbSettings {
createArtifactInstancesTableTemplate.append("file_path text NOT NULL,");
createArtifactInstancesTableTemplate.append("known_status integer NOT NULL,");
createArtifactInstancesTableTemplate.append("comment text,");
+ createArtifactInstancesTableTemplate.append("file_obj_id integer,");
createArtifactInstancesTableTemplate.append("CONSTRAINT %s_multi_unique UNIQUE(data_source_id, value, file_path) ON CONFLICT IGNORE,");
createArtifactInstancesTableTemplate.append("foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,");
createArtifactInstancesTableTemplate.append("foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL");
@@ -493,6 +498,19 @@ public final class SqliteEamDbSettings {
return "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)";
}
+ /**
+ * Get the template for creating an index on the file_obj_id column of an
+ * instance table. %s will exist in the template where the name of the new
+ * table will be addedd.
+ *
+ * @return a String which is a template for adding an index to the file_obj_id
+ * column of a _instances table
+ */
+ static String getAddObjectIdIndexTemplate() {
+ // Each "%s" will be replaced with the relevant TYPE_instances table name.
+ return "CREATE INDEX IF NOT EXISTS %s_file_obj_id ON %s (file_obj_id)";
+ }
+
public boolean insertDefaultDatabaseContent() {
Connection conn = getEphemeralConnection();
if (null == conn) {
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java
index 2643c7aac5..ffff8c7b8b 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java
@@ -443,19 +443,16 @@ final class CaseEventListener implements PropertyChangeListener {
Content newDataSource = dataSourceAddedEvent.getDataSource();
try {
- String deviceId = openCase.getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId();
CorrelationCase correlationCase = dbManager.getCase(openCase);
if (null == correlationCase) {
correlationCase = dbManager.newCase(openCase);
}
- if (null == dbManager.getDataSource(correlationCase, deviceId)) {
+ if (null == dbManager.getDataSource(correlationCase, newDataSource.getId())) {
CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource);
}
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error adding new data source to the central repository", ex); //NON-NLS
- } catch (TskCoreException | TskDataException ex) {
- LOGGER.log(Level.SEVERE, "Error getting data source from DATA_SOURCE_ADDED event content.", ex); //NON-NLS
- }
+ }
} // DATA_SOURCE_ADDED
}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java
index 7469e38bd0..0eecc533b0 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java
@@ -152,14 +152,14 @@ final class IngestModule implements FileIngestModule {
// insert this file into the central repository
try {
CorrelationAttributeInstance cefi = new CorrelationAttributeInstance(
+ filesType,
md5,
- filesType,
eamCase,
eamDataSource,
abstractFile.getParentPath() + abstractFile.getName(),
null,
TskData.FileKnown.UNKNOWN // NOTE: Known status in the CR is based on tagging, not hashes like the Case Database.
- );
+, abstractFile.getId());
dbManager.addAttributeInstanceBulk(cefi);
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error adding artifact to bulk artifacts.", ex); // NON-NLS
@@ -192,7 +192,7 @@ final class IngestModule implements FileIngestModule {
logger.log(Level.SEVERE, "Error doing bulk insert of artifacts.", ex); // NON-NLS
}
try {
- Long count = dbManager.getCountArtifactInstancesByCaseDataSource(eamCase.getCaseUUID(), eamDataSource.getDeviceID());
+ Long count = dbManager.getCountArtifactInstancesByCaseDataSource(eamDataSource);
logger.log(Level.INFO, "{0} artifacts in db for case: {1} ds:{2}", new Object[]{count, eamCase.getDisplayName(), eamDataSource.getName()}); // NON-NLS
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error counting artifacts.", ex); // NON-NLS
@@ -303,7 +303,7 @@ final class IngestModule implements FileIngestModule {
== 1) {
// ensure we have this data source in the EAM DB
try {
- if (null == centralRepoDb.getDataSource(eamCase, eamDataSource.getDeviceID())) {
+ if (null == centralRepoDb.getDataSource(eamCase, eamDataSource.getDataSourceObjectID())) {
centralRepoDb.newDataSource(eamDataSource);
}
} catch (EamDbException ex) {
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties
index aae9fa321d..635f5a558c 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties
@@ -61,7 +61,7 @@ EamDbSettingsDialog.lbFullDbPath.text=
GlobalSettingsPanel.cbUseCentralRepo.text=Use a Central Repository
GlobalSettingsPanel.organizationTextArea.text=Organization information can be tracked in the Central Repository.
GlobalSettingsPanel.manageOrganizationButton.text=Manage Organizations
-GlobalSettingsPanel.lbCentralRepository.text=A Central Repository allows you to correlate files and results between cases.
+GlobalSettingsPanel.lbCentralRepository.text=A Central Repository allows you to correlate files and results between cases. Central Repository configuration can not be modified while a case is open.
GlobalSettingsPanel.pnCorrelationProperties.border.title=Correlation Properties
GlobalSettingsPanel.organizationPanel.border.title=Organizations
GlobalSettingsPanel.casesPanel.border.title=Case Details
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form
index 0a8c7dcc64..617f6e1fe5 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form
@@ -140,7 +140,7 @@
-
+
@@ -150,7 +150,7 @@
-
+
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java
index a4d6ef5cc0..67d1f33889 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java
@@ -23,11 +23,13 @@ import java.awt.EventQueue;
import org.sleuthkit.autopsy.coreutils.Logger;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import java.util.EnumSet;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
+import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.autopsy.ingest.IngestManager;
@@ -58,6 +60,10 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
initComponents();
customizeComponents();
addIngestJobEventsListener();
+ Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> {
+ //disable when case is open, enable when case is closed
+ ingestStateUpdated(evt.getNewValue() != null);
+ });
}
private void customizeComponents() {
@@ -66,7 +72,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
private void addIngestJobEventsListener() {
IngestManager.getInstance().addIngestJobEventListener(ingestJobEventListener);
- ingestStateUpdated();
+ ingestStateUpdated(Case.isCaseOpen());
}
@Messages({"GlobalSettingsPanel.updateFailed.title=Update failed",
@@ -173,7 +179,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addGroup(pnDatabaseConfigurationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnDatabaseConfigurationLayout.createSequentialGroup()
.addComponent(bnDbConfigure)
- .addContainerGap())
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(pnDatabaseConfigurationLayout.createSequentialGroup()
.addGroup(pnDatabaseConfigurationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(lbDbPlatformTypeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
@@ -181,7 +187,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addComponent(lbDbLocationLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(pnDatabaseConfigurationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
- .addComponent(lbDbNameValue, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(lbDbNameValue, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 936, Short.MAX_VALUE)
.addComponent(lbDbPlatformValue, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(lbDbLocationValue, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
);
@@ -429,7 +435,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
store();
updateDatabase();
load();
- this.ingestStateUpdated();
+ this.ingestStateUpdated(Case.isCaseOpen());
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_cbUseCentralRepoActionPerformed
@@ -447,7 +453,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
@Messages({"GlobalSettingsPanel.validationerrMsg.mustConfigure=Configure the database to enable this module."})
public void load() {
tbOops.setText("");
- enableAllSubComponents(false);
+ enableButtonSubComponents(false);
EamDbPlatformEnum selectedPlatform = EamDbPlatformEnum.getSelectedPlatform();
cbUseCentralRepo.setSelected(EamDbUtil.useCentralRepo()); // NON-NLS
switch (selectedPlatform) {
@@ -456,20 +462,19 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
lbDbPlatformValue.setText(EamDbPlatformEnum.POSTGRESQL.toString());
lbDbNameValue.setText(dbSettingsPg.getDbName());
lbDbLocationValue.setText(dbSettingsPg.getHost());
- enableAllSubComponents(true);
+ enableButtonSubComponents(cbUseCentralRepo.isSelected());
break;
case SQLITE:
SqliteEamDbSettings dbSettingsSqlite = new SqliteEamDbSettings();
lbDbPlatformValue.setText(EamDbPlatformEnum.SQLITE.toString());
lbDbNameValue.setText(dbSettingsSqlite.getDbName());
lbDbLocationValue.setText(dbSettingsSqlite.getDbDirectory());
- enableAllSubComponents(true);
+ enableButtonSubComponents(cbUseCentralRepo.isSelected());
break;
default:
lbDbPlatformValue.setText(EamDbPlatformEnum.DISABLED.toString());
lbDbNameValue.setText("");
lbDbLocationValue.setText("");
- enableDatabaseConfigureButton(cbUseCentralRepo.isSelected());
tbOops.setText(Bundle.GlobalSettingsPanel_validationerrMsg_mustConfigure());
break;
}
@@ -521,7 +526,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
- ingestStateUpdated();
+ ingestStateUpdated(Case.isCaseOpen());
}
});
}
@@ -550,38 +555,25 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
}
@Messages({"GlobalSettingsPanel.validationErrMsg.ingestRunning=You cannot change settings while ingest is running."})
- private void ingestStateUpdated() {
+ private void ingestStateUpdated(boolean caseIsOpen) {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(() -> {
- ingestStateUpdated();
+ ingestStateUpdated(caseIsOpen);
});
return;
}
+ cbUseCentralRepo.setEnabled(!caseIsOpen);
if (IngestManager.getInstance().isIngestRunning()) {
tbOops.setText(Bundle.GlobalSettingsPanel_validationErrMsg_ingestRunning());
tbOops.setVisible(true);
- cbUseCentralRepo.setEnabled(false);
- enableAllSubComponents(false);
- } else if (!cbUseCentralRepo.isEnabled()) {
- cbUseCentralRepo.setEnabled(true);
+ enableButtonSubComponents(cbUseCentralRepo.isSelected());
+ } else {
load();
+ enableDatabaseConfigureButton(cbUseCentralRepo.isSelected() && !caseIsOpen);
}
- }
- /**
- * Wrapper around each of the enableComponentXYZ methods to enable/disable
- * them all at the same time.
- *
- * @param enable
- *
- * @return True
- */
- private boolean enableAllSubComponents(Boolean enable) {
- enableDatabaseConfigureButton(cbUseCentralRepo.isSelected() && enable);
- enableButtonSubComponents(cbUseCentralRepo.isSelected() && enable);
- return true;
}
/**
diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CaseDBCommonAttributeInstanceNode.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CaseDBCommonAttributeInstanceNode.java
index b4f8ee525e..504aa45b97 100644
--- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CaseDBCommonAttributeInstanceNode.java
+++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CaseDBCommonAttributeInstanceNode.java
@@ -18,17 +18,16 @@
*/
package org.sleuthkit.autopsy.commonfilesearch;
-import java.util.List;
-import org.apache.commons.lang3.StringUtils;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
import org.openide.nodes.Sheet;
-import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
-import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
-import org.sleuthkit.autopsy.core.UserPreferences;
+import org.openide.util.NbBundle;
+import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.AbstractFile;
-import org.sleuthkit.datamodel.ContentTag;
/**
* Node that wraps CaseDBCommonAttributeInstance to represent a file instance
@@ -75,33 +74,25 @@ public class CaseDBCommonAttributeInstanceNode extends FileNode {
@Override
protected Sheet createSheet() {
- Sheet sheet = new Sheet();
+ Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
- if (sheetSet == null) {
- sheetSet = Sheet.createPropertiesSet();
- sheet.put(sheetSet);
+ Set keepProps = new HashSet<>(Arrays.asList(
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.mimeType")));
+
+ for(Property> p : sheetSet.getProperties()) {
+ if(!keepProps.contains(p.getName())){
+ sheetSet.remove(p.getName());
+ }
}
- List tags = getContentTagsFromDatabase();
-
final String NO_DESCR = Bundle.CommonFilesSearchResultsViewerTable_noDescText();
-
- sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, this.getContent().getName()));
- addScoreProperty(sheetSet, tags);
-
- CorrelationAttributeInstance correlationAttribute = null;
- if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
- correlationAttribute = getCorrelationAttributeInstance();
- }
- addCommentProperty(sheetSet, tags, correlationAttribute);
-
- if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
- addCountProperty(sheetSet, correlationAttribute);
- }
- sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, this.getContent().getParentPath()));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, this.getDataSource()));
- sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), NO_DESCR, StringUtils.defaultString(this.getContent().getMIMEType())));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), NO_DESCR, caseName));
+
return sheet;
}
}
\ No newline at end of file
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java
index d88b5ac2fb..72343ec616 100755
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java
@@ -67,19 +67,19 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
initComponents();
Utilities.configureTextPaneAsHtml(jTextPane1);
}
-
+
@Override
public void setNode(Node node) {
if ((node == null) || (!isSupported(node))) {
resetComponent();
return;
}
-
+
StringBuilder html = new StringBuilder();
-
+
BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
Content sourceFile = null;
-
+
try {
if (artifact != null) {
/*
@@ -100,32 +100,32 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
"Exception while trying to retrieve a Content instance from the BlackboardArtifact '%s' (id=%d).",
artifact.getDisplayName(), artifact.getArtifactID()), ex);
}
-
+
if (artifact != null) {
populateTagData(html, artifact, sourceFile);
} else {
populateTagData(html, sourceFile);
}
-
+
if (sourceFile instanceof AbstractFile) {
populateCentralRepositoryData(html, artifact, (AbstractFile) sourceFile);
}
-
+
setText(html.toString());
jTextPane1.setCaretPosition(0);
}
-
+
/**
* Populate the "Selected Item" sections with tag data for the supplied
* content.
- *
+ *
* @param html The HTML text to update.
* @param content Selected content.
*/
private void populateTagData(StringBuilder html, Content content) {
try {
SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
-
+
startSection(html, "Selected Item");
List fileTagsList = tskCase.getContentTagsByContent(content);
if (fileTagsList.isEmpty()) {
@@ -142,11 +142,11 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
logger.log(Level.SEVERE, "Exception while getting tags from the case database.", ex); //NON-NLS
}
}
-
+
/**
* Populate the "Selected Item" and "Source File" sections with tag data for
* a supplied artifact.
- *
+ *
* @param html The HTML text to update.
* @param artifact A selected artifact.
* @param sourceFile The source content of the selected artifact.
@@ -154,7 +154,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
private void populateTagData(StringBuilder html, BlackboardArtifact artifact, Content sourceFile) {
try {
SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
-
+
startSection(html, "Selected Item");
List artifactTagsList = tskCase.getBlackboardArtifactTagsByArtifact(artifact);
if (artifactTagsList.isEmpty()) {
@@ -165,7 +165,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
}
}
endSection(html);
-
+
if (sourceFile != null) {
startSection(html, "Source File");
List fileTagsList = tskCase.getContentTagsByContent(sourceFile);
@@ -184,10 +184,10 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
logger.log(Level.SEVERE, "Exception while getting tags from the case database.", ex); //NON-NLS
}
}
-
+
/**
* Populate the "Central Repository Comments" section with data.
- *
+ *
* @param html The HTML text to update.
* @param artifact A selected artifact (can be null).
* @param sourceFile A selected file, or a source file of the selected
@@ -208,23 +208,24 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
if (attributeType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) {
CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getCurrentCase());
instancesList.add(new CorrelationAttributeInstance(
- md5,
attributeType,
+ md5,
correlationCase,
CorrelationDataSource.fromTSKDataSource(correlationCase, sourceFile.getDataSource()),
sourceFile.getParentPath() + sourceFile.getName(),
"",
- sourceFile.getKnown()));
+ sourceFile.getKnown(),
+ sourceFile.getId()));
break;
}
}
}
boolean commentDataFound = false;
-
+
for (CorrelationAttributeInstance instance : instancesList) {
- List correlatedInstancesList =
- EamDb.getInstance().getArtifactInstancesByTypeValue(instance.getCorrelationType(), instance.getCorrelationValue());
+ List correlatedInstancesList
+ = EamDb.getInstance().getArtifactInstancesByTypeValue(instance.getCorrelationType(), instance.getCorrelationValue());
for (CorrelationAttributeInstance correlatedInstance : correlatedInstancesList) {
if (correlatedInstance.getComment() != null && correlatedInstance.getComment().isEmpty() == false) {
commentDataFound = true;
@@ -232,7 +233,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
}
}
}
-
+
if (commentDataFound == false) {
addMessage(html, "There is no comment data for the selected content in the Central Repository.");
}
@@ -247,16 +248,16 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
/**
* Set the text of the text panel.
- *
+ *
* @param text The text to set to the text panel.
*/
private void setText(String text) {
jTextPane1.setText("" + text + ""); //NON-NLS
}
-
+
/**
* Start a new data section.
- *
+ *
* @param html The HTML text to add the section to.
* @param sectionName The name of the section.
*/
@@ -265,10 +266,10 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
.append(sectionName)
.append("
"); //NON-NLS
}
-
+
/**
* Add a message.
- *
+ *
* @param html The HTML text to add the message to.
* @param message The message text.
*/
@@ -277,10 +278,10 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
.append(message)
.append(" "); //NON-NLS
}
-
+
/**
* Add a data table containing information about a tag.
- *
+ *
* @param html The HTML text to add the table to.
* @param tag The tag whose information will be used to populate the table.
*/
@@ -296,11 +297,11 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
addRow(html, Bundle.AnnotationsContentViewer_tagEntryDataLabel_comment(), formatHtmlString(tag.getComment()));
endTable(html);
}
-
+
/**
* Add a data table containing information about a correlation attribute
* instance in the Central Repository.
- *
+ *
* @param html The HTML text to add the table to.
* @param attributeInstance The attribute instance whose information will be
* used to populate the table.
@@ -319,10 +320,10 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
addRow(html, Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_path(), attributeInstance.getFilePath());
endTable(html);
}
-
+
/**
* Start a data table.
- *
+ *
* @param html The HTML text to add the table to.
*/
private void startTable(StringBuilder html) {
@@ -331,7 +332,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
/**
* Add a data row to a table.
- *
+ *
* @param html The HTML text to add the row to.
* @param key The key for the left column of the data row.
* @param value The value for the right column of the data row.
@@ -343,10 +344,10 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
html.append(value);
html.append(""); //NON-NLS
}
-
+
/**
* End a data table.
- *
+ *
* @param html The HTML text on which to end a table.
*/
private void endTable(StringBuilder html) {
@@ -355,18 +356,19 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
/**
* End a data section.
- *
+ *
* @param html The HTML text on which to end a section.
*/
private void endSection(StringBuilder html) {
html.append(" "); //NON-NLS
}
-
+
/**
* Apply escape sequence to special characters. Line feed and carriage
* return character combinations will be converted to HTML line breaks.
- *
+ *
* @param text The text to format.
+ *
* @return The formatted text.
*/
private String formatHtmlString(String text) {
@@ -428,7 +430,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
@Override
public boolean isSupported(Node node) {
BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
-
+
try {
if (artifact != null) {
if (artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID()) != null) {
@@ -444,7 +446,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
"Exception while trying to retrieve a Content instance from the BlackboardArtifact '%s' (id=%d).",
artifact.getDisplayName(), artifact.getArtifactID()), ex);
}
-
+
return false;
}
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java
index e1565c3b89..bf319bde0c 100644
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java
@@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.contentviewers;
import java.awt.Component;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -43,6 +44,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.coreutils.Logger;
+import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
@@ -721,31 +723,23 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
@Override
protected Sheet createSheet() {
- Sheet sheet = new Sheet();
+ Sheet sheet = super.createSheet();
+ Set keepProps = new HashSet<>(Arrays.asList(
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.sizeColLbl"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.mimeType"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.knownColLbl")));
+
+ //Remove all other props except for the ones above
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
- if (sheetSet == null) {
- sheetSet = Sheet.createPropertiesSet();
- sheet.put(sheetSet);
+ for(Property> p : sheetSet.getProperties()) {
+ if(!keepProps.contains(p.getName())){
+ sheetSet.remove(p.getName());
+ }
}
- List tags = getContentTagsFromDatabase();
-
- AbstractFile file = getContent();
- sheetSet.put(new NodeProperty<>("Name", "Name", "Name", file.getName()));
-
- addScoreProperty(sheetSet, tags);
-
- CorrelationAttributeInstance correlationAttribute = null;
- if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
- correlationAttribute = getCorrelationAttributeInstance();
- }
- addCommentProperty(sheetSet, tags, correlationAttribute);
-
- if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
- addCountProperty(sheetSet, correlationAttribute);
- }
- sheetSet.put(new NodeProperty<>("Size", "Size", "Size", file.getSize()));
- sheetSet.put(new NodeProperty<>("Mime Type", "Mime Type", "Mime Type", StringUtils.defaultString(file.getMIMEType())));
- sheetSet.put(new NodeProperty<>("Known", "Known", "Known", file.getKnown().getName()));
return sheet;
}
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java
index f2be8c90c4..f2db7c2532 100755
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java
@@ -24,21 +24,15 @@ import java.awt.Cursor;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.SQLException;
-import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.function.Consumer;
import java.util.logging.Level;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
@@ -48,11 +42,11 @@ import org.apache.commons.io.FilenameUtils;
import org.openide.util.NbBundle;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
-import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
+import org.sleuthkit.autopsy.coreutils.SQLiteTableReaderException;
import org.sleuthkit.autopsy.coreutils.Logger;
-import org.sleuthkit.datamodel.AbstractFile;
-import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
+import org.sleuthkit.datamodel.AbstractFile;
+import org.sleuthkit.autopsy.coreutils.SQLiteTableReader;
/**
* A file content viewer for SQLite database files.
@@ -66,8 +60,14 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
private static final Logger logger = Logger.getLogger(FileViewer.class.getName());
private final SQLiteTableView selectedTableView = new SQLiteTableView();
private AbstractFile sqliteDbFile;
- private File tmpDbFile;
- private Connection connection;
+
+ private SQLiteTableReader viewReader;
+
+ private Map row = new LinkedHashMap<>();
+ private List