6711 add ResultDomain object

This commit is contained in:
William Schaefer 2020-08-20 16:07:34 -04:00
parent 1b73edee7d
commit e9b80d09a1
15 changed files with 369 additions and 240 deletions

View File

@ -61,7 +61,7 @@ public abstract class AbstractFilter {
* *
* @throws DiscoveryException * @throws DiscoveryException
*/ */
public List<ResultFile> applyAlternateFilter(List<ResultFile> currentResults, SleuthkitCase caseDb, public List<Result> applyAlternateFilter(List<Result> currentResults, SleuthkitCase caseDb,
CentralRepository centralRepoDb) throws DiscoveryException { CentralRepository centralRepoDb) throws DiscoveryException {
return new ArrayList<>(); return new ArrayList<>();
} }

View File

@ -52,19 +52,19 @@ public class DiscoveryAttributes {
* *
* @return the key for the group this file goes in * @return the key for the group this file goes in
*/ */
public abstract DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file); public abstract DiscoveryKeyUtils.GroupKey getGroupKey(Result file);
/** /**
* Add any extra data to the ResultFile object from this attribute. * Add any extra data to the ResultFile object from this attribute.
* *
* @param files The list of files to enhance * @param files The list of results to enhance
* @param caseDb The case database * @param caseDb The case database
* @param centralRepoDb The central repository database. Can be null if * @param centralRepoDb The central repository database. Can be null if
* not needed. * not needed.
* *
* @throws DiscoveryException * @throws DiscoveryException
*/ */
public void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { public void addAttributeToResultFiles(List<Result> results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException {
// Default is to do nothing // Default is to do nothing
} }
} }
@ -75,8 +75,8 @@ public class DiscoveryAttributes {
public static class FileSizeAttribute extends AttributeType { public static class FileSizeAttribute extends AttributeType {
@Override @Override
public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) {
return new DiscoveryKeyUtils.FileSizeGroupKey(file); return new DiscoveryKeyUtils.FileSizeGroupKey((ResultFile) file);
} }
} }
@ -86,8 +86,8 @@ public class DiscoveryAttributes {
public static class ParentPathAttribute extends AttributeType { public static class ParentPathAttribute extends AttributeType {
@Override @Override
public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) {
return new DiscoveryKeyUtils.ParentPathGroupKey(file); return new DiscoveryKeyUtils.ParentPathGroupKey((ResultFile) file);
} }
} }
@ -97,7 +97,7 @@ public class DiscoveryAttributes {
static class NoGroupingAttribute extends AttributeType { static class NoGroupingAttribute extends AttributeType {
@Override @Override
public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { public DiscoveryKeyUtils.GroupKey getGroupKey(Result result) {
return new DiscoveryKeyUtils.NoGroupingGroupKey(); return new DiscoveryKeyUtils.NoGroupingGroupKey();
} }
} }
@ -108,8 +108,8 @@ public class DiscoveryAttributes {
static class DataSourceAttribute extends AttributeType { static class DataSourceAttribute extends AttributeType {
@Override @Override
public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { public DiscoveryKeyUtils.GroupKey getGroupKey(Result result) {
return new DiscoveryKeyUtils.DataSourceGroupKey(file); return new DiscoveryKeyUtils.DataSourceGroupKey(result);
} }
} }
@ -119,7 +119,7 @@ public class DiscoveryAttributes {
static class FileTypeAttribute extends AttributeType { static class FileTypeAttribute extends AttributeType {
@Override @Override
public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) {
return new DiscoveryKeyUtils.FileTypeGroupKey(file); return new DiscoveryKeyUtils.FileTypeGroupKey(file);
} }
} }
@ -130,20 +130,20 @@ public class DiscoveryAttributes {
static class KeywordListAttribute extends AttributeType { static class KeywordListAttribute extends AttributeType {
@Override @Override
public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) {
return new DiscoveryKeyUtils.KeywordListGroupKey(file); return new DiscoveryKeyUtils.KeywordListGroupKey((ResultFile) file);
} }
@Override @Override
public void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb, public void addAttributeToResultFiles(List<Result> results, SleuthkitCase caseDb,
CentralRepository centralRepoDb) throws DiscoveryException { CentralRepository centralRepoDb) throws DiscoveryException {
// Get pairs of (object ID, keyword list name) for all files in the list of files that have // Get pairs of (object ID, keyword list name) for all files in the list of files that have
// keyword list hits. // keyword list hits.
String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(), String selectQuery = createSetNameClause(results, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(),
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID());
SetKeywordListNamesCallback callback = new SetKeywordListNamesCallback(files); SetKeywordListNamesCallback callback = new SetKeywordListNamesCallback(results);
try { try {
caseDb.getCaseDbAccessManager().select(selectQuery, callback); caseDb.getCaseDbAccessManager().select(selectQuery, callback);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
@ -158,14 +158,14 @@ public class DiscoveryAttributes {
*/ */
private static class SetKeywordListNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { private static class SetKeywordListNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
List<ResultFile> resultFiles; List<Result> resultFiles;
/** /**
* Create the callback. * Create the callback.
* *
* @param resultFiles List of files to add keyword list names to * @param resultFiles List of files to add keyword list names to
*/ */
SetKeywordListNamesCallback(List<ResultFile> resultFiles) { SetKeywordListNamesCallback(List<Result> resultFiles) {
this.resultFiles = resultFiles; this.resultFiles = resultFiles;
} }
@ -174,7 +174,11 @@ public class DiscoveryAttributes {
try { try {
// Create a temporary map of object ID to ResultFile // Create a temporary map of object ID to ResultFile
Map<Long, ResultFile> tempMap = new HashMap<>(); Map<Long, ResultFile> tempMap = new HashMap<>();
for (ResultFile file : resultFiles) { for (Result result : resultFiles) {
if (result.getType() == SearchData.Type.DOMAIN) {
break;
}
ResultFile file = (ResultFile) result;
tempMap.put(file.getFirstInstance().getId(), file); tempMap.put(file.getFirstInstance().getId(), file);
} }
@ -204,21 +208,21 @@ public class DiscoveryAttributes {
static final int BATCH_SIZE = 50; // Number of hashes to look up at one time static final int BATCH_SIZE = 50; // Number of hashes to look up at one time
@Override @Override
public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) {
return new DiscoveryKeyUtils.FrequencyGroupKey(file); return new DiscoveryKeyUtils.FrequencyGroupKey(file);
} }
@Override @Override
public void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb, public void addAttributeToResultFiles(List<Result> results, SleuthkitCase caseDb,
CentralRepository centralRepoDb) throws DiscoveryException { CentralRepository centralRepoDb) throws DiscoveryException {
if (centralRepoDb == null) { if (centralRepoDb == null) {
for (ResultFile file : files) { for (Result result : results) {
if (file.getFrequency() == SearchData.Frequency.UNKNOWN && file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { if (result.getFrequency() == SearchData.Frequency.UNKNOWN && result.getKnown() == TskData.FileKnown.KNOWN) {
file.setFrequency(SearchData.Frequency.KNOWN); result.setFrequency(SearchData.Frequency.KNOWN);
} }
} }
} else { } else {
processResultFilesForCR(files, centralRepoDb); processResultFilesForCR(results, centralRepoDb);
} }
} }
@ -230,20 +234,23 @@ public class DiscoveryAttributes {
* for. * for.
* @param centralRepoDb The central repository currently in use. * @param centralRepoDb The central repository currently in use.
*/ */
private void processResultFilesForCR(List<ResultFile> files, private void processResultFilesForCR(List<Result> results,
CentralRepository centralRepoDb) { CentralRepository centralRepoDb) {
List<ResultFile> currentFiles = new ArrayList<>(); List<ResultFile> currentFiles = new ArrayList<>();
Set<String> hashesToLookUp = new HashSet<>(); Set<String> hashesToLookUp = new HashSet<>();
for (ResultFile file : files) { for (Result result : results) {
if (file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { if (result.getKnown() == TskData.FileKnown.KNOWN) {
file.setFrequency(SearchData.Frequency.KNOWN); result.setFrequency(SearchData.Frequency.KNOWN);
} }
if (result.getType() != SearchData.Type.DOMAIN) {
ResultFile file = (ResultFile) result;
if (file.getFrequency() == SearchData.Frequency.UNKNOWN if (file.getFrequency() == SearchData.Frequency.UNKNOWN
&& file.getFirstInstance().getMd5Hash() != null && file.getFirstInstance().getMd5Hash() != null
&& !file.getFirstInstance().getMd5Hash().isEmpty()) { && !file.getFirstInstance().getMd5Hash().isEmpty()) {
hashesToLookUp.add(file.getFirstInstance().getMd5Hash()); hashesToLookUp.add(file.getFirstInstance().getMd5Hash());
currentFiles.add(file); currentFiles.add(file);
} }
}
if (hashesToLookUp.size() >= BATCH_SIZE) { if (hashesToLookUp.size() >= BATCH_SIZE) {
computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); computeFrequency(hashesToLookUp, currentFiles, centralRepoDb);
@ -299,20 +306,23 @@ public class DiscoveryAttributes {
static class HashHitsAttribute extends AttributeType { static class HashHitsAttribute extends AttributeType {
@Override @Override
public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { public DiscoveryKeyUtils.GroupKey getGroupKey(Result result) {
return new DiscoveryKeyUtils.HashHitsGroupKey(file); if (result.getType() == SearchData.Type.DOMAIN) {
return null;
}
return new DiscoveryKeyUtils.HashHitsGroupKey((ResultFile) result);
} }
@Override @Override
public void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb, public void addAttributeToResultFiles(List<Result> results, SleuthkitCase caseDb,
CentralRepository centralRepoDb) throws DiscoveryException { CentralRepository centralRepoDb) throws DiscoveryException {
// Get pairs of (object ID, hash set name) for all files in the list of files that have // Get pairs of (object ID, hash set name) for all files in the list of files that have
// hash set hits. // hash set hits.
String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(), String selectQuery = createSetNameClause(results, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(),
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID());
HashSetNamesCallback callback = new HashSetNamesCallback(files); HashSetNamesCallback callback = new HashSetNamesCallback(results);
try { try {
caseDb.getCaseDbAccessManager().select(selectQuery, callback); caseDb.getCaseDbAccessManager().select(selectQuery, callback);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
@ -326,15 +336,15 @@ public class DiscoveryAttributes {
*/ */
private static class HashSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { private static class HashSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
List<ResultFile> resultFiles; List<Result> results;
/** /**
* Create the callback. * Create the callback.
* *
* @param resultFiles List of files to add hash set names to * @param resultFiles List of files to add hash set names to
*/ */
HashSetNamesCallback(List<ResultFile> resultFiles) { HashSetNamesCallback(List<Result> results) {
this.resultFiles = resultFiles; this.results = results;
} }
@Override @Override
@ -342,7 +352,11 @@ public class DiscoveryAttributes {
try { try {
// Create a temporary map of object ID to ResultFile // Create a temporary map of object ID to ResultFile
Map<Long, ResultFile> tempMap = new HashMap<>(); Map<Long, ResultFile> tempMap = new HashMap<>();
for (ResultFile file : resultFiles) { for (Result result : results) {
if (result.getType() == SearchData.Type.DOMAIN) {
return;
}
ResultFile file = (ResultFile) result;
tempMap.put(file.getFirstInstance().getId(), file); tempMap.put(file.getFirstInstance().getId(), file);
} }
@ -370,20 +384,20 @@ public class DiscoveryAttributes {
static class InterestingItemAttribute extends AttributeType { static class InterestingItemAttribute extends AttributeType {
@Override @Override
public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) {
return new DiscoveryKeyUtils.InterestingItemGroupKey(file); return new DiscoveryKeyUtils.InterestingItemGroupKey((ResultFile) file);
} }
@Override @Override
public void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb, public void addAttributeToResultFiles(List<Result> results, SleuthkitCase caseDb,
CentralRepository centralRepoDb) throws DiscoveryException { CentralRepository centralRepoDb) throws DiscoveryException {
// Get pairs of (object ID, interesting item set name) for all files in the list of files that have // Get pairs of (object ID, interesting item set name) for all files in the list of files that have
// interesting file set hits. // interesting file set hits.
String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), String selectQuery = createSetNameClause(results, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID());
InterestingFileSetNamesCallback callback = new InterestingFileSetNamesCallback(files); InterestingFileSetNamesCallback callback = new InterestingFileSetNamesCallback(results);
try { try {
caseDb.getCaseDbAccessManager().select(selectQuery, callback); caseDb.getCaseDbAccessManager().select(selectQuery, callback);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
@ -398,7 +412,7 @@ public class DiscoveryAttributes {
*/ */
private static class InterestingFileSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { private static class InterestingFileSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
List<ResultFile> resultFiles; List<Result> results;
/** /**
* Create the callback. * Create the callback.
@ -406,8 +420,8 @@ public class DiscoveryAttributes {
* @param resultFiles List of files to add interesting file set * @param resultFiles List of files to add interesting file set
* names to * names to
*/ */
InterestingFileSetNamesCallback(List<ResultFile> resultFiles) { InterestingFileSetNamesCallback(List<Result> results) {
this.resultFiles = resultFiles; this.results = results;
} }
@Override @Override
@ -415,7 +429,11 @@ public class DiscoveryAttributes {
try { try {
// Create a temporary map of object ID to ResultFile // Create a temporary map of object ID to ResultFile
Map<Long, ResultFile> tempMap = new HashMap<>(); Map<Long, ResultFile> tempMap = new HashMap<>();
for (ResultFile file : resultFiles) { for (Result result : results) {
if (result.getType() == SearchData.Type.DOMAIN) {
return;
}
ResultFile file = (ResultFile) result;
tempMap.put(file.getFirstInstance().getId(), file); tempMap.put(file.getFirstInstance().getId(), file);
} }
@ -443,20 +461,20 @@ public class DiscoveryAttributes {
static class ObjectDetectedAttribute extends AttributeType { static class ObjectDetectedAttribute extends AttributeType {
@Override @Override
public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) {
return new DiscoveryKeyUtils.ObjectDetectedGroupKey(file); return new DiscoveryKeyUtils.ObjectDetectedGroupKey((ResultFile) file);
} }
@Override @Override
public void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb, public void addAttributeToResultFiles(List<Result> results, SleuthkitCase caseDb,
CentralRepository centralRepoDb) throws DiscoveryException { CentralRepository centralRepoDb) throws DiscoveryException {
// Get pairs of (object ID, object type name) for all files in the list of files that have // Get pairs of (object ID, object type name) for all files in the list of files that have
// objects detected // objects detected
String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID(), String selectQuery = createSetNameClause(results, BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID(),
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID()); BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID());
ObjectDetectedNamesCallback callback = new ObjectDetectedNamesCallback(files); ObjectDetectedNamesCallback callback = new ObjectDetectedNamesCallback(results);
try { try {
caseDb.getCaseDbAccessManager().select(selectQuery, callback); caseDb.getCaseDbAccessManager().select(selectQuery, callback);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
@ -471,15 +489,15 @@ public class DiscoveryAttributes {
*/ */
private static class ObjectDetectedNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { private static class ObjectDetectedNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
List<ResultFile> resultFiles; List<Result> results;
/** /**
* Create the callback. * Create the callback.
* *
* @param resultFiles List of files to add object detected names to * @param resultFiles List of files to add object detected names to
*/ */
ObjectDetectedNamesCallback(List<ResultFile> resultFiles) { ObjectDetectedNamesCallback(List<Result> results) {
this.resultFiles = resultFiles; this.results = results;
} }
@Override @Override
@ -487,7 +505,11 @@ public class DiscoveryAttributes {
try { try {
// Create a temporary map of object ID to ResultFile // Create a temporary map of object ID to ResultFile
Map<Long, ResultFile> tempMap = new HashMap<>(); Map<Long, ResultFile> tempMap = new HashMap<>();
for (ResultFile file : resultFiles) { for (Result result : results) {
if (result.getType() == SearchData.Type.DOMAIN) {
return;
}
ResultFile file = (ResultFile) result;
tempMap.put(file.getFirstInstance().getId(), file); tempMap.put(file.getFirstInstance().getId(), file);
} }
@ -515,20 +537,24 @@ public class DiscoveryAttributes {
static class FileTagAttribute extends AttributeType { static class FileTagAttribute extends AttributeType {
@Override @Override
public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { public DiscoveryKeyUtils.GroupKey getGroupKey(Result file) {
return new DiscoveryKeyUtils.FileTagGroupKey(file); return new DiscoveryKeyUtils.FileTagGroupKey((ResultFile) file);
} }
@Override @Override
public void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb, public void addAttributeToResultFiles(List<Result> results, SleuthkitCase caseDb,
CentralRepository centralRepoDb) throws DiscoveryException { CentralRepository centralRepoDb) throws DiscoveryException {
try { try {
for (ResultFile resultFile : files) { for (Result result : results) {
List<ContentTag> contentTags = caseDb.getContentTagsByContent(resultFile.getFirstInstance()); if (result.getType() == SearchData.Type.DOMAIN) {
return;
}
ResultFile file = (ResultFile) result;
List<ContentTag> contentTags = caseDb.getContentTagsByContent(file.getFirstInstance());
for (ContentTag tag : contentTags) { for (ContentTag tag : contentTags) {
resultFile.addTagName(tag.getName().getDisplayName()); result.addTagName(tag.getName().getDisplayName());
} }
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
@ -625,12 +651,16 @@ public class DiscoveryAttributes {
} }
private static String createSetNameClause(List<ResultFile> files, private static String createSetNameClause(List<Result> results,
int artifactTypeID, int setNameAttrID) throws DiscoveryException { int artifactTypeID, int setNameAttrID) throws DiscoveryException {
// Concatenate the object IDs in the list of files // Concatenate the object IDs in the list of files
String objIdList = ""; // NON-NLS String objIdList = ""; // NON-NLS
for (ResultFile file : files) { for (Result result : results) {
if (result.getType() == SearchData.Type.DOMAIN) {
break;
}
ResultFile file = (ResultFile) result;
if (!objIdList.isEmpty()) { if (!objIdList.isEmpty()) {
objIdList += ","; // NON-NLS objIdList += ","; // NON-NLS
} }
@ -644,7 +674,8 @@ public class DiscoveryAttributes {
+ "INNER JOIN blackboard_attributes ON blackboard_artifacts.artifact_id=blackboard_attributes.artifact_id " + "INNER JOIN blackboard_attributes ON blackboard_artifacts.artifact_id=blackboard_attributes.artifact_id "
+ "WHERE blackboard_attributes.artifact_type_id=\'" + artifactTypeID + "\' " + "WHERE blackboard_attributes.artifact_type_id=\'" + artifactTypeID + "\' "
+ "AND blackboard_attributes.attribute_type_id=\'" + setNameAttrID + "\' " + "AND blackboard_attributes.attribute_type_id=\'" + setNameAttrID + "\' "
+ "AND blackboard_artifacts.obj_id IN (" + objIdList + ") "; // NON-NLS + "AND blackboard_artifacts.obj_id IN (" + objIdList
+ ") "; // NON-NLS
} }
private DiscoveryAttributes() { private DiscoveryAttributes() {

View File

@ -197,7 +197,7 @@ public final class DiscoveryEventUtils {
*/ */
public static final class PageRetrievedEvent { public static final class PageRetrievedEvent {
private final List<ResultFile> results; private final List<Result> results;
private final int page; private final int page;
private final Type resultType; private final Type resultType;
@ -208,7 +208,7 @@ public final class DiscoveryEventUtils {
* @param page The number of the page which was retrieved. * @param page The number of the page which was retrieved.
* @param results The list of files in the page retrieved. * @param results The list of files in the page retrieved.
*/ */
public PageRetrievedEvent(Type resultType, int page, List<ResultFile> results) { public PageRetrievedEvent(Type resultType, int page, List<Result> results) {
this.results = results; this.results = results;
this.page = page; this.page = page;
this.resultType = resultType; this.resultType = resultType;
@ -219,7 +219,7 @@ public final class DiscoveryEventUtils {
* *
* @return The list of files in the page retrieved. * @return The list of files in the page retrieved.
*/ */
public List<ResultFile> getSearchResults() { public List<Result> getSearchResults() {
return Collections.unmodifiableList(results); return Collections.unmodifiableList(results);
} }

View File

@ -155,11 +155,12 @@ public class DiscoveryKeyUtils {
private final SearchData.FileSize fileSize; private final SearchData.FileSize fileSize;
FileSizeGroupKey(ResultFile file) { FileSizeGroupKey(Result file) {
if (file.getFileType() == SearchData.Type.VIDEO) { ResultFile resultFile = (ResultFile) file;
fileSize = SearchData.FileSize.fromVideoSize(file.getFirstInstance().getSize()); if (resultFile.getFileType() == SearchData.Type.VIDEO) {
fileSize = SearchData.FileSize.fromVideoSize(resultFile.getFirstInstance().getSize());
} else { } else {
fileSize = SearchData.FileSize.fromImageSize(file.getFirstInstance().getSize()); fileSize = SearchData.FileSize.fromImageSize(resultFile.getFirstInstance().getSize());
} }
} }
@ -212,8 +213,8 @@ public class DiscoveryKeyUtils {
private final SearchData.Type fileType; private final SearchData.Type fileType;
FileTypeGroupKey(ResultFile file) { FileTypeGroupKey(Result file) {
fileType = file.getFileType(); fileType = ((ResultFile) file).getFileType();
} }
@Override @Override
@ -539,19 +540,19 @@ public class DiscoveryKeyUtils {
@NbBundle.Messages({ @NbBundle.Messages({
"# {0} - Data source name", "# {0} - Data source name",
"# {1} - Data source ID", "# {1} - Data source ID",
"FileSearch.DataSourceGroupKey.datasourceAndID={0}(ID: {1})", "DiscoveryKeyUtils.DataSourceGroupKey.datasourceAndID={0}(ID: {1})",
"# {0} - Data source ID", "# {0} - Data source ID",
"FileSearch.DataSourceGroupKey.idOnly=Data source (ID: {0})"}) "DiscoveryKeyUtils.DataSourceGroupKey.idOnly=Data source (ID: {0})"})
DataSourceGroupKey(ResultFile file) { DataSourceGroupKey(Result result) {
dataSourceID = file.getFirstInstance().getDataSourceObjectId(); //get the id first so that it can be used when logging if necessary
dataSourceID = result.getDataSourceObjectId();
try { try {
// The data source should be cached so this won't actually be a database query. // The data source should be cached so this won't actually be a database query.
Content ds = file.getFirstInstance().getDataSource(); Content ds = result.getDataSource();
displayName = Bundle.FileSearch_DataSourceGroupKey_datasourceAndID(ds.getName(), ds.getId()); displayName = Bundle.DiscoveryKeyUtils_DataSourceGroupKey_datasourceAndID(ds.getName(), ds.getId());
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error looking up data source with ID " + dataSourceID, ex); // NON-NLS logger.log(Level.WARNING, "Error looking up data source with ID " + dataSourceID, ex); // NON-NLS
displayName = Bundle.FileSearch_DataSourceGroupKey_idOnly(dataSourceID); displayName = Bundle.DiscoveryKeyUtils_DataSourceGroupKey_idOnly(dataSourceID);
} }
} }
@ -646,7 +647,7 @@ public class DiscoveryKeyUtils {
private final SearchData.Frequency frequency; private final SearchData.Frequency frequency;
FrequencyGroupKey(ResultFile file) { FrequencyGroupKey(Result file) {
frequency = file.getFrequency(); frequency = file.getFrequency();
} }

View File

@ -45,7 +45,7 @@ public class FileSearch {
private final static Logger logger = Logger.getLogger(FileSearch.class.getName()); private final static Logger logger = Logger.getLogger(FileSearch.class.getName());
private static final int MAXIMUM_CACHE_SIZE = 10; private static final int MAXIMUM_CACHE_SIZE = 10;
private static final Cache<SearchKey, Map<GroupKey, List<ResultFile>>> searchCache = CacheBuilder.newBuilder() private static final Cache<SearchKey, Map<GroupKey, List<Result>>> searchCache = CacheBuilder.newBuilder()
.maximumSize(MAXIMUM_CACHE_SIZE) .maximumSize(MAXIMUM_CACHE_SIZE)
.build(); .build();
@ -82,18 +82,18 @@ public class FileSearch {
attributesNeededForGroupingOrSorting.addAll(fileSortingMethod.getRequiredAttributes()); attributesNeededForGroupingOrSorting.addAll(fileSortingMethod.getRequiredAttributes());
// Run the queries for each filter // Run the queries for each filter
List<ResultFile> resultFiles = SearchFiltering.runQueries(filters, caseDb, centralRepoDb); List<Result> results = SearchFiltering.runQueries(filters, caseDb, centralRepoDb);
// Add the data to resultFiles for any attributes needed for sorting and grouping // Add the data to resultFiles for any attributes needed for sorting and grouping
addAttributes(attributesNeededForGroupingOrSorting, resultFiles, caseDb, centralRepoDb); addAttributes(attributesNeededForGroupingOrSorting, results, caseDb, centralRepoDb);
// Collect everything in the search results // Collect everything in the search results
SearchResults searchResults = new SearchResults(groupSortingType, groupAttributeType, fileSortingMethod); SearchResults searchResults = new SearchResults(groupSortingType, groupAttributeType, fileSortingMethod);
searchResults.add(resultFiles); searchResults.add(results);
// Sort and group the results // Sort and group the results
searchResults.sortGroupsAndFiles(); searchResults.sortGroupsAndFiles();
Map<GroupKey, List<ResultFile>> resultHashMap = searchResults.toLinkedHashMap(); Map<GroupKey, List<Result>> resultHashMap = searchResults.toLinkedHashMap();
SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod); SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod);
synchronized (searchCache) { synchronized (searchCache) {
searchCache.put(searchKey, resultHashMap); searchCache.put(searchKey, resultHashMap);
@ -125,7 +125,7 @@ public class FileSearch {
Group.GroupSortingAlgorithm groupSortingType, Group.GroupSortingAlgorithm groupSortingType,
FileSorter.SortingMethod fileSortingMethod, FileSorter.SortingMethod fileSortingMethod,
SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException {
Map<GroupKey, List<ResultFile>> searchResults = runFileSearch(userName, filters, Map<GroupKey, List<Result>> searchResults = runFileSearch(userName, filters,
groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb); groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb);
LinkedHashMap<GroupKey, Integer> groupSizes = new LinkedHashMap<>(); LinkedHashMap<GroupKey, Integer> groupSizes = new LinkedHashMap<>();
for (GroupKey groupKey : searchResults.keySet()) { for (GroupKey groupKey : searchResults.keySet()) {
@ -156,7 +156,7 @@ public class FileSearch {
* *
* @throws DiscoveryException * @throws DiscoveryException
*/ */
public static List<ResultFile> getFilesInGroup(String userName, public static List<Result> getFilesInGroup(String userName,
List<AbstractFilter> filters, List<AbstractFilter> filters,
AttributeType groupAttributeType, AttributeType groupAttributeType,
Group.GroupSortingAlgorithm groupSortingType, Group.GroupSortingAlgorithm groupSortingType,
@ -166,16 +166,16 @@ public class FileSearch {
int numberOfEntries, int numberOfEntries,
SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException {
//the group should be in the cache at this point //the group should be in the cache at this point
List<ResultFile> filesInGroup = null; List<Result> filesInGroup = null;
SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod); SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod);
Map<GroupKey, List<ResultFile>> resultsMap; Map<GroupKey, List<Result>> resultsMap;
synchronized (searchCache) { synchronized (searchCache) {
resultsMap = searchCache.getIfPresent(searchKey); resultsMap = searchCache.getIfPresent(searchKey);
} }
if (resultsMap != null) { if (resultsMap != null) {
filesInGroup = resultsMap.get(groupKey); filesInGroup = resultsMap.get(groupKey);
} }
List<ResultFile> page = new ArrayList<>(); List<Result> page = new ArrayList<>();
if (filesInGroup == null) { if (filesInGroup == null) {
logger.log(Level.INFO, "Group {0} was not cached, performing search to cache all groups again", groupKey); logger.log(Level.INFO, "Group {0} was not cached, performing search to cache all groups again", groupKey);
runFileSearch(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb); runFileSearch(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb);
@ -252,7 +252,7 @@ public class FileSearch {
* *
* @throws DiscoveryException * @throws DiscoveryException
*/ */
private static Map<GroupKey, List<ResultFile>> runFileSearch(String userName, private static Map<GroupKey, List<Result>> runFileSearch(String userName,
List<AbstractFilter> filters, List<AbstractFilter> filters,
AttributeType groupAttributeType, AttributeType groupAttributeType,
Group.GroupSortingAlgorithm groupSortingType, Group.GroupSortingAlgorithm groupSortingType,
@ -268,15 +268,15 @@ public class FileSearch {
attributesNeededForGroupingOrSorting.addAll(fileSortingMethod.getRequiredAttributes()); attributesNeededForGroupingOrSorting.addAll(fileSortingMethod.getRequiredAttributes());
// Run the queries for each filter // Run the queries for each filter
List<ResultFile> resultFiles = SearchFiltering.runQueries(filters, caseDb, centralRepoDb); List<Result> results = SearchFiltering.runQueries(filters, caseDb, centralRepoDb);
// Add the data to resultFiles for any attributes needed for sorting and grouping // Add the data to resultFiles for any attributes needed for sorting and grouping
addAttributes(attributesNeededForGroupingOrSorting, resultFiles, caseDb, centralRepoDb); addAttributes(attributesNeededForGroupingOrSorting, results, caseDb, centralRepoDb);
// Collect everything in the search results // Collect everything in the search results
SearchResults searchResults = new SearchResults(groupSortingType, groupAttributeType, fileSortingMethod); SearchResults searchResults = new SearchResults(groupSortingType, groupAttributeType, fileSortingMethod);
searchResults.add(resultFiles); searchResults.add(results);
Map<GroupKey, List<ResultFile>> resultHashMap = searchResults.toLinkedHashMap(); Map<GroupKey, List<Result>> resultHashMap = searchResults.toLinkedHashMap();
SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod); SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod);
synchronized (searchCache) { synchronized (searchCache) {
searchCache.put(searchKey, resultHashMap); searchCache.put(searchKey, resultHashMap);
@ -298,10 +298,10 @@ public class FileSearch {
* *
* @throws DiscoveryException * @throws DiscoveryException
*/ */
private static void addAttributes(List<AttributeType> attrs, List<ResultFile> resultFiles, SleuthkitCase caseDb, CentralRepository centralRepoDb) private static void addAttributes(List<AttributeType> attrs, List<Result> results, SleuthkitCase caseDb, CentralRepository centralRepoDb)
throws DiscoveryException { throws DiscoveryException {
for (AttributeType attr : attrs) { for (AttributeType attr : attrs) {
attr.addAttributeToResultFiles(resultFiles, caseDb, centralRepoDb); attr.addAttributeToResultFiles(results, caseDb, centralRepoDb);
} }
} }

View File

@ -29,9 +29,9 @@ import org.sleuthkit.datamodel.TskCoreException;
/** /**
* Class used to sort ResultFiles using the supplied method. * Class used to sort ResultFiles using the supplied method.
*/ */
public class FileSorter implements Comparator<ResultFile> { public class FileSorter implements Comparator<Result> {
private final List<Comparator<ResultFile>> comparators = new ArrayList<>(); private final List<Comparator<Result>> comparators = new ArrayList<>();
/** /**
* Set up the sorter using the supplied sorting method. The sorting is * Set up the sorter using the supplied sorting method. The sorting is
@ -51,7 +51,7 @@ public class FileSorter implements Comparator<ResultFile> {
comparators.add(getFileSizeComparator()); comparators.add(getFileSizeComparator());
break; break;
case BY_FILE_TYPE: case BY_FILE_TYPE:
comparators.add(getFileTypeComparator()); comparators.add(getTypeComparator());
comparators.add(getMIMETypeComparator()); comparators.add(getMIMETypeComparator());
break; break;
case BY_FREQUENCY: case BY_FREQUENCY:
@ -77,11 +77,11 @@ public class FileSorter implements Comparator<ResultFile> {
} }
@Override @Override
public int compare(ResultFile file1, ResultFile file2) { public int compare(Result result1, Result result2) {
int result = 0; int result = 0;
for (Comparator<ResultFile> comp : comparators) { for (Comparator<Result> comp : comparators) {
result = comp.compare(file1, file2); result = comp.compare(result1, result2);
if (result != 0) { if (result != 0) {
return result; return result;
} }
@ -96,8 +96,8 @@ public class FileSorter implements Comparator<ResultFile> {
* *
* @return -1 if file1 has the lower data source ID, 0 if equal, 1 otherwise * @return -1 if file1 has the lower data source ID, 0 if equal, 1 otherwise
*/ */
private static Comparator<ResultFile> getDataSourceComparator() { private static Comparator<Result> getDataSourceComparator() {
return (ResultFile file1, ResultFile file2) -> Long.compare(file1.getFirstInstance().getDataSourceObjectId(), file2.getFirstInstance().getDataSourceObjectId()); return (Result result1, Result result2) -> Long.compare(result1.getDataSourceObjectId(), result2.getDataSourceObjectId());
} }
/** /**
@ -106,8 +106,8 @@ public class FileSorter implements Comparator<ResultFile> {
* *
* @return -1 if file1 has the lower FileType value, 0 if equal, 1 otherwise * @return -1 if file1 has the lower FileType value, 0 if equal, 1 otherwise
*/ */
private static Comparator<ResultFile> getFileTypeComparator() { private static Comparator<Result> getTypeComparator() {
return (ResultFile file1, ResultFile file2) -> Integer.compare(file1.getFileType().getRanking(), file2.getFileType().getRanking()); return (Result result1, Result result2) -> Integer.compare(result1.getType().getRanking(), result2.getType().getRanking());
} }
/** /**
@ -118,9 +118,14 @@ public class FileSorter implements Comparator<ResultFile> {
* @return -1 if file1 has the earliest combined keyword list name, 0 if * @return -1 if file1 has the earliest combined keyword list name, 0 if
* equal, 1 otherwise * equal, 1 otherwise
*/ */
private static Comparator<ResultFile> getKeywordListNameComparator() { private static Comparator<Result> getKeywordListNameComparator() {
return (ResultFile file1, ResultFile file2) -> { return (Result result1, Result result2) -> {
// Put empty lists at the bottom // Put empty lists at the bottom
if (result1.getType() == SearchData.Type.DOMAIN) {
return 0;
}
ResultFile file1 = (ResultFile) result1;
ResultFile file2 = (ResultFile) result2;
if (file1.getKeywordListNames().isEmpty()) { if (file1.getKeywordListNames().isEmpty()) {
if (file2.getKeywordListNames().isEmpty()) { if (file2.getKeywordListNames().isEmpty()) {
return 0; return 0;
@ -142,11 +147,16 @@ public class FileSorter implements Comparator<ResultFile> {
* @return -1 if file1's path comes first alphabetically, 0 if equal, 1 * @return -1 if file1's path comes first alphabetically, 0 if equal, 1
* otherwise * otherwise
*/ */
private static Comparator<ResultFile> getParentPathComparator() { private static Comparator<Result> getParentPathComparator() {
return new Comparator<ResultFile>() { return new Comparator<Result>() {
@Override @Override
public int compare(ResultFile file1, ResultFile file2) { public int compare(Result result1, Result result2) {
if (result1.getType() == SearchData.Type.DOMAIN) {
return 0;
}
ResultFile file1 = (ResultFile) result1;
ResultFile file2 = (ResultFile) result2;
String file1ParentPath; String file1ParentPath;
try { try {
file1ParentPath = file1.getFirstInstance().getParent().getUniquePath(); file1ParentPath = file1.getFirstInstance().getParent().getUniquePath();
@ -170,8 +180,8 @@ public class FileSorter implements Comparator<ResultFile> {
* *
* @return -1 if file1's rarity is lower than file2, 0 if equal, 1 otherwise * @return -1 if file1's rarity is lower than file2, 0 if equal, 1 otherwise
*/ */
private static Comparator<ResultFile> getFrequencyComparator() { private static Comparator<Result> getFrequencyComparator() {
return (ResultFile file1, ResultFile file2) -> Integer.compare(file1.getFrequency().getRanking(), file2.getFrequency().getRanking()); return (Result result1, Result result2) -> Integer.compare(result1.getFrequency().getRanking(), result2.getFrequency().getRanking());
} }
/** /**
@ -180,8 +190,13 @@ public class FileSorter implements Comparator<ResultFile> {
* @return -1 if file1's MIME type comes before file2's, 0 if equal, 1 * @return -1 if file1's MIME type comes before file2's, 0 if equal, 1
* otherwise * otherwise
*/ */
private static Comparator<ResultFile> getMIMETypeComparator() { private static Comparator<Result> getMIMETypeComparator() {
return (ResultFile file1, ResultFile file2) -> compareStrings(file1.getFirstInstance().getMIMEType(), file2.getFirstInstance().getMIMEType()); return (Result result1, Result result2) -> {
if (result1.getType() == SearchData.Type.DOMAIN) {
return 0;
}
return compareStrings(((ResultFile) result1).getFirstInstance().getMIMEType(), ((ResultFile) result2).getFirstInstance().getMIMEType());
};
} }
/** /**
@ -189,9 +204,13 @@ public class FileSorter implements Comparator<ResultFile> {
* *
* @return -1 if file1 is larger than file2, 0 if equal, 1 otherwise * @return -1 if file1 is larger than file2, 0 if equal, 1 otherwise
*/ */
private static Comparator<ResultFile> getFileSizeComparator() { private static Comparator<Result> getFileSizeComparator() {
return (ResultFile file1, ResultFile file2) -> -1 * Long.compare(file1.getFirstInstance().getSize(), file2.getFirstInstance().getSize()) // Sort large to small return (Result result1, Result result2) -> {
; if (result1.getType() == SearchData.Type.DOMAIN) {
return 0;
}
return -1 * Long.compare(((ResultFile) result1).getFirstInstance().getSize(), ((ResultFile) result2).getFirstInstance().getSize()); // Sort large to small
};
} }
/** /**
@ -199,8 +218,13 @@ public class FileSorter implements Comparator<ResultFile> {
* *
* @return -1 if file1 comes before file2, 0 if equal, 1 otherwise * @return -1 if file1 comes before file2, 0 if equal, 1 otherwise
*/ */
private static Comparator<ResultFile> getFileNameComparator() { private static Comparator<Result> getFileNameComparator() {
return (ResultFile file1, ResultFile file2) -> compareStrings(file1.getFirstInstance().getName().toLowerCase(), file2.getFirstInstance().getName().toLowerCase()); return (Result result1, Result result2) -> {
if (result1.getType() == SearchData.Type.DOMAIN) {
return 0;
}
return compareStrings(((ResultFile) result1).getFirstInstance().getName().toLowerCase(), (((ResultFile) result2).getFirstInstance().getName().toLowerCase()));
};
} }
/** /**
@ -211,14 +235,21 @@ public class FileSorter implements Comparator<ResultFile> {
* *
* @return -1 if file1 comes before file2, 0 if equal, 1 otherwise * @return -1 if file1 comes before file2, 0 if equal, 1 otherwise
*/ */
private static Comparator<ResultFile> getDefaultComparator() { private static Comparator<Result> getDefaultComparator() {
return (ResultFile file1, ResultFile file2) -> { return (Result result1, Result result2) -> {
// Compare file names and then object ID (to ensure a consistent sort) // Compare file names and then object ID (to ensure a consistent sort)
if (result1.getType() == SearchData.Type.DOMAIN) {
return getFrequencyComparator().compare(result1, result2);
} else {
ResultFile file1 = (ResultFile) result1;
ResultFile file2 = (ResultFile) result2;
int result = getFileNameComparator().compare(file1, file2); int result = getFileNameComparator().compare(file1, file2);
if (result == 0) { if (result == 0) {
return Long.compare(file1.getFirstInstance().getId(), file2.getFirstInstance().getId()); return Long.compare(file1.getFirstInstance().getId(), file2.getFirstInstance().getId());
} }
return result; return result;
}
}; };
} }
@ -234,6 +265,7 @@ public class FileSorter implements Comparator<ResultFile> {
String string1 = s1 == null ? "" : s1; String string1 = s1 == null ? "" : s1;
String string2 = s2 == null ? "" : s2; String string2 = s2 == null ? "" : s2;
return string1.compareTo(string2); return string1.compareTo(string2);
} }
/** /**

View File

@ -30,7 +30,7 @@ public class Group implements Comparable<Group> {
private final Group.GroupSortingAlgorithm groupSortingType; private final Group.GroupSortingAlgorithm groupSortingType;
private final DiscoveryKeyUtils.GroupKey groupKey; private final DiscoveryKeyUtils.GroupKey groupKey;
private final List<ResultFile> files; private final List<Result> results;
private final String displayName; private final String displayName;
/** /**
@ -42,21 +42,23 @@ public class Group implements Comparable<Group> {
public Group(Group.GroupSortingAlgorithm groupSortingType, DiscoveryKeyUtils.GroupKey groupKey) { public Group(Group.GroupSortingAlgorithm groupSortingType, DiscoveryKeyUtils.GroupKey groupKey) {
this.groupSortingType = groupSortingType; this.groupSortingType = groupSortingType;
this.groupKey = groupKey; this.groupKey = groupKey;
files = new ArrayList<>(); results = new ArrayList<>();
this.displayName = groupKey.getDisplayName(); this.displayName = groupKey.getDisplayName();
} }
/** /**
* Add a ResultFile to the group. Will not be sorted at this time. * Add a Result to the group. Will not be sorted at this time.
* *
* @param file The ResultFile to add to the FileGroup * @param result The Result to add to the FileGroup
*/ */
void addFile(ResultFile file) { void addResult(Result result) {
if (files.contains(file)) { if (result.getType() != SearchData.Type.DOMAIN && results.contains(result)) {
ResultFile existingCopy = files.get(files.indexOf(file)); //get the copy of this which exists in the list //dedupe files and show instances
existingCopy.addDuplicate(file.getFirstInstance()); ResultFile existingCopy = (ResultFile)results.get(results.indexOf(result)); //get the copy of this which exists in the list
existingCopy.addDuplicate(((ResultFile)result).getFirstInstance());
} else { } else {
files.add(file); //Domains and non files are not being deduped currently
results.add(result);
} }
} }
@ -82,7 +84,7 @@ public class Group implements Comparable<Group> {
* Sort all the files in the group * Sort all the files in the group
*/ */
public void sortFiles(FileSorter sorter) { public void sortFiles(FileSorter sorter) {
Collections.sort(files, sorter); Collections.sort(results, sorter);
} }
/** /**
@ -128,8 +130,8 @@ public class Group implements Comparable<Group> {
* @return -1 if group1 should be displayed before group2, 1 otherwise * @return -1 if group1 should be displayed before group2, 1 otherwise
*/ */
private static int compareGroupsBySize(Group group1, Group group2) { private static int compareGroupsBySize(Group group1, Group group2) {
if (group1.getFiles().size() != group2.getFiles().size()) { if (group1.getResults().size() != group2.getResults().size()) {
return -1 * Long.compare(group1.getFiles().size(), group2.getFiles().size()); // High to low return -1 * Long.compare(group1.getResults().size(), group2.getResults().size()); // High to low
} else { } else {
// If the groups have the same size, fall through to the BY_GROUP_NAME sorting // If the groups have the same size, fall through to the BY_GROUP_NAME sorting
return compareGroupsByGroupKey(group1, group2); return compareGroupsByGroupKey(group1, group2);
@ -168,8 +170,8 @@ public class Group implements Comparable<Group> {
* *
* @return List of ResultFile objects * @return List of ResultFile objects
*/ */
public List<ResultFile> getFiles() { public List<Result> getResults() {
return Collections.unmodifiableList(files); return Collections.unmodifiableList(results);
} }
} }

View File

@ -18,9 +18,67 @@
*/ */
package org.sleuthkit.autopsy.discovery.search; package org.sleuthkit.autopsy.discovery.search;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/** /**
* Interface implemented by all types of results. * Interface implemented by all types of results.
*/ */
public interface Result { public abstract class Result {
private SearchData.Frequency frequency;
private final List<String> tagNames = new ArrayList<>();
public abstract long getDataSourceObjectId();
/**
* Get the frequency of this result in the central repository.
*
* @return The Frequency enum.
*/
public SearchData.Frequency getFrequency() {
return frequency;
}
public abstract TskData.FileKnown getKnown();
/**
* Set the frequency of this result in the central repository.
*
* @param frequency The frequency of the result as an enum.
*/
final public void setFrequency(SearchData.Frequency frequency) {
this.frequency = frequency;
}
public abstract Content getDataSource() throws TskCoreException;
public abstract SearchData.Type getType();
/**
* Add a tag name that matched this file.
*
* @param tagName
*/
public void addTagName(String tagName) {
if (!tagNames.contains(tagName)) {
tagNames.add(tagName);
}
// Sort the list so the getTagNames() will be consistent regardless of the order added
Collections.sort(tagNames);
}
/**
* Get the tag names for this file
*
* @return the tag names that matched this file.
*/
public List<String> getTagNames() {
return Collections.unmodifiableList(tagNames);
}
} }

View File

@ -18,7 +18,34 @@
*/ */
package org.sleuthkit.autopsy.discovery.search; package org.sleuthkit.autopsy.discovery.search;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
public class ResultDomain implements Result { public class ResultDomain extends Result {
ResultDomain() {
this.setFrequency(SearchData.Frequency.UNKNOWN);
}
@Override
public long getDataSourceObjectId() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public Content getDataSource() throws TskCoreException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public TskData.FileKnown getKnown() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public SearchData.Type getType() {
return SearchData.Type.DOMAIN;
}
} }

View File

@ -31,6 +31,7 @@ import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import static org.sleuthkit.autopsy.discovery.search.SearchData.Type.OTHER; import static org.sleuthkit.autopsy.discovery.search.SearchData.Type.OTHER;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.HashUtility;
import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.Tag;
@ -40,13 +41,11 @@ import org.sleuthkit.datamodel.TskData;
/** /**
* Container for files that holds all necessary data for grouping and sorting. * Container for files that holds all necessary data for grouping and sorting.
*/ */
public class ResultFile implements Result{ public class ResultFile extends Result {
private final static Logger logger = Logger.getLogger(ResultFile.class.getName()); private final static Logger logger = Logger.getLogger(ResultFile.class.getName());
private SearchData.Frequency frequency;
private final List<String> keywordListNames; private final List<String> keywordListNames;
private final List<String> hashSetNames; private final List<String> hashSetNames;
private final List<String> tagNames;
private final List<String> interestingSetNames; private final List<String> interestingSetNames;
private final List<String> objectDetectedNames; private final List<String> objectDetectedNames;
private final List<AbstractFile> instances = new ArrayList<>(); private final List<AbstractFile> instances = new ArrayList<>();
@ -73,33 +72,13 @@ public class ResultFile implements Result{
deleted = true; deleted = true;
} }
updateScoreAndDescription(abstractFile); updateScoreAndDescription(abstractFile);
this.frequency = SearchData.Frequency.UNKNOWN;
keywordListNames = new ArrayList<>(); keywordListNames = new ArrayList<>();
hashSetNames = new ArrayList<>(); hashSetNames = new ArrayList<>();
tagNames = new ArrayList<>();
interestingSetNames = new ArrayList<>(); interestingSetNames = new ArrayList<>();
objectDetectedNames = new ArrayList<>(); objectDetectedNames = new ArrayList<>();
fileType = fromMIMEtype(abstractFile.getMIMEType()); fileType = fromMIMEtype(abstractFile.getMIMEType());
} }
/**
* Get the frequency of this file in the central repository
*
* @return The Frequency enum
*/
public SearchData.Frequency getFrequency() {
return frequency;
}
/**
* Set the frequency of this file from the central repository
*
* @param frequency The frequency of the file as an enum
*/
public void setFrequency(SearchData.Frequency frequency) {
this.frequency = frequency;
}
/** /**
* Add an AbstractFile to the list of files which are instances of this * Add an AbstractFile to the list of files which are instances of this
* file. * file.
@ -218,29 +197,6 @@ public class ResultFile implements Result{
return Collections.unmodifiableList(hashSetNames); return Collections.unmodifiableList(hashSetNames);
} }
/**
* Add a tag name that matched this file.
*
* @param tagName
*/
public void addTagName(String tagName) {
if (!tagNames.contains(tagName)) {
tagNames.add(tagName);
}
// Sort the list so the getTagNames() will be consistent regardless of the order added
Collections.sort(tagNames);
}
/**
* Get the tag names for this file
*
* @return the tag names that matched this file.
*/
public List<String> getTagNames() {
return Collections.unmodifiableList(tagNames);
}
/** /**
* Add an interesting file set name that matched this file. * Add an interesting file set name that matched this file.
* *
@ -300,7 +256,7 @@ public class ResultFile implements Result{
public String toString() { public String toString() {
return getFirstInstance().getName() + "(" + getFirstInstance().getId() + ") - " return getFirstInstance().getName() + "(" + getFirstInstance().getId() + ") - "
+ getFirstInstance().getSize() + ", " + getFirstInstance().getParentPath() + ", " + getFirstInstance().getSize() + ", " + getFirstInstance().getParentPath() + ", "
+ getFirstInstance().getDataSourceObjectId() + ", " + frequency.toString() + ", " + getFirstInstance().getDataSourceObjectId() + ", " + getFrequency().toString() + ", "
+ String.join(",", keywordListNames) + ", " + getFirstInstance().getMIMEType(); + String.join(",", keywordListNames) + ", " + getFirstInstance().getMIMEType();
} }
@ -397,4 +353,24 @@ public class ResultFile implements Result{
} }
return OTHER; return OTHER;
} }
@Override
public long getDataSourceObjectId() {
return getFirstInstance().getDataSourceObjectId();
}
@Override
public Content getDataSource() throws TskCoreException {
return getFirstInstance().getDataSource();
}
@Override
public TskData.FileKnown getKnown() {
return getFirstInstance().getKnown();
}
@Override
public Type getType() {
return fileType;
}
} }

View File

@ -54,7 +54,7 @@ public class SearchFiltering {
* *
* @return * @return
*/ */
static List<ResultFile> runQueries(List<AbstractFilter> filters, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { static List<Result> runQueries(List<AbstractFilter> filters, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException {
if (caseDb == null) { if (caseDb == null) {
throw new DiscoveryException("Case DB parameter is null"); // NON-NLS throw new DiscoveryException("Case DB parameter is null"); // NON-NLS
} }
@ -94,9 +94,9 @@ public class SearchFiltering {
* @throws TskCoreException * @throws TskCoreException
* @throws DiscoveryException * @throws DiscoveryException
*/ */
private static List<ResultFile> getResultList(List<AbstractFilter> filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws TskCoreException, DiscoveryException { private static List<Result> getResultList(List<AbstractFilter> filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws TskCoreException, DiscoveryException {
// Get all matching abstract files // Get all matching abstract files
List<ResultFile> resultList = new ArrayList<>(); List<Result> resultList = new ArrayList<>();
List<AbstractFile> sqlResults = caseDb.findAllFilesWhere(combinedQuery); List<AbstractFile> sqlResults = caseDb.findAllFilesWhere(combinedQuery);
// If there are no results, return now // If there are no results, return now
@ -514,7 +514,7 @@ public class SearchFiltering {
} }
@Override @Override
public List<ResultFile> applyAlternateFilter(List<ResultFile> currentResults, SleuthkitCase caseDb, public List<Result> applyAlternateFilter(List<Result> currentResults, SleuthkitCase caseDb,
CentralRepository centralRepoDb) throws DiscoveryException { CentralRepository centralRepoDb) throws DiscoveryException {
// We have to have run some kind of SQL filter before getting to this point, // We have to have run some kind of SQL filter before getting to this point,
@ -528,8 +528,8 @@ public class SearchFiltering {
freqAttr.addAttributeToResultFiles(currentResults, caseDb, centralRepoDb); freqAttr.addAttributeToResultFiles(currentResults, caseDb, centralRepoDb);
// If the frequency matches the filter, add the file to the results // If the frequency matches the filter, add the file to the results
List<ResultFile> frequencyResults = new ArrayList<>(); List<Result> frequencyResults = new ArrayList<>();
for (ResultFile file : currentResults) { for (Result file : currentResults) {
if (frequencies.contains(file.getFrequency())) { if (frequencies.contains(file.getFrequency())) {
frequencyResults.add(file); frequencyResults.add(file);
} }
@ -834,7 +834,7 @@ public class SearchFiltering {
} }
@Override @Override
public List<ResultFile> applyAlternateFilter(List<ResultFile> currentResults, SleuthkitCase caseDb, public List<Result> applyAlternateFilter(List<Result> currentResults, SleuthkitCase caseDb,
CentralRepository centralRepoDb) throws DiscoveryException { CentralRepository centralRepoDb) throws DiscoveryException {
if (centralRepoDb == null) { if (centralRepoDb == null) {
@ -848,18 +848,21 @@ public class SearchFiltering {
} }
// The matching files // The matching files
List<ResultFile> notableResults = new ArrayList<>(); List<Result> notableResults = new ArrayList<>();
try { try {
CorrelationAttributeInstance.Type type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID); CorrelationAttributeInstance.Type type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID);
for (ResultFile file : currentResults) { for (Result result : currentResults) {
ResultFile file = (ResultFile) result;
if (result.getType() == SearchData.Type.DOMAIN) {
break;
}
if (file.getFirstInstance().getMd5Hash() != null && !file.getFirstInstance().getMd5Hash().isEmpty()) { if (file.getFirstInstance().getMd5Hash() != null && !file.getFirstInstance().getMd5Hash().isEmpty()) {
// Check if this file hash is marked as notable in the CR // Check if this file hash is marked as notable in the CR
String value = file.getFirstInstance().getMd5Hash(); String value = file.getFirstInstance().getMd5Hash();
if (centralRepoDb.getCountArtifactInstancesKnownBad(type, value) > 0) { if (centralRepoDb.getCountArtifactInstancesKnownBad(type, value) > 0) {
notableResults.add(file); notableResults.add(result);
} }
} }
} }

View File

@ -72,15 +72,15 @@ class SearchResults {
* *
* @param files The list of ResultFiles to add. * @param files The list of ResultFiles to add.
*/ */
void add(List<ResultFile> files) { void add(List<Result> results) {
for (ResultFile file : files) { for (Result result : results) {
// Add the file to the appropriate group, creating it if necessary // Add the file to the appropriate group, creating it if necessary
GroupKey groupKey = attrType.getGroupKey(file); GroupKey groupKey = attrType.getGroupKey(result);
if (!groupMap.containsKey(groupKey)) { if (!groupMap.containsKey(groupKey)) {
groupMap.put(groupKey, new Group(groupSortingType, groupKey)); groupMap.put(groupKey, new Group(groupSortingType, groupKey));
} }
groupMap.get(groupKey).addFile(file); groupMap.get(groupKey).addResult(result);
} }
} }
@ -102,25 +102,25 @@ class SearchResults {
@Override @Override
public String toString() { public String toString() {
String result = ""; String resultString = "";
if (groupList == null) { if (groupList == null) {
return result; return resultString;
} }
long count = 0; long count = 0;
for (Group group : groupList) { for (Group group : groupList) {
result += group.getDisplayName() + "\n"; resultString += group.getDisplayName() + "\n";
for (ResultFile file : group.getFiles()) { for (Result result : group.getResults()) {
result += " " + file.toString() + "\n"; resultString += " " + result.toString() + "\n";
count++; count++;
if (count > MAX_OUTPUT_FILES) { if (count > MAX_OUTPUT_FILES) {
result += "(truncated)"; resultString += "(truncated)";
return result; return resultString;
} }
} }
} }
return result; return resultString;
} }
/** /**
@ -129,7 +129,7 @@ class SearchResults {
* @return The list of group names. * @return The list of group names.
*/ */
List<String> getGroupNamesWithCounts() { List<String> getGroupNamesWithCounts() {
return groupList.stream().map(p -> p.getDisplayName() + " (" + p.getFiles().size() + ")").collect(Collectors.toList()); return groupList.stream().map(p -> p.getDisplayName() + " (" + p.getResults().size() + ")").collect(Collectors.toList());
} }
/** /**
@ -139,13 +139,13 @@ class SearchResults {
* *
* @return The list of result files. * @return The list of result files.
*/ */
List<ResultFile> getResultFilesInGroup(String groupName) { List<Result> getResultFilesInGroup(String groupName) {
if (groupName != null) { if (groupName != null) {
final String modifiedGroupName = groupName.replaceAll(" \\([0-9]+\\)$", ""); final String modifiedGroupName = groupName.replaceAll(" \\([0-9]+\\)$", "");
java.util.Optional<Group> fileGroup = groupList.stream().filter(p -> p.getDisplayName().equals(modifiedGroupName)).findFirst(); java.util.Optional<Group> group = groupList.stream().filter(p -> p.getDisplayName().equals(modifiedGroupName)).findFirst();
if (fileGroup.isPresent()) { if (group.isPresent()) {
return fileGroup.get().getFiles(); return group.get().getResults();
} }
} }
return new ArrayList<>(); return new ArrayList<>();
@ -156,15 +156,15 @@ class SearchResults {
* *
* @return The grouped and sorted results. * @return The grouped and sorted results.
*/ */
Map<GroupKey, List<ResultFile>> toLinkedHashMap() throws DiscoveryException { Map<GroupKey, List<Result>> toLinkedHashMap() throws DiscoveryException {
Map<GroupKey, List<ResultFile>> map = new LinkedHashMap<>(); Map<GroupKey, List<Result>> map = new LinkedHashMap<>();
// Sort the groups and files // Sort the groups and files
sortGroupsAndFiles(); sortGroupsAndFiles();
// groupList is sorted and a LinkedHashMap will preserve that order. // groupList is sorted and a LinkedHashMap will preserve that order.
for (Group group : groupList) { for (Group group : groupList) {
map.put(group.getGroupKey(), group.getFiles()); map.put(group.getGroupKey(), group.getResults());
} }
return map; return map;

View File

@ -232,6 +232,7 @@ final class DiscoveryUiUtils {
* Helper method to display an error message when the results of the * Helper method to display an error message when the results of the
* Discovery Top component may be incomplete. * Discovery Top component may be incomplete.
*/ */
@NbBundle.Messages({"DiscoveryUiUtils.resultsIncomplete.text=Discovery results may be incomplete"})
static void displayErrorMessage(DiscoveryDialog dialog) { static void displayErrorMessage(DiscoveryDialog dialog) {
//check if modules run and assemble message //check if modules run and assemble message
try { try {
@ -258,7 +259,7 @@ final class DiscoveryUiUtils {
messageScrollPane.setMaximumSize(new Dimension(600, 100)); messageScrollPane.setMaximumSize(new Dimension(600, 100));
messageScrollPane.setPreferredSize(new Dimension(600, 100)); messageScrollPane.setPreferredSize(new Dimension(600, 100));
messageScrollPane.setViewportView(messageTextPane); messageScrollPane.setViewportView(messageTextPane);
JOptionPane.showMessageDialog(dialog, messageScrollPane, Bundle.OpenDiscoveryAction_resultsIncomplete_text(), JOptionPane.PLAIN_MESSAGE); JOptionPane.showMessageDialog(dialog, messageScrollPane, Bundle.DiscoveryUiUtils_resultsIncomplete_text(), JOptionPane.PLAIN_MESSAGE);
} }
} catch (NoCurrentCaseException | TskCoreException ex) { } catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.WARNING, "Exception while determining which modules have been run for Discovery", ex); logger.log(Level.WARNING, "Exception while determining which modules have been run for Discovery", ex);

View File

@ -62,8 +62,6 @@ public final class OpenDiscoveryAction extends CallableSystemAction implements P
return Case.isCaseOpen(); return Case.isCaseOpen();
} }
@NbBundle.Messages({"OpenDiscoveryAction.resultsIncomplete.text=Discovery results may be incomplete"})
@Override @Override
public void performAction() { public void performAction() {
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {

View File

@ -34,7 +34,7 @@ import org.sleuthkit.autopsy.discovery.search.FileSearch;
import org.sleuthkit.autopsy.discovery.search.SearchData; import org.sleuthkit.autopsy.discovery.search.SearchData;
import org.sleuthkit.autopsy.discovery.search.DiscoveryException; import org.sleuthkit.autopsy.discovery.search.DiscoveryException;
import org.sleuthkit.autopsy.discovery.search.FileSorter; import org.sleuthkit.autopsy.discovery.search.FileSorter;
import org.sleuthkit.autopsy.discovery.search.ResultFile; import org.sleuthkit.autopsy.discovery.search.Result;
/** /**
* SwingWorker to retrieve the contents of a page. * SwingWorker to retrieve the contents of a page.
@ -52,7 +52,7 @@ final class PageWorker extends SwingWorker<Void, Void> {
private final int pageSize; private final int pageSize;
private final SearchData.Type resultType; private final SearchData.Type resultType;
private final CentralRepository centralRepo; private final CentralRepository centralRepo;
private final List<ResultFile> results = new ArrayList<>(); private final List<Result> results = new ArrayList<>();
/** /**
* Construct a new PageWorker. * Construct a new PageWorker.