diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED index 9924fbae02..41cab2b5c2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/Bundle.properties-MERGED @@ -1,5 +1,3 @@ -AttributeSearchData.AttributeType.Domain.displayName=Domain -AttributeSearchData.AttributeType.Other.displayName=Other DiscoveryKeyUtils.FileTagGroupKey.noSets=None DiscoveryKeyUtils.NoGroupingGroupKey.allFiles=All Files FileGroup.groupSortingAlgorithm.groupName.text=Group Name @@ -26,39 +24,6 @@ FileSearch.HashHitsGroupKey.noHashHits=None FileSearch.InterestingItemGroupKey.noSets=None FileSearch.KeywordListGroupKey.noKeywords=None FileSearch.ObjectDetectedGroupKey.noSets=None -FileSearchData.FileSize.100kbto1mb=: 100KB-1MB -FileSearchData.FileSize.100mbto1gb=: 100MB-1GB -FileSearchData.FileSize.10PlusGb=: 10GB+ -FileSearchData.FileSize.16kbto100kb=: 16-100KB -FileSearchData.FileSize.1gbto5gb=: 1-5GB -FileSearchData.FileSize.1mbto50mb=: 1-50MB -FileSearchData.FileSize.200PlusMb=: 200MB+ -FileSearchData.FileSize.500kbto100mb=: 500KB-100MB -FileSearchData.FileSize.50mbto200mb=: 50-200MB -FileSearchData.FileSize.5gbto10gb=: 5-10GB -FileSearchData.FileSize.LARGE.displayName=Large -FileSearchData.FileSize.MEDIUM.displayName=Medium -FileSearchData.FileSize.SMALL.displayName=Small -FileSearchData.FileSize.upTo16kb=: 0-16KB -FileSearchData.FileSize.upTo500kb=: 0-500KB -FileSearchData.FileSize.XLARGE.displayName=XLarge -FileSearchData.FileSize.XSMALL.displayName=XSmall -FileSearchData.FileSize.XXLARGE.displayName=XXLarge -FileSearchData.FileType.Audio.displayName=Audio -FileSearchData.FileType.Documents.displayName=Documents -FileSearchData.FileType.Executables.displayName=Executables -FileSearchData.FileType.Image.displayName=Image -FileSearchData.FileType.Other.displayName=Other/Unknown -FileSearchData.FileType.Video.displayName=Video -FileSearchData.Frequency.common.displayName=Common (11 - 100) -FileSearchData.Frequency.known.displayName=Known (NSRL) -FileSearchData.Frequency.rare.displayName=Rare (2-10) -FileSearchData.Frequency.unique.displayName=Unique (1) -FileSearchData.Frequency.unknown.displayName=Unknown -FileSearchData.Frequency.verycommon.displayName=Very Common (100+) -FileSearchData.Score.interesting.displayName=Interesting -FileSearchData.Score.notable.displayName=Notable -FileSearchData.Score.unknown.displayName=Unknown FileSearchFiltering.concatenateSetNamesForDisplay.comma=, # {0} - filters FileSearchFiltering.HashSetFilter.desc=Hash set hits in set(s): {0} @@ -79,6 +44,40 @@ ResultFile.score.interestingResult.description=At least one instance of the file ResultFile.score.notableFile.description=At least one instance of the file was recognized as notable. ResultFile.score.notableTaggedFile.description=At least one instance of the file is tagged with a notable tag. ResultFile.score.taggedFile.description=At least one instance of the file has been tagged. +SearchData.AttributeType.Domain.displayName=Domains +SearchData.FileSize.100kbto1mb=: 100KB-1MB +SearchData.FileSize.100mbto1gb=: 100MB-1GB +SearchData.FileSize.10PlusGb=: 10GB+ +SearchData.FileSize.16kbto100kb=: 16-100KB +SearchData.FileSize.1gbto5gb=: 1-5GB +SearchData.FileSize.1mbto50mb=: 1-50MB +SearchData.FileSize.200PlusMb=: 200MB+ +SearchData.FileSize.500kbto100mb=: 500KB-100MB +SearchData.FileSize.50mbto200mb=: 50-200MB +SearchData.FileSize.5gbto10gb=: 5-10GB +SearchData.FileSize.LARGE.displayName=Large +SearchData.FileSize.MEDIUM.displayName=Medium +SearchData.FileSize.SMALL.displayName=Small +SearchData.FileSize.upTo16kb=: 0-16KB +SearchData.FileSize.upTo500kb=: 0-500KB +SearchData.FileSize.XLARGE.displayName=XLarge +SearchData.FileSize.XSMALL.displayName=XSmall +SearchData.FileSize.XXLARGE.displayName=XXLarge +SearchData.FileType.Audio.displayName=Audio +SearchData.FileType.Documents.displayName=Documents +SearchData.FileType.Executables.displayName=Executables +SearchData.FileType.Image.displayName=Image +SearchData.FileType.Other.displayName=Other/Unknown +SearchData.FileType.Video.displayName=Video +SearchData.Frequency.common.displayName=Common (11 - 100) +SearchData.Frequency.known.displayName=Known (NSRL) +SearchData.Frequency.rare.displayName=Rare (2-10) +SearchData.Frequency.unique.displayName=Unique (1) +SearchData.Frequency.unknown.displayName=Unknown +SearchData.Frequency.verycommon.displayName=Very Common (100+) +SearchData.Score.interesting.displayName=Interesting +SearchData.Score.notable.displayName=Notable +SearchData.Score.unknown.displayName=Unknown # {0} - Data source name # {1} - Data source ID SearchFiltering.DataSourceFilter.datasource={0}({1}) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java new file mode 100644 index 0000000000..54123077e8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -0,0 +1,653 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.discovery.search; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.centralrepository.datamodel.InstanceTableCallback; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.CaseDbAccessManager; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; + +/** + * + * @author wschaefer + */ +public class DiscoveryAttributes { + + private final static Logger logger = Logger.getLogger(DiscoveryAttributes.class.getName()); + + /** + * Base class for the grouping attributes. + */ + public abstract static class AttributeType { + + /** + * For a given file, return the key for the group it belongs to for this + * attribute type. + * + * @param file the result file to be grouped + * + * @return the key for the group this file goes in + */ + public abstract DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file); + + /** + * Add any extra data to the ResultFile object from this attribute. + * + * @param files The list of files to enhance + * @param caseDb The case database + * @param centralRepoDb The central repository database. Can be null if + * not needed. + * + * @throws DiscoveryException + */ + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + // Default is to do nothing + } + } + + /** + * Attribute for grouping/sorting by file size + */ + public static class FileSizeAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.FileSizeGroupKey(file); + } + } + + /** + * Attribute for grouping/sorting by parent path + */ + public static class ParentPathAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.ParentPathGroupKey(file); + } + } + + /** + * Default attribute used to make one group + */ + static class NoGroupingAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.NoGroupingGroupKey(); + } + } + + /** + * Attribute for grouping/sorting by data source + */ + static class DataSourceAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.DataSourceGroupKey(file); + } + } + + /** + * Attribute for grouping/sorting by file type + */ + static class FileTypeAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.FileTypeGroupKey(file); + } + } + + /** + * Attribute for grouping/sorting by keyword lists + */ + static class KeywordListAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.KeywordListGroupKey(file); + } + + @Override + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + CentralRepository centralRepoDb) throws DiscoveryException { + + // Get pairs of (object ID, keyword list name) for all files in the list of files that have + // keyword list hits. + String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(), + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); + + SetKeywordListNamesCallback callback = new SetKeywordListNamesCallback(files); + try { + caseDb.getCaseDbAccessManager().select(selectQuery, callback); + } catch (TskCoreException ex) { + throw new DiscoveryException("Error looking up keyword list attributes", ex); // NON-NLS + } + } + + /** + * Callback to process the results of the CaseDbAccessManager select + * query. Will add the keyword list names to the list of ResultFile + * objects. + */ + private static class SetKeywordListNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { + + List resultFiles; + + /** + * Create the callback. + * + * @param resultFiles List of files to add keyword list names to + */ + SetKeywordListNamesCallback(List resultFiles) { + this.resultFiles = resultFiles; + } + + @Override + public void process(ResultSet rs) { + try { + // Create a temporary map of object ID to ResultFile + Map tempMap = new HashMap<>(); + for (ResultFile file : resultFiles) { + tempMap.put(file.getFirstInstance().getId(), file); + } + + while (rs.next()) { + try { + Long objId = rs.getLong("object_id"); // NON-NLS + String keywordListName = rs.getString("set_name"); // NON-NLS + + tempMap.get(objId).addKeywordListName(keywordListName); + + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS + } + } + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Failed to get keyword list names", ex); // NON-NLS + } + } + } + } + + /** + * Attribute for grouping/sorting by frequency in the central repository + */ + static class FrequencyAttribute extends AttributeType { + + static final int BATCH_SIZE = 50; // Number of hashes to look up at one time + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.FrequencyGroupKey(file); + } + + @Override + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + CentralRepository centralRepoDb) throws DiscoveryException { + if (centralRepoDb == null) { + for (ResultFile file : files) { + if (file.getFrequency() == SearchData.Frequency.UNKNOWN && file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { + file.setFrequency(SearchData.Frequency.KNOWN); + } + } + } else { + processResultFilesForCR(files, centralRepoDb); + } + } + + /** + * Private helper method for adding Frequency attribute when CR is + * enabled. + * + * @param files The list of ResultFiles to caluclate frequency + * for. + * @param centralRepoDb The central repository currently in use. + */ + private void processResultFilesForCR(List files, + CentralRepository centralRepoDb) { + List currentFiles = new ArrayList<>(); + Set hashesToLookUp = new HashSet<>(); + for (ResultFile file : files) { + if (file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { + file.setFrequency(SearchData.Frequency.KNOWN); + } + if (file.getFrequency() == SearchData.Frequency.UNKNOWN + && file.getFirstInstance().getMd5Hash() != null + && !file.getFirstInstance().getMd5Hash().isEmpty()) { + hashesToLookUp.add(file.getFirstInstance().getMd5Hash()); + currentFiles.add(file); + } + if (hashesToLookUp.size() >= BATCH_SIZE) { + computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); + + hashesToLookUp.clear(); + currentFiles.clear(); + } + } + computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); + } + } + + /** + * Callback to use with findInterCaseValuesByCount which generates a list of + * values for common property search + */ + private static class FrequencyCallback implements InstanceTableCallback { + + private final List files; + + private FrequencyCallback(List files) { + this.files = new ArrayList<>(files); + } + + @Override + public void process(ResultSet resultSet) { + try { + + while (resultSet.next()) { + String hash = resultSet.getString(1); + int count = resultSet.getInt(2); + for (Iterator iterator = files.iterator(); iterator.hasNext();) { + ResultFile file = iterator.next(); + if (file.getFirstInstance().getMd5Hash().equalsIgnoreCase(hash)) { + file.setFrequency(SearchData.Frequency.fromCount(count)); + iterator.remove(); + } + } + } + + // The files left had no matching entries in the CR, so mark them as unique + for (ResultFile file : files) { + file.setFrequency(SearchData.Frequency.UNIQUE); + } + } catch (SQLException ex) { + logger.log(Level.WARNING, "Error getting frequency counts from Central Repository", ex); // NON-NLS + } + } + } + + /** + * Attribute for grouping/sorting by hash set lists + */ + static class HashHitsAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.HashHitsGroupKey(file); + } + + @Override + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + CentralRepository centralRepoDb) throws DiscoveryException { + + // Get pairs of (object ID, hash set name) for all files in the list of files that have + // hash set hits. + String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(), + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); + + HashSetNamesCallback callback = new HashSetNamesCallback(files); + try { + caseDb.getCaseDbAccessManager().select(selectQuery, callback); + } catch (TskCoreException ex) { + throw new DiscoveryException("Error looking up hash set attributes", ex); // NON-NLS + } + } + + /** + * Callback to process the results of the CaseDbAccessManager select + * query. Will add the hash set names to the list of ResultFile objects. + */ + private static class HashSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { + + List resultFiles; + + /** + * Create the callback. + * + * @param resultFiles List of files to add hash set names to + */ + HashSetNamesCallback(List resultFiles) { + this.resultFiles = resultFiles; + } + + @Override + public void process(ResultSet rs) { + try { + // Create a temporary map of object ID to ResultFile + Map tempMap = new HashMap<>(); + for (ResultFile file : resultFiles) { + tempMap.put(file.getFirstInstance().getId(), file); + } + + while (rs.next()) { + try { + Long objId = rs.getLong("object_id"); // NON-NLS + String hashSetName = rs.getString("set_name"); // NON-NLS + + tempMap.get(objId).addHashSetName(hashSetName); + + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS + } + } + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Failed to get hash set names", ex); // NON-NLS + } + } + } + } + + /** + * Attribute for grouping/sorting by interesting item set lists + */ + static class InterestingItemAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.InterestingItemGroupKey(file); + } + + @Override + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + CentralRepository centralRepoDb) throws DiscoveryException { + + // Get pairs of (object ID, interesting item set name) for all files in the list of files that have + // interesting file set hits. + String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); + + InterestingFileSetNamesCallback callback = new InterestingFileSetNamesCallback(files); + try { + caseDb.getCaseDbAccessManager().select(selectQuery, callback); + } catch (TskCoreException ex) { + throw new DiscoveryException("Error looking up interesting file set attributes", ex); // NON-NLS + } + } + + /** + * Callback to process the results of the CaseDbAccessManager select + * query. Will add the interesting file set names to the list of + * ResultFile objects. + */ + private static class InterestingFileSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { + + List resultFiles; + + /** + * Create the callback. + * + * @param resultFiles List of files to add interesting file set + * names to + */ + InterestingFileSetNamesCallback(List resultFiles) { + this.resultFiles = resultFiles; + } + + @Override + public void process(ResultSet rs) { + try { + // Create a temporary map of object ID to ResultFile + Map tempMap = new HashMap<>(); + for (ResultFile file : resultFiles) { + tempMap.put(file.getFirstInstance().getId(), file); + } + + while (rs.next()) { + try { + Long objId = rs.getLong("object_id"); // NON-NLS + String setName = rs.getString("set_name"); // NON-NLS + + tempMap.get(objId).addInterestingSetName(setName); + + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS + } + } + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Failed to get interesting file set names", ex); // NON-NLS + } + } + } + } + + /** + * Attribute for grouping/sorting by objects detected + */ + static class ObjectDetectedAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.ObjectDetectedGroupKey(file); + } + + @Override + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + CentralRepository centralRepoDb) throws DiscoveryException { + + // Get pairs of (object ID, object type name) for all files in the list of files that have + // objects detected + String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID(), + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID()); + + ObjectDetectedNamesCallback callback = new ObjectDetectedNamesCallback(files); + try { + caseDb.getCaseDbAccessManager().select(selectQuery, callback); + } catch (TskCoreException ex) { + throw new DiscoveryException("Error looking up object detected attributes", ex); // NON-NLS + } + } + + /** + * Callback to process the results of the CaseDbAccessManager select + * query. Will add the object type names to the list of ResultFile + * objects. + */ + private static class ObjectDetectedNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { + + List resultFiles; + + /** + * Create the callback. + * + * @param resultFiles List of files to add object detected names to + */ + ObjectDetectedNamesCallback(List resultFiles) { + this.resultFiles = resultFiles; + } + + @Override + public void process(ResultSet rs) { + try { + // Create a temporary map of object ID to ResultFile + Map tempMap = new HashMap<>(); + for (ResultFile file : resultFiles) { + tempMap.put(file.getFirstInstance().getId(), file); + } + + while (rs.next()) { + try { + Long objId = rs.getLong("object_id"); // NON-NLS + String setName = rs.getString("set_name"); // NON-NLS + + tempMap.get(objId).addObjectDetectedName(setName); + + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS + } + } + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Failed to get object detected names", ex); // NON-NLS + } + } + } + } + + /** + * Attribute for grouping/sorting by tag name + */ + static class FileTagAttribute extends AttributeType { + + @Override + public DiscoveryKeyUtils.GroupKey getGroupKey(ResultFile file) { + return new DiscoveryKeyUtils.FileTagGroupKey(file); + } + + @Override + public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, + CentralRepository centralRepoDb) throws DiscoveryException { + + try { + for (ResultFile resultFile : files) { + List contentTags = caseDb.getContentTagsByContent(resultFile.getFirstInstance()); + + for (ContentTag tag : contentTags) { + resultFile.addTagName(tag.getName().getDisplayName()); + } + } + } catch (TskCoreException ex) { + throw new DiscoveryException("Error looking up file tag attributes", ex); // NON-NLS + } + } + } + + /** + * Enum for the attribute types that can be used for grouping. + */ + @NbBundle.Messages({ + "DiscoveryAttributes.GroupingAttributeType.fileType.displayName=File Type", + "DiscoveryAttributes.GroupingAttributeType.frequency.displayName=Past Occurrences", + "DiscoveryAttributes.GroupingAttributeType.keywordList.displayName=Keyword", + "DiscoveryAttributes.GroupingAttributeType.size.displayName=File Size", + "DiscoveryAttributes.GroupingAttributeType.datasource.displayName=Data Source", + "DiscoveryAttributes.GroupingAttributeType.parent.displayName=Parent Folder", + "DiscoveryAttributes.GroupingAttributeType.hash.displayName=Hash Set", + "DiscoveryAttributes.GroupingAttributeType.interestingItem.displayName=Interesting Item", + "DiscoveryAttributes.GroupingAttributeType.tag.displayName=Tag", + "DiscoveryAttributes.GroupingAttributeType.object.displayName=Object Detected", + "DiscoveryAttributes.GroupingAttributeType.none.displayName=None"}) + public enum GroupingAttributeType { + FILE_SIZE(new FileSizeAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_size_displayName()), + FREQUENCY(new FrequencyAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_frequency_displayName()), + KEYWORD_LIST_NAME(new KeywordListAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_keywordList_displayName()), + DATA_SOURCE(new DataSourceAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_datasource_displayName()), + PARENT_PATH(new ParentPathAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_parent_displayName()), + HASH_LIST_NAME(new HashHitsAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_hash_displayName()), + INTERESTING_ITEM_SET(new InterestingItemAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_interestingItem_displayName()), + FILE_TAG(new FileTagAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_tag_displayName()), + OBJECT_DETECTED(new ObjectDetectedAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_object_displayName()), + NO_GROUPING(new NoGroupingAttribute(), Bundle.DiscoveryAttributes_GroupingAttributeType_none_displayName()); + + private final AttributeType attributeType; + private final String displayName; + + GroupingAttributeType(AttributeType attributeType, String displayName) { + this.attributeType = attributeType; + this.displayName = displayName; + } + + @Override + public String toString() { + return displayName; + } + + public AttributeType getAttributeType() { + return attributeType; + } + + /** + * Get the list of enums that are valid for grouping images. + * + * @return enums that can be used to group images + */ + public static List getOptionsForGrouping() { + return Arrays.asList(FILE_SIZE, FREQUENCY, PARENT_PATH, OBJECT_DETECTED, HASH_LIST_NAME, INTERESTING_ITEM_SET); + } + } + + /** + * Computes the CR frequency of all the given hashes and updates the list of + * files. + * + * @param hashesToLookUp Hashes to find the frequency of + * @param currentFiles List of files to update with frequencies + */ + private static void computeFrequency(Set hashesToLookUp, List currentFiles, CentralRepository centralRepoDb) { + + if (hashesToLookUp.isEmpty()) { + return; + } + + String hashes = String.join("','", hashesToLookUp); + hashes = "'" + hashes + "'"; + try { + CorrelationAttributeInstance.Type attributeType = centralRepoDb.getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID); + String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType); + + String selectClause = " value, COUNT(value) FROM " + + "(SELECT DISTINCT case_id, value FROM " + tableName + + " WHERE value IN (" + + hashes + + ")) AS foo GROUP BY value"; + + FrequencyCallback callback = new FrequencyCallback(currentFiles); + centralRepoDb.processSelectClause(selectClause, callback); + + } catch (CentralRepoException ex) { + logger.log(Level.WARNING, "Error getting frequency counts from Central Repository", ex); // NON-NLS + } + + } + + private static String createSetNameClause(List files, + int artifactTypeID, int setNameAttrID) throws DiscoveryException { + + // Concatenate the object IDs in the list of files + String objIdList = ""; // NON-NLS + for (ResultFile file : files) { + if (!objIdList.isEmpty()) { + objIdList += ","; // NON-NLS + } + objIdList += "\'" + file.getFirstInstance().getId() + "\'"; // NON-NLS + } + + // Get pairs of (object ID, set name) for all files in the list of files that have + // the given artifact type. + return "blackboard_artifacts.obj_id AS object_id, blackboard_attributes.value_text AS set_name " + + "FROM blackboard_artifacts " + + "INNER JOIN blackboard_attributes ON blackboard_artifacts.artifact_id=blackboard_attributes.artifact_id " + + "WHERE blackboard_attributes.artifact_type_id=\'" + artifactTypeID + "\' " + + "AND blackboard_attributes.attribute_type_id=\'" + setNameAttrID + "\' " + + "AND blackboard_artifacts.obj_id IN (" + objIdList + ") "; // NON-NLS + } + + private DiscoveryAttributes() { + // Class should not be instantiated + } +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java index 5bd5d81ef0..f58a6eb08b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryEventUtils.java @@ -119,7 +119,7 @@ public final class DiscoveryEventUtils { private final Map groupMap; private final List searchFilters; - private final FileSearch.AttributeType groupingAttribute; + private final DiscoveryAttributes.AttributeType groupingAttribute; private final Group.GroupSortingAlgorithm groupSort; private final FileSorter.SortingMethod fileSortMethod; @@ -135,7 +135,7 @@ public final class DiscoveryEventUtils { * @param fileSortMethod The sorting method used for files. */ public SearchCompleteEvent(Map groupMap, List searchfilters, - FileSearch.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, + DiscoveryAttributes.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { this.groupMap = groupMap; this.searchFilters = searchfilters; @@ -167,7 +167,7 @@ public final class DiscoveryEventUtils { * * @return The grouping attribute used by the search. */ - public FileSearch.AttributeType getGroupingAttr() { + public DiscoveryAttributes.AttributeType getGroupingAttr() { return groupingAttribute; } @@ -278,7 +278,7 @@ public final class DiscoveryEventUtils { private final GroupKey groupKey; private final int groupSize; private final List searchfilters; - private final FileSearch.AttributeType groupingAttribute; + private final DiscoveryAttributes.AttributeType groupingAttribute; private final Group.GroupSortingAlgorithm groupSort; private final FileSorter.SortingMethod fileSortMethod; @@ -297,7 +297,7 @@ public final class DiscoveryEventUtils { * @param resultType The type of files which exist in the group. */ public GroupSelectedEvent(List searchfilters, - FileSearch.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, + DiscoveryAttributes.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, int groupSize, Type resultType) { this.searchfilters = searchfilters; this.groupingAttribute = groupingAttribute; @@ -369,7 +369,7 @@ public final class DiscoveryEventUtils { * * @return The grouping attribute used by the search. */ - public FileSearch.AttributeType getGroupingAttr() { + public DiscoveryAttributes.AttributeType getGroupingAttr() { return groupingAttribute; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index 481d354b8f..9eb172094f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -52,7 +52,7 @@ public class DiscoveryKeyUtils { * @param fileSortingMethod The method to sort the files by. */ SearchKey(String userName, List filters, - FileSearch.AttributeType groupAttributeType, + DiscoveryAttributes.AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, FileSorter.SortingMethod fileSortingMethod) { StringBuilder searchStringBuilder = new StringBuilder(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java index 625f2140bd..b5d51d6810 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java @@ -21,35 +21,18 @@ package org.sleuthkit.autopsy.discovery.search; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.io.IOException; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.logging.Level; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; -import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; -import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil; -import org.sleuthkit.autopsy.centralrepository.datamodel.InstanceTableCallback; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.discovery.search.SearchData.Frequency; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.CaseDbAccessManager; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.AttributeType; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.SearchKey; import org.sleuthkit.autopsy.textsummarizer.TextSummarizer; @@ -322,615 +305,9 @@ public class FileSearch { } } - /** - * Computes the CR frequency of all the given hashes and updates the list of - * files. - * - * @param hashesToLookUp Hashes to find the frequency of - * @param currentFiles List of files to update with frequencies - */ - private static void computeFrequency(Set hashesToLookUp, List currentFiles, CentralRepository centralRepoDb) { - - if (hashesToLookUp.isEmpty()) { - return; - } - - String hashes = String.join("','", hashesToLookUp); - hashes = "'" + hashes + "'"; - try { - CorrelationAttributeInstance.Type attributeType = centralRepoDb.getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID); - String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType); - - String selectClause = " value, COUNT(value) FROM " - + "(SELECT DISTINCT case_id, value FROM " + tableName - + " WHERE value IN (" - + hashes - + ")) AS foo GROUP BY value"; - - FrequencyCallback callback = new FrequencyCallback(currentFiles); - centralRepoDb.processSelectClause(selectClause, callback); - - } catch (CentralRepoException ex) { - logger.log(Level.WARNING, "Error getting frequency counts from Central Repository", ex); // NON-NLS - } - - } - - private static String createSetNameClause(List files, - int artifactTypeID, int setNameAttrID) throws DiscoveryException { - - // Concatenate the object IDs in the list of files - String objIdList = ""; // NON-NLS - for (ResultFile file : files) { - if (!objIdList.isEmpty()) { - objIdList += ","; // NON-NLS - } - objIdList += "\'" + file.getFirstInstance().getId() + "\'"; // NON-NLS - } - - // Get pairs of (object ID, set name) for all files in the list of files that have - // the given artifact type. - return "blackboard_artifacts.obj_id AS object_id, blackboard_attributes.value_text AS set_name " - + "FROM blackboard_artifacts " - + "INNER JOIN blackboard_attributes ON blackboard_artifacts.artifact_id=blackboard_attributes.artifact_id " - + "WHERE blackboard_attributes.artifact_type_id=\'" + artifactTypeID + "\' " - + "AND blackboard_attributes.attribute_type_id=\'" + setNameAttrID + "\' " - + "AND blackboard_artifacts.obj_id IN (" + objIdList + ") "; // NON-NLS - } private FileSearch() { // Class should not be instantiated } - /** - * Base class for the grouping attributes. - */ - public abstract static class AttributeType { - - /** - * For a given file, return the key for the group it belongs to for this - * attribute type. - * - * @param file the result file to be grouped - * - * @return the key for the group this file goes in - */ - public abstract GroupKey getGroupKey(ResultFile file); - - /** - * Add any extra data to the ResultFile object from this attribute. - * - * @param files The list of files to enhance - * @param caseDb The case database - * @param centralRepoDb The central repository database. Can be null if - * not needed. - * - * @throws DiscoveryException - */ - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { - // Default is to do nothing - } - } - - /** - * Attribute for grouping/sorting by file size - */ - public static class FileSizeAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.FileSizeGroupKey(file); - } - } - - /** - * Attribute for grouping/sorting by parent path - */ - public static class ParentPathAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.ParentPathGroupKey(file); - } - } - - /** - * Default attribute used to make one group - */ - static class NoGroupingAttribute extends FileSearch.AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.NoGroupingGroupKey(); - } - } - - /** - * Attribute for grouping/sorting by data source - */ - static class DataSourceAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.DataSourceGroupKey(file); - } - } - - /** - * Attribute for grouping/sorting by file type - */ - static class FileTypeAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.FileTypeGroupKey(file); - } - } - - /** - * Attribute for grouping/sorting by keyword lists - */ - static class KeywordListAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.KeywordListGroupKey(file); - } - - @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { - - // Get pairs of (object ID, keyword list name) for all files in the list of files that have - // keyword list hits. - String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(), - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); - - SetKeywordListNamesCallback callback = new SetKeywordListNamesCallback(files); - try { - caseDb.getCaseDbAccessManager().select(selectQuery, callback); - } catch (TskCoreException ex) { - throw new DiscoveryException("Error looking up keyword list attributes", ex); // NON-NLS - } - } - - /** - * Callback to process the results of the CaseDbAccessManager select - * query. Will add the keyword list names to the list of ResultFile - * objects. - */ - private static class SetKeywordListNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - - List resultFiles; - - /** - * Create the callback. - * - * @param resultFiles List of files to add keyword list names to - */ - SetKeywordListNamesCallback(List resultFiles) { - this.resultFiles = resultFiles; - } - - @Override - public void process(ResultSet rs) { - try { - // Create a temporary map of object ID to ResultFile - Map tempMap = new HashMap<>(); - for (ResultFile file : resultFiles) { - tempMap.put(file.getFirstInstance().getId(), file); - } - - while (rs.next()) { - try { - Long objId = rs.getLong("object_id"); // NON-NLS - String keywordListName = rs.getString("set_name"); // NON-NLS - - tempMap.get(objId).addKeywordListName(keywordListName); - - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS - } - } - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Failed to get keyword list names", ex); // NON-NLS - } - } - } - } - - /** - * Attribute for grouping/sorting by frequency in the central repository - */ - static class FrequencyAttribute extends AttributeType { - - static final int BATCH_SIZE = 50; // Number of hashes to look up at one time - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.FrequencyGroupKey(file); - } - - @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { - if (centralRepoDb == null) { - for (ResultFile file : files) { - if (file.getFrequency() == Frequency.UNKNOWN && file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { - file.setFrequency(Frequency.KNOWN); - } - } - } else { - processResultFilesForCR(files, centralRepoDb); - } - } - - /** - * Private helper method for adding Frequency attribute when CR is - * enabled. - * - * @param files The list of ResultFiles to caluclate frequency - * for. - * @param centralRepoDb The central repository currently in use. - */ - private void processResultFilesForCR(List files, - CentralRepository centralRepoDb) { - List currentFiles = new ArrayList<>(); - Set hashesToLookUp = new HashSet<>(); - for (ResultFile file : files) { - if (file.getFirstInstance().getKnown() == TskData.FileKnown.KNOWN) { - file.setFrequency(Frequency.KNOWN); - } - if (file.getFrequency() == Frequency.UNKNOWN - && file.getFirstInstance().getMd5Hash() != null - && !file.getFirstInstance().getMd5Hash().isEmpty()) { - hashesToLookUp.add(file.getFirstInstance().getMd5Hash()); - currentFiles.add(file); - } - if (hashesToLookUp.size() >= BATCH_SIZE) { - computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); - - hashesToLookUp.clear(); - currentFiles.clear(); - } - } - computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); - } - } - - /** - * Callback to use with findInterCaseValuesByCount which generates a list of - * values for common property search - */ - private static class FrequencyCallback implements InstanceTableCallback { - - private final List files; - - private FrequencyCallback(List files) { - this.files = new ArrayList<>(files); - } - - @Override - public void process(ResultSet resultSet) { - try { - - while (resultSet.next()) { - String hash = resultSet.getString(1); - int count = resultSet.getInt(2); - for (Iterator iterator = files.iterator(); iterator.hasNext();) { - ResultFile file = iterator.next(); - if (file.getFirstInstance().getMd5Hash().equalsIgnoreCase(hash)) { - file.setFrequency(Frequency.fromCount(count)); - iterator.remove(); - } - } - } - - // The files left had no matching entries in the CR, so mark them as unique - for (ResultFile file : files) { - file.setFrequency(Frequency.UNIQUE); - } - } catch (SQLException ex) { - logger.log(Level.WARNING, "Error getting frequency counts from Central Repository", ex); // NON-NLS - } - } - } - - /** - * Attribute for grouping/sorting by hash set lists - */ - static class HashHitsAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.HashHitsGroupKey(file); - } - - @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { - - // Get pairs of (object ID, hash set name) for all files in the list of files that have - // hash set hits. - String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(), - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); - - HashSetNamesCallback callback = new HashSetNamesCallback(files); - try { - caseDb.getCaseDbAccessManager().select(selectQuery, callback); - } catch (TskCoreException ex) { - throw new DiscoveryException("Error looking up hash set attributes", ex); // NON-NLS - } - } - - /** - * Callback to process the results of the CaseDbAccessManager select - * query. Will add the hash set names to the list of ResultFile objects. - */ - private static class HashSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - - List resultFiles; - - /** - * Create the callback. - * - * @param resultFiles List of files to add hash set names to - */ - HashSetNamesCallback(List resultFiles) { - this.resultFiles = resultFiles; - } - - @Override - public void process(ResultSet rs) { - try { - // Create a temporary map of object ID to ResultFile - Map tempMap = new HashMap<>(); - for (ResultFile file : resultFiles) { - tempMap.put(file.getFirstInstance().getId(), file); - } - - while (rs.next()) { - try { - Long objId = rs.getLong("object_id"); // NON-NLS - String hashSetName = rs.getString("set_name"); // NON-NLS - - tempMap.get(objId).addHashSetName(hashSetName); - - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS - } - } - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Failed to get hash set names", ex); // NON-NLS - } - } - } - } - - /** - * Attribute for grouping/sorting by interesting item set lists - */ - static class InterestingItemAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.InterestingItemGroupKey(file); - } - - @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { - - // Get pairs of (object ID, interesting item set name) for all files in the list of files that have - // interesting file set hits. - String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); - - InterestingFileSetNamesCallback callback = new InterestingFileSetNamesCallback(files); - try { - caseDb.getCaseDbAccessManager().select(selectQuery, callback); - } catch (TskCoreException ex) { - throw new DiscoveryException("Error looking up interesting file set attributes", ex); // NON-NLS - } - } - - /** - * Callback to process the results of the CaseDbAccessManager select - * query. Will add the interesting file set names to the list of - * ResultFile objects. - */ - private static class InterestingFileSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - - List resultFiles; - - /** - * Create the callback. - * - * @param resultFiles List of files to add interesting file set - * names to - */ - InterestingFileSetNamesCallback(List resultFiles) { - this.resultFiles = resultFiles; - } - - @Override - public void process(ResultSet rs) { - try { - // Create a temporary map of object ID to ResultFile - Map tempMap = new HashMap<>(); - for (ResultFile file : resultFiles) { - tempMap.put(file.getFirstInstance().getId(), file); - } - - while (rs.next()) { - try { - Long objId = rs.getLong("object_id"); // NON-NLS - String setName = rs.getString("set_name"); // NON-NLS - - tempMap.get(objId).addInterestingSetName(setName); - - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS - } - } - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Failed to get interesting file set names", ex); // NON-NLS - } - } - } - } - - /** - * Attribute for grouping/sorting by objects detected - */ - static class ObjectDetectedAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.ObjectDetectedGroupKey(file); - } - - @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { - - // Get pairs of (object ID, object type name) for all files in the list of files that have - // objects detected - String selectQuery = createSetNameClause(files, BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID(), - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID()); - - ObjectDetectedNamesCallback callback = new ObjectDetectedNamesCallback(files); - try { - caseDb.getCaseDbAccessManager().select(selectQuery, callback); - } catch (TskCoreException ex) { - throw new DiscoveryException("Error looking up object detected attributes", ex); // NON-NLS - } - } - - /** - * Callback to process the results of the CaseDbAccessManager select - * query. Will add the object type names to the list of ResultFile - * objects. - */ - private static class ObjectDetectedNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - - List resultFiles; - - /** - * Create the callback. - * - * @param resultFiles List of files to add object detected names to - */ - ObjectDetectedNamesCallback(List resultFiles) { - this.resultFiles = resultFiles; - } - - @Override - public void process(ResultSet rs) { - try { - // Create a temporary map of object ID to ResultFile - Map tempMap = new HashMap<>(); - for (ResultFile file : resultFiles) { - tempMap.put(file.getFirstInstance().getId(), file); - } - - while (rs.next()) { - try { - Long objId = rs.getLong("object_id"); // NON-NLS - String setName = rs.getString("set_name"); // NON-NLS - - tempMap.get(objId).addObjectDetectedName(setName); - - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS - } - } - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Failed to get object detected names", ex); // NON-NLS - } - } - } - } - - /** - * Attribute for grouping/sorting by tag name - */ - static class FileTagAttribute extends AttributeType { - - @Override - public GroupKey getGroupKey(ResultFile file) { - return new DiscoveryKeyUtils.FileTagGroupKey(file); - } - - @Override - public void addAttributeToResultFiles(List files, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { - - try { - for (ResultFile resultFile : files) { - List contentTags = caseDb.getContentTagsByContent(resultFile.getFirstInstance()); - - for (ContentTag tag : contentTags) { - resultFile.addTagName(tag.getName().getDisplayName()); - } - } - } catch (TskCoreException ex) { - throw new DiscoveryException("Error looking up file tag attributes", ex); // NON-NLS - } - } - } - - /** - * Enum for the attribute types that can be used for grouping. - */ - @NbBundle.Messages({ - "FileSearch.GroupingAttributeType.fileType.displayName=File Type", - "FileSearch.GroupingAttributeType.frequency.displayName=Past Occurrences", - "FileSearch.GroupingAttributeType.keywordList.displayName=Keyword", - "FileSearch.GroupingAttributeType.size.displayName=File Size", - "FileSearch.GroupingAttributeType.datasource.displayName=Data Source", - "FileSearch.GroupingAttributeType.parent.displayName=Parent Folder", - "FileSearch.GroupingAttributeType.hash.displayName=Hash Set", - "FileSearch.GroupingAttributeType.interestingItem.displayName=Interesting Item", - "FileSearch.GroupingAttributeType.tag.displayName=Tag", - "FileSearch.GroupingAttributeType.object.displayName=Object Detected", - "FileSearch.GroupingAttributeType.none.displayName=None"}) - public enum GroupingAttributeType { - FILE_SIZE(new FileSizeAttribute(), Bundle.FileSearch_GroupingAttributeType_size_displayName()), - FREQUENCY(new FrequencyAttribute(), Bundle.FileSearch_GroupingAttributeType_frequency_displayName()), - KEYWORD_LIST_NAME(new KeywordListAttribute(), Bundle.FileSearch_GroupingAttributeType_keywordList_displayName()), - DATA_SOURCE(new DataSourceAttribute(), Bundle.FileSearch_GroupingAttributeType_datasource_displayName()), - PARENT_PATH(new ParentPathAttribute(), Bundle.FileSearch_GroupingAttributeType_parent_displayName()), - HASH_LIST_NAME(new HashHitsAttribute(), Bundle.FileSearch_GroupingAttributeType_hash_displayName()), - INTERESTING_ITEM_SET(new InterestingItemAttribute(), Bundle.FileSearch_GroupingAttributeType_interestingItem_displayName()), - FILE_TAG(new FileTagAttribute(), Bundle.FileSearch_GroupingAttributeType_tag_displayName()), - OBJECT_DETECTED(new ObjectDetectedAttribute(), Bundle.FileSearch_GroupingAttributeType_object_displayName()), - NO_GROUPING(new NoGroupingAttribute(), Bundle.FileSearch_GroupingAttributeType_none_displayName()); - - private final AttributeType attributeType; - private final String displayName; - - GroupingAttributeType(AttributeType attributeType, String displayName) { - this.attributeType = attributeType; - this.displayName = displayName; - } - - @Override - public String toString() { - return displayName; - } - - public AttributeType getAttributeType() { - return attributeType; - } - - /** - * Get the list of enums that are valid for grouping images. - * - * @return enums that can be used to group images - */ - public static List getOptionsForGrouping() { - return Arrays.asList(FILE_SIZE, FREQUENCY, PARENT_PATH, OBJECT_DETECTED, HASH_LIST_NAME, INTERESTING_ITEM_SET); - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java index 30064b5ce9..a97f99d8cd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSorter.java @@ -254,19 +254,19 @@ public class FileSorter implements Comparator { Bundle.FileSorter_SortingMethod_datasource_displayName()), // Sort in increasing order of data source ID BY_FILE_SIZE(new ArrayList<>(), Bundle.FileSorter_SortingMethod_filesize_displayName()), // Sort in decreasing order of size - BY_FILE_TYPE(Arrays.asList(new FileSearch.FileTypeAttribute()), + BY_FILE_TYPE(Arrays.asList(new DiscoveryAttributes.FileTypeAttribute()), Bundle.FileSorter_SortingMethod_filetype_displayName()), // Sort in order of file type (defined in FileType enum), with secondary sort on MIME type - BY_FREQUENCY(Arrays.asList(new FileSearch.FrequencyAttribute()), + BY_FREQUENCY(Arrays.asList(new DiscoveryAttributes.FrequencyAttribute()), Bundle.FileSorter_SortingMethod_frequency_displayName()), // Sort by decreasing rarity in the central repository - BY_KEYWORD_LIST_NAMES(Arrays.asList(new FileSearch.KeywordListAttribute()), + BY_KEYWORD_LIST_NAMES(Arrays.asList(new DiscoveryAttributes.KeywordListAttribute()), Bundle.FileSorter_SortingMethod_keywordlist_displayName()), // Sort alphabetically by list of keyword list names found BY_FULL_PATH(new ArrayList<>(), Bundle.FileSorter_SortingMethod_fullPath_displayName()); // Sort alphabetically by path private final String displayName; - private final List requiredAttributes; + private final List requiredAttributes; - SortingMethod(List attributes, String displayName) { + SortingMethod(List attributes, String displayName) { this.requiredAttributes = attributes; this.displayName = displayName; } @@ -276,7 +276,7 @@ public class FileSorter implements Comparator { return displayName; } - public List getRequiredAttributes() { + public List getRequiredAttributes() { return Collections.unmodifiableList(requiredAttributes); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index 9b4374e927..59bf5e15d3 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -524,7 +524,7 @@ public class SearchFiltering { } // Set the frequency for each file - FileSearch.FrequencyAttribute freqAttr = new FileSearch.FrequencyAttribute(); + DiscoveryAttributes.FrequencyAttribute freqAttr = new DiscoveryAttributes.FrequencyAttribute(); freqAttr.addAttributeToResultFiles(currentResults, caseDb, centralRepoDb); // If the frequency matches the filter, add the file to the results diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java index 77ce01b5c9..176c22d652 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchResults.java @@ -33,7 +33,7 @@ import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; class SearchResults { private final Group.GroupSortingAlgorithm groupSortingType; - private final FileSearch.AttributeType attrType; + private final DiscoveryAttributes.AttributeType attrType; private final FileSorter fileSorter; private final Map groupMap = new HashMap<>(); @@ -50,7 +50,7 @@ class SearchResults { * @param fileSortingMethod The method that should be used to * sortGroupsAndFiles the files in each group. */ - SearchResults(Group.GroupSortingAlgorithm groupSortingType, FileSearch.AttributeType attrType, + SearchResults(Group.GroupSortingAlgorithm groupSortingType, DiscoveryAttributes.AttributeType attrType, FileSorter.SortingMethod fileSortingMethod) { this.groupSortingType = groupSortingType; this.attrType = attrType; @@ -63,7 +63,7 @@ class SearchResults { */ SearchResults() { this.groupSortingType = Group.GroupSortingAlgorithm.BY_GROUP_NAME; - this.attrType = new FileSearch.FileSizeAttribute(); + this.attrType = new DiscoveryAttributes.FileSizeAttribute(); this.fileSorter = new FileSorter(FileSorter.SortingMethod.BY_FILE_NAME); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index dc0f8cc6de..7227388742 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -37,13 +37,13 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.Group.GroupSortingAlgorithm; import static org.sleuthkit.autopsy.discovery.search.Group.GroupSortingAlgorithm.BY_GROUP_SIZE; -import org.sleuthkit.autopsy.discovery.search.FileSearch; -import org.sleuthkit.autopsy.discovery.search.FileSearch.GroupingAttributeType; -import static org.sleuthkit.autopsy.discovery.search.FileSearch.GroupingAttributeType.PARENT_PATH; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.GroupingAttributeType; +import static org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes.GroupingAttributeType.PARENT_PATH; import org.sleuthkit.autopsy.discovery.search.FileSorter; import org.sleuthkit.autopsy.discovery.search.FileSorter.SortingMethod; import static org.sleuthkit.autopsy.discovery.search.FileSorter.SortingMethod.BY_FILE_NAME; @@ -169,7 +169,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { private void updateComboBoxes() { groupByCombobox.removeAllItems(); // Set up the grouping attributes - for (FileSearch.GroupingAttributeType groupingType : FileSearch.GroupingAttributeType.getOptionsForGrouping()) { + for (DiscoveryAttributes.GroupingAttributeType groupingType : DiscoveryAttributes.GroupingAttributeType.getOptionsForGrouping()) { addTypeToGroupByComboBox(groupingType); } groupByCombobox.setSelectedItem(PARENT_PATH); @@ -554,7 +554,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.SearchStartedEvent(type)); // Get the grouping attribute and group sorting method - FileSearch.AttributeType groupingAttr = groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex()).getAttributeType(); + DiscoveryAttributes.AttributeType groupingAttr = groupByCombobox.getItemAt(groupByCombobox.getSelectedIndex()).getAttributeType(); Group.GroupSortingAlgorithm groupSortAlgorithm = groupSortingComboBox.getItemAt(groupSortingComboBox.getSelectedIndex()); // Get the file sorting method diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java index ddca7c785e..b9f47dc26e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/GroupListPanel.java @@ -29,10 +29,10 @@ import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.Group; -import org.sleuthkit.autopsy.discovery.search.FileSearch; import org.sleuthkit.autopsy.discovery.search.SearchData.Type; import org.sleuthkit.autopsy.discovery.search.FileSorter; @@ -45,7 +45,7 @@ final class GroupListPanel extends javax.swing.JPanel { private Type type = null; private Map groupMap = null; private List searchfilters; - private FileSearch.AttributeType groupingAttribute; + private DiscoveryAttributes.AttributeType groupingAttribute; private Group.GroupSortingAlgorithm groupSort; private FileSorter.SortingMethod fileSortMethod; private GroupKey selectedGroupKey; @@ -210,7 +210,7 @@ final class GroupListPanel extends javax.swing.JPanel { String valueString = newValue.toString(); setToolTipText(valueString); //if paths would be longer than 37 characters shorten them to be 37 characters - if (groupingAttribute instanceof FileSearch.ParentPathAttribute && valueString.length() > 37) { + if (groupingAttribute instanceof DiscoveryAttributes.ParentPathAttribute && valueString.length() > 37) { valueString = valueString.substring(0, 16) + " ... " + valueString.substring(valueString.length() - 16); } newValue = valueString + " (" + groupMap.get(newValue) + ")"; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java index 1139366cf0..3a9033b08f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java @@ -26,6 +26,7 @@ import javax.swing.SwingWorker; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.Group; @@ -43,7 +44,7 @@ final class PageWorker extends SwingWorker { private final static Logger logger = Logger.getLogger(PageWorker.class.getName()); private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS private final List searchfilters; - private final FileSearch.AttributeType groupingAttribute; + private final DiscoveryAttributes.AttributeType groupingAttribute; private final Group.GroupSortingAlgorithm groupSort; private final FileSorter.SortingMethod fileSortMethod; private final GroupKey groupKey; @@ -69,7 +70,7 @@ final class PageWorker extends SwingWorker { * @param resultType The type of files which exist in the group. * @param centralRepo The central repository to be used. */ - PageWorker(List searchfilters, FileSearch.AttributeType groupingAttribute, + PageWorker(List searchfilters, DiscoveryAttributes.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod, GroupKey groupKey, int startingEntry, int pageSize, SearchData.Type resultType, CentralRepository centralRepo) { this.searchfilters = searchfilters; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java index c6551d7706..d11700e336 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/ResultsPanel.java @@ -38,6 +38,7 @@ import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.Group; @@ -59,7 +60,7 @@ final class ResultsPanel extends javax.swing.JPanel { private final ImageThumbnailViewer imageThumbnailViewer; private final DocumentPreviewViewer documentPreviewViewer; private List searchFilters; - private FileSearch.AttributeType groupingAttribute; + private DiscoveryAttributes.AttributeType groupingAttribute; private Group.GroupSortingAlgorithm groupSort; private FileSorter.SortingMethod fileSortMethod; private GroupKey selectedGroupKey; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java index 49b2de3d71..4453743bcf 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java @@ -27,6 +27,7 @@ import java.util.logging.Level; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryEventUtils; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; import org.sleuthkit.autopsy.discovery.search.Group; @@ -42,7 +43,7 @@ final class SearchWorker extends SwingWorker { private final static Logger logger = Logger.getLogger(SearchWorker.class.getName()); private static final String USER_NAME_PROPERTY = "user.name"; //NON-NLS private final List filters; - private final FileSearch.AttributeType groupingAttr; + private final DiscoveryAttributes.AttributeType groupingAttr; private final FileSorter.SortingMethod fileSort; private final Group.GroupSortingAlgorithm groupSortAlgorithm; private final CentralRepository centralRepoDb; @@ -58,7 +59,7 @@ final class SearchWorker extends SwingWorker { * @param groupSort The Algorithm to sort groups by. * @param fileSortMethod The SortingMethod to use for files. */ - SearchWorker(CentralRepository centralRepo, List searchfilters, FileSearch.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { + SearchWorker(CentralRepository centralRepo, List searchfilters, DiscoveryAttributes.AttributeType groupingAttribute, Group.GroupSortingAlgorithm groupSort, FileSorter.SortingMethod fileSortMethod) { centralRepoDb = centralRepo; filters = searchfilters; groupingAttr = groupingAttribute;