diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index bfcbcb6cb5..2987ada263 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -40,6 +40,7 @@ import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.logging.Level; +import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil.updateSchemaVersion; @@ -625,7 +626,7 @@ abstract class AbstractSqlEamDb implements EamDb { // This data source is already in the central repo return eamDataSource; } - + Connection conn = connect(); PreparedStatement preparedStatement = null; @@ -650,7 +651,7 @@ abstract class AbstractSqlEamDb implements EamDb { /* * If nothing was inserted, then return the data source that * exists in the Central Repository. - * + * * This is expected to occur with PostgreSQL Central Repository * databases. */ @@ -675,7 +676,7 @@ abstract class AbstractSqlEamDb implements EamDb { * If an exception was thrown causing us to not return a new data * source, attempt to get an existing data source with the same case * ID and data source object ID. - * + * * This exception block is expected to occur with SQLite Central * Repository databases. */ @@ -1052,6 +1053,74 @@ abstract class AbstractSqlEamDb implements EamDb { } } + /** + * Retrieves eamArtifact instances from the database that are associated + * with the eamArtifactType and eamArtifactValue of the given eamArtifact. + * + * @param aType The type of the artifact + * @param value The correlation value + * + * @return List of artifact instances for a given type/value + * + * @throws EamDbException + */ + public List getArtifactInstancesByTypeValues(CorrelationAttributeInstance.Type aType, List values) throws EamDbException, CorrelationAttributeNormalizationException { + + String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType); + String sql + = "SELECT " + + tableName + + ".id," + + tableName + + ".value," + + 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, data_sources.md5, data_sources.sha1, data_sources.sha256 FROM " + + tableName + + " LEFT JOIN cases ON " + + tableName + + ".case_id=cases.id" + + " LEFT JOIN data_sources ON " + + tableName + + ".data_source_id=data_sources.id" + + " WHERE value IN ("; + StringBuilder inValuesBuilder = new StringBuilder(sql); + //WJS-TODO use non-stream solution to making statement for proper error handling + for (String value : values) { + if (value != null) { + inValuesBuilder.append("'"); + inValuesBuilder.append(value); + inValuesBuilder.append("',"); + } + } + inValuesBuilder.deleteCharAt(inValuesBuilder.length() - 1); //delete last comma + inValuesBuilder.append(")"); + Connection conn = connect(); + + List artifactInstances = new ArrayList<>(); + + CorrelationAttributeInstance artifactInstance; + PreparedStatement preparedStatement = null; + ResultSet resultSet = null; + + try { + preparedStatement = conn.prepareStatement(sql); + resultSet = preparedStatement.executeQuery(); + while (resultSet.next()) { + artifactInstance = getEamArtifactInstanceFromResultSet(resultSet, aType); + artifactInstances.add(artifactInstance); + } + } catch (SQLException ex) { + throw new EamDbException("Error getting artifact instances by artifactType and artifactValue.", ex); // NON-NLS + } finally { + EamDbUtil.closeStatement(preparedStatement); + EamDbUtil.closeResultSet(resultSet); + EamDbUtil.closeConnection(conn); + } + + return artifactInstances; + } + /** * Retrieves eamArtifact instances from the database that are associated * with the eamArtifactType and eamArtifactValue of the given eamArtifact. @@ -1114,6 +1183,69 @@ abstract class AbstractSqlEamDb implements EamDb { return artifactInstances; } + /** + * Retrieves eamArtifact instances from the database that are associated + * with the eamArtifactType and eamArtifactValue of the given eamArtifact. + * + * @param aType The type of the artifact + * @param value The correlation value + * + * @return List of artifact instances for a given type/value + * + * @throws EamDbException + */ + @Override + public List getArtifactInstancesByTypeValueAndCase(CorrelationAttributeInstance.Type aType, String value, List caseIds) throws EamDbException, CorrelationAttributeNormalizationException { + String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType); + String sql + = "SELECT " + + tableName + + ".id," + + tableName + + ".value," + + 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, data_sources.md5, data_sources.sha1, data_sources.sha256 FROM " + + tableName + + " LEFT JOIN cases ON " + + tableName + + ".case_id=cases.id" + + " LEFT JOIN data_sources ON " + + tableName + + ".data_source_id=data_sources.id" + + " WHERE value=? and " + + tableName + +".case_id in ('"; + StringBuilder inValuesBuilder = new StringBuilder(sql); + inValuesBuilder.append(caseIds.stream().map(String::valueOf).collect(Collectors.joining("', '"))); + inValuesBuilder.append("')"); + String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value); + Connection conn = connect(); + List artifactInstances = new ArrayList<>(); + + CorrelationAttributeInstance artifactInstance; + PreparedStatement preparedStatement = null; + ResultSet resultSet = null; + + try { + preparedStatement = conn.prepareStatement(inValuesBuilder.toString()); + preparedStatement.setString(1, normalizedValue); + resultSet = preparedStatement.executeQuery(); + while (resultSet.next()) { + artifactInstance = getEamArtifactInstanceFromResultSet(resultSet, aType); + artifactInstances.add(artifactInstance); + } + } catch (SQLException ex) { + throw new EamDbException("Error getting artifact instances by artifactType and artifactValue.", ex); // NON-NLS + } finally { + EamDbUtil.closeStatement(preparedStatement); + EamDbUtil.closeResultSet(resultSet); + EamDbUtil.closeConnection(conn); + } + + return artifactInstances; + } + /** * Retrieves eamArtifact instances from the database that are associated * with the aType and filePath diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java index a5ef89caa0..110a24e5a1 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java @@ -284,6 +284,16 @@ public interface EamDb { */ List getArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException; + /** + * Retrieves eamArtifact instances from the database that are associated + * with the eamArtifactType and eamArtifactValue of the given eamArtifact. + * + * @param aType EamArtifact.Type to search for + * @param value Value to search for + * + * @return List of artifact instances for a given type/value + */ + List getArtifactInstancesByTypeValueAndCase(CorrelationAttributeInstance.Type aType, String value, List caseIds) throws EamDbException, CorrelationAttributeNormalizationException; /** * Retrieves eamArtifact instances from the database that are associated * with the aType and filePath diff --git a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCaseSearchResultsProcessor.java b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCaseSearchResultsProcessor.java index 3dafb6e06e..e4146a15af 100644 --- a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCaseSearchResultsProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCaseSearchResultsProcessor.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.commonpropertiessearch; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -240,6 +241,11 @@ final class InterCaseSearchResultsProcessor { public void process(ResultSet resultSet) { try { Set values = new HashSet<>(); + List targetCases = new ArrayList<>(); + if (targetCase != 0) { + targetCases.add(caseID); + targetCases.add(targetCase); + } while (resultSet.next()) { String corValue = InstanceTableCallback.getValue(resultSet); if (corValue == null || HashUtility.isNoDataMd5(corValue)) { @@ -248,7 +254,12 @@ final class InterCaseSearchResultsProcessor { values.add(corValue); } for (String corValue : values) { - List instances = EamDb.getInstance().getArtifactInstancesByTypeValue(correlationType, corValue); + List instances; + if (targetCases.isEmpty()) { + instances = EamDb.getInstance().getArtifactInstancesByTypeValue(correlationType, corValue); + } else { + instances = EamDb.getInstance().getArtifactInstancesByTypeValueAndCase(correlationType, corValue, targetCases); + } int size = instances.size(); if (size > 1) { CommonAttributeValue commonAttributeValue = new CommonAttributeValue(corValue); @@ -257,9 +268,7 @@ final class InterCaseSearchResultsProcessor { CentralRepoCommonAttributeInstance searchResult = new CentralRepoCommonAttributeInstance(instance.getID(), correlationType, NODE_TYPE.COUNT_NODE); searchResult.setCurrentAttributeInst(instance); commonAttributeValue.addInstance(searchResult); - if (!anotherCase && ((targetCase == 0 && instance.getCorrelationCase().getID() != caseID) || (targetCase == instance.getCorrelationCase().getID()))) { - anotherCase = true; - } + anotherCase = anotherCase || instance.getCorrelationCase().getID() != caseID; } if (anotherCase) { if (instanceCollatedCommonFiles.containsKey(size)) { @@ -308,6 +317,11 @@ final class InterCaseSearchResultsProcessor { @Override public void process(ResultSet resultSet) { try { + List targetCases = new ArrayList<>(); + if (targetCase != 0) { + targetCases.add(caseID); + targetCases.add(targetCase); + } Set values = new HashSet<>(); while (resultSet.next()) { String corValue = InstanceTableCallback.getValue(resultSet); @@ -317,44 +331,34 @@ final class InterCaseSearchResultsProcessor { values.add(corValue); } for (String corValue : values) { - List instances = EamDb.getInstance().getArtifactInstancesByTypeValue(correlationType, corValue); + List instances; + if (targetCases.isEmpty()) { + instances = EamDb.getInstance().getArtifactInstancesByTypeValue(correlationType, corValue); + } else { + instances = EamDb.getInstance().getArtifactInstancesByTypeValueAndCase(correlationType, corValue, targetCases); + } if (instances.size() > 1) { - boolean addToResults = targetCase == 0; - if (!addToResults) { - for (CorrelationAttributeInstance instance : instances) { - if (instance.getCorrelationCase().getID() == targetCase) { - System.out.println("Target case found in results"); - addToResults = true; - break; - } + for (CorrelationAttributeInstance instance : instances) { + CorrelationCase correlationCase = instance.getCorrelationCase(); + String caseName = correlationCase.getDisplayName(); + CorrelationDataSource correlationDatasource = instance.getCorrelationDataSource(); + //label datasource with it's id for uniqueness done in same manner as ImageGallery does in the DataSourceCell class + String dataSourceNameKey = correlationDatasource.getName() + " (Id: " + correlationDatasource.getDataSourceObjectID() + ")"; + if (!caseCollatedDataSourceCollections.containsKey(caseName)) { + caseCollatedDataSourceCollections.put(caseName, new HashMap<>()); } - } - else { - System.out.println("Target case is not set adding all results"); - } - if (addToResults) { - for (CorrelationAttributeInstance instance : instances) { - CorrelationCase correlationCase = instance.getCorrelationCase(); - String caseName = correlationCase.getDisplayName(); - CorrelationDataSource correlationDatasource = instance.getCorrelationDataSource(); - //label datasource with it's id for uniqueness done in same manner as ImageGallery does in the DataSourceCell class - String dataSourceNameKey = correlationDatasource.getName() + " (Id: " + correlationDatasource.getDataSourceObjectID() + ")"; - if (!caseCollatedDataSourceCollections.containsKey(caseName)) { - caseCollatedDataSourceCollections.put(caseName, new HashMap<>()); - } - Map dataSourceToFile = caseCollatedDataSourceCollections.get(caseName); - if (!dataSourceToFile.containsKey(dataSourceNameKey)) { - dataSourceToFile.put(dataSourceNameKey, new CommonAttributeValueList()); - } - CommonAttributeValueList valueList = dataSourceToFile.get(dataSourceNameKey); - CentralRepoCommonAttributeInstance searchResult = new CentralRepoCommonAttributeInstance(instance.getID(), correlationType, NODE_TYPE.CASE_NODE); - searchResult.setCurrentAttributeInst(instance); - CommonAttributeValue commonAttributeValue = new CommonAttributeValue(corValue); - commonAttributeValue.addInstance(searchResult); - valueList.addMetadataToList(commonAttributeValue); - dataSourceToFile.put(dataSourceNameKey, valueList); - caseCollatedDataSourceCollections.put(caseName, dataSourceToFile); + Map dataSourceToFile = caseCollatedDataSourceCollections.get(caseName); + if (!dataSourceToFile.containsKey(dataSourceNameKey)) { + dataSourceToFile.put(dataSourceNameKey, new CommonAttributeValueList()); } + CommonAttributeValueList valueList = dataSourceToFile.get(dataSourceNameKey); + CentralRepoCommonAttributeInstance searchResult = new CentralRepoCommonAttributeInstance(instance.getID(), correlationType, NODE_TYPE.CASE_NODE); + searchResult.setCurrentAttributeInst(instance); + CommonAttributeValue commonAttributeValue = new CommonAttributeValue(corValue); + commonAttributeValue.addInstance(searchResult); + valueList.addMetadataToList(commonAttributeValue); + dataSourceToFile.put(dataSourceNameKey, valueList); + caseCollatedDataSourceCollections.put(caseName, dataSourceToFile); } } }