Adding more attributes

This commit is contained in:
Ann Priestman 2019-07-09 07:56:34 -04:00
parent e41f38ec28
commit 124fd325d5
7 changed files with 1165 additions and 131 deletions

View File

@ -20,3 +20,7 @@ FileSearchDialog.searchButton.text=Search
ResultsDialog.exitButton.text=Exit
ResultsDialog.searchButton.text=Run another search
FileSearchDialog.errorLabel.text=jLabel6
FileSearchDialog.hashCheckBox.text=Hash Set
FileSearchDialog.intCheckBox.text=Interesting Items
FileSearchDialog.tagsCheckBox.text=Tags
FileSearchDialog.objCheckBox.text=Objects

View File

@ -4,15 +4,23 @@ CTL_FileSearchTestAction=Test file search
FileSearch.DataSourceGroupKey.datasourceAndID={0}(ID: {1})
# {0} - Data source ID
FileSearch.DataSourceGroupKey.idOnly=Data source (ID: {0})
FileSearch.FileTagGroupKey.noSets=None
FileSearch.GroupingAttributeType.datasource.displayName=Data source
FileSearch.GroupingAttributeType.fileType.displayName=File type
FileSearch.GroupingAttributeType.frequency.displayName=Past occurrences
FileSearch.GroupingAttributeType.hash.displayName=Hash set
FileSearch.GroupingAttributeType.interestingItem.displayName=Interesting item set
FileSearch.GroupingAttributeType.keywordList.displayName=Keyword list names
FileSearch.GroupingAttributeType.none.displayName=None
FileSearch.GroupingAttributeType.object.displayName=Object detected
FileSearch.GroupingAttributeType.parent.displayName=Parent folder
FileSearch.GroupingAttributeType.size.displayName=Size
FileSearch.GroupingAttributeType.tag.displayName=File tag
FileSearch.HashHitsGroupKey.noHashHits=None
FileSearch.InterestingItemGroupKey.noSets=None
FileSearch.KeywordListGroupKey.noKeywords=None
FileSearch.NoGroupingGroupKey.allFiles=All Files
FileSearch.ObjectDetectedGroupKey.noSets=None
FileSearchData.FileSize.large.displayName=200MB-1GB
FileSearchData.FileSize.medium.displayName=50-200MB
FileSearchData.FileSize.small.displayName=1-50MB
@ -48,6 +56,7 @@ FileSearchDialog.orderSizeRadioButton.text=Group Size
FileSearchDialog.jLabel5.text=Order files by:
FileSearchDialog.parentCheckBox.text=Parent
FileSearchDialog.searchButton.text=Search
FileSearchFiltering.concatenateSetNamesForDisplay.comma=,
# {0} - Data source name
# {1} - Data source ID
FileSearchFiltering.DataSourceFilter.datasource={0}({1})
@ -60,10 +69,15 @@ FileSearchFiltering.FileTypeFilter.or=\ or
# {0} - filters
FileSearchFiltering.FrequencyFilter.desc=Files with frequency: {0}
FileSearchFiltering.FrequencyFilter.or=\ or
FileSearchFiltering.KeywordListFilter.comma=,
# {0} - filters
FileSearchFiltering.HashSetFilter.desc=Files with hash set hits in set(s): {0}
# {0} - filters
FileSearchFiltering.InterestingItemSetFilter.desc=Files with interesting item hits in set(s): {0}
# {0} - filters
FileSearchFiltering.KeywordListFilter.desc=Files with keywords in list(s): {0}
# {0} - filters
FileSearchFiltering.ObjectDetectionFilter.desc=Files with objects detected in set(s): {0}
# {0} - filters
FileSearchFiltering.ParentFilter.desc=Files with paths matching: {0}
FileSearchFiltering.ParentFilter.exact=(exact match)
FileSearchFiltering.ParentFilter.or=\ or
@ -78,6 +92,9 @@ FileSearchFiltering.SizeFilter.or=\ or
# {0} - Minimum bytes
# {1} - Maximum bytes
FileSearchFiltering.SizeFilter.range=({0} to {1})
# {0} - tag names
FileSearchFiltering.TagsFilter.desc=Files that have been tagged {0}
FileSearchFiltering.TagsFilter.or=\ or
FileSorter.SortingMethod.datasource.displayName=By data source
FileSorter.SortingMethod.filename.displayName=By file name
FileSorter.SortingMethod.filesize.displayName=By file size
@ -89,3 +106,7 @@ ResultsDialog.dialogTitle.text=File search results
ResultsDialog.exitButton.text=Exit
ResultsDialog.searchButton.text=Run another search
FileSearchDialog.errorLabel.text=jLabel6
FileSearchDialog.hashCheckBox.text=Hash Set
FileSearchDialog.intCheckBox.text=Interesting Items
FileSearchDialog.tagsCheckBox.text=Tags
FileSearchDialog.objCheckBox.text=Objects

View File

@ -42,6 +42,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.CaseDbAccessManager;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
@ -157,6 +158,10 @@ class FileSearch {
"FileSearch.GroupingAttributeType.size.displayName=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 set",
"FileSearch.GroupingAttributeType.tag.displayName=File tag",
"FileSearch.GroupingAttributeType.object.displayName=Object detected",
"FileSearch.GroupingAttributeType.none.displayName=None",
})
enum GroupingAttributeType {
@ -166,6 +171,10 @@ class FileSearch {
FILE_SIZE(new FileSizeAttribute(), Bundle.FileSearch_GroupingAttributeType_size_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;
@ -527,24 +536,11 @@ class FileSearch {
@Override
void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb,
EamDb centralRepoDb) throws FileSearchException {
// 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.getAbstractFile().getId() + "\'"; // NON-NLS
}
// Get pairs of (object ID, keyword list name) for all files in the list of files that have
// keyword list hits.
String selectQuery = "blackboard_artifacts.obj_id AS object_id, blackboard_attributes.value_text AS keyword_list_name " +
"FROM blackboard_artifacts " +
"INNER JOIN blackboard_attributes ON blackboard_artifacts.artifact_id=blackboard_attributes.artifact_id " +
"WHERE blackboard_attributes.artifact_type_id=\'" + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + "\' " +
"AND blackboard_attributes.attribute_type_id=\'" + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + "\' " +
"AND blackboard_artifacts.obj_id IN (" + objIdList + ") "; // NON-NLS
String selectQuery = createSetNameQuery(files, caseDb, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(),
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID());
SetKeywordListNamesCallback callback = new SetKeywordListNamesCallback(files);
try {
@ -583,12 +579,12 @@ class FileSearch {
while (rs.next()) {
try {
Long objId = rs.getLong("object_id"); // NON-NLS
String keywordListName = rs.getString("keyword_list_name"); // 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 keyword_list_name from result set", ex); // NON-NLS
logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS
}
}
} catch (SQLException ex) {
@ -760,23 +756,10 @@ class FileSearch {
void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb,
EamDb centralRepoDb) throws FileSearchException {
// 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.getAbstractFile().getId() + "\'"; // NON-NLS
}
// Get pairs of (object ID, keyword list name) for all files in the list of files that have
// keyword list hits.
String selectQuery = "blackboard_artifacts.obj_id AS object_id, blackboard_attributes.value_text AS hash_set_name " +
"FROM blackboard_artifacts " +
"INNER JOIN blackboard_attributes ON blackboard_artifacts.artifact_id=blackboard_attributes.artifact_id " +
"WHERE blackboard_attributes.artifact_type_id=\'" + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + "\' " +
"AND blackboard_attributes.attribute_type_id=\'" + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + "\' " +
"AND blackboard_artifacts.obj_id IN (" + objIdList + ") "; // NON-NLS
// hash set hits.
String selectQuery = createSetNameQuery(files, caseDb, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(),
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID());
SetHashSetNamesCallback callback = new SetHashSetNamesCallback(files);
try {
@ -797,7 +780,7 @@ class FileSearch {
/**
* Create the callback.
*
* @param resultFiles List of files to add keyword list names to
* @param resultFiles List of files to add hash set names to
*/
SetHashSetNamesCallback(List<ResultFile> resultFiles) {
this.resultFiles = resultFiles;
@ -815,12 +798,12 @@ class FileSearch {
while (rs.next()) {
try {
Long objId = rs.getLong("object_id"); // NON-NLS
String hashSetName = rs.getString("hash_set_name"); // 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 hash_set_name from result set", ex); // NON-NLS
logger.log(Level.SEVERE, "Unable to get object_id or set_name from result set", ex); // NON-NLS
}
}
} catch (SQLException ex) {
@ -841,7 +824,7 @@ class FileSearch {
"FileSearch.HashHitsGroupKey.noHashHits=None",
})
HashHitsGroupKey(ResultFile file) {
hashSetNames = file.getKeywordListNames();
hashSetNames = file.getHashSetNames();
if (hashSetNames.isEmpty()) {
hashSetNamesString = Bundle.FileSearch_HashHitsGroupKey_noHashHits();
@ -896,7 +879,378 @@ class FileSearch {
return Objects.hash(hashSetNamesString);
}
}
/**
* Attribute for grouping/sorting by interesting item set lists
*/
static class InterestingItemAttribute extends AttributeType {
@Override
GroupKey getGroupKey(ResultFile file) {
return new InterestingItemGroupKey(file);
}
@Override
void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb,
EamDb centralRepoDb) throws FileSearchException {
// Get pairs of (object ID, keyword list name) for all files in the list of files that have
// interesting file set hits.
String selectQuery = createSetNameQuery(files, caseDb, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID());
SetInterstingFileSetNamesCallback callback = new SetInterstingFileSetNamesCallback(files);
try {
caseDb.getCaseDbAccessManager().select(selectQuery, callback);
} catch (TskCoreException ex) {
throw new FileSearchException("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 SetInterstingFileSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
List<ResultFile> resultFiles;
/**
* Create the callback.
*
* @param resultFiles List of files to add interesting file set names to
*/
SetInterstingFileSetNamesCallback(List<ResultFile> resultFiles) {
this.resultFiles = resultFiles;
}
@Override
public void process(ResultSet rs) {
try {
// Create a temporary map of object ID to ResultFile
Map<Long, ResultFile> tempMap = new HashMap<>();
for (ResultFile file : resultFiles) {
tempMap.put(file.getAbstractFile().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
}
}
}
}
/**
* Key representing a interesting item set group
*/
private static class InterestingItemGroupKey extends GroupKey {
private final List<String> interestingItemSetNames;
private final String interestingItemSetNamesString;
@NbBundle.Messages({
"FileSearch.InterestingItemGroupKey.noSets=None",
})
InterestingItemGroupKey(ResultFile file) {
interestingItemSetNames = file.getInterestingSetNames();
if (interestingItemSetNames.isEmpty()) {
interestingItemSetNamesString = Bundle.FileSearch_InterestingItemGroupKey_noSets();
} else {
interestingItemSetNamesString = String.join(",", interestingItemSetNames); // NON-NLS
}
}
@Override
String getDisplayName() {
return interestingItemSetNamesString;
}
@Override
public int compareTo(GroupKey otherGroupKey) {
if (otherGroupKey instanceof InterestingItemGroupKey) {
InterestingItemGroupKey otherInterestingItemGroupKey = (InterestingItemGroupKey)otherGroupKey;
// Put the empty list at the end
if (this.interestingItemSetNames.isEmpty()) {
if (otherInterestingItemGroupKey.interestingItemSetNames.isEmpty()) {
return 0;
} else {
return 1;
}
} else if (otherInterestingItemGroupKey.interestingItemSetNames.isEmpty()) {
return -1;
}
return interestingItemSetNamesString.compareTo(otherInterestingItemGroupKey.interestingItemSetNamesString);
} else {
return compareClassNames(otherGroupKey);
}
}
@Override
public boolean equals(Object otherKey) {
if (otherKey == this){
return true;
}
if (!(otherKey instanceof InterestingItemGroupKey)) {
return false;
}
InterestingItemGroupKey otherInterestingItemGroupKey = (InterestingItemGroupKey)otherKey;
return interestingItemSetNamesString.equals(otherInterestingItemGroupKey.interestingItemSetNamesString);
}
@Override
public int hashCode() {
return Objects.hash(interestingItemSetNamesString);
}
}
/**
* Attribute for grouping/sorting by objects detected
*/
static class ObjectDetectedAttribute extends AttributeType {
@Override
GroupKey getGroupKey(ResultFile file) {
return new ObjectDetectedGroupKey(file);
}
@Override
void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb,
EamDb centralRepoDb) throws FileSearchException {
// Get pairs of (object ID, keyword list name) for all files in the list of files that have
// objects detected
String selectQuery = createSetNameQuery(files, caseDb, BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID(),
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID());
SetObjectDetectedNamesCallback callback = new SetObjectDetectedNamesCallback(files);
try {
caseDb.getCaseDbAccessManager().select(selectQuery, callback);
} catch (TskCoreException ex) {
throw new FileSearchException("Error looking up object detected 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 SetObjectDetectedNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
List<ResultFile> resultFiles;
/**
* Create the callback.
*
* @param resultFiles List of files to add object detected names to
*/
SetObjectDetectedNamesCallback(List<ResultFile> resultFiles) {
this.resultFiles = resultFiles;
}
@Override
public void process(ResultSet rs) {
try {
// Create a temporary map of object ID to ResultFile
Map<Long, ResultFile> tempMap = new HashMap<>();
for (ResultFile file : resultFiles) {
tempMap.put(file.getAbstractFile().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
}
}
}
}
/**
* Key representing an object detected group
*/
private static class ObjectDetectedGroupKey extends GroupKey {
private final List<String> objectDetectedNames;
private final String objectDetectedNamesString;
@NbBundle.Messages({
"FileSearch.ObjectDetectedGroupKey.noSets=None",
})
ObjectDetectedGroupKey(ResultFile file) {
objectDetectedNames = file.getObjectDetectedNames();
if (objectDetectedNames.isEmpty()) {
objectDetectedNamesString = Bundle.FileSearch_ObjectDetectedGroupKey_noSets();
} else {
objectDetectedNamesString = String.join(",", objectDetectedNames); // NON-NLS
}
}
@Override
String getDisplayName() {
return objectDetectedNamesString;
}
@Override
public int compareTo(GroupKey otherGroupKey) {
if (otherGroupKey instanceof ObjectDetectedGroupKey) {
ObjectDetectedGroupKey otherObjectDetectedGroupKey = (ObjectDetectedGroupKey)otherGroupKey;
// Put the empty list at the end
if (this.objectDetectedNames.isEmpty()) {
if (otherObjectDetectedGroupKey.objectDetectedNames.isEmpty()) {
return 0;
} else {
return 1;
}
} else if (otherObjectDetectedGroupKey.objectDetectedNames.isEmpty()) {
return -1;
}
return objectDetectedNamesString.compareTo(otherObjectDetectedGroupKey.objectDetectedNamesString);
} else {
return compareClassNames(otherGroupKey);
}
}
@Override
public boolean equals(Object otherKey) {
if (otherKey == this){
return true;
}
if (!(otherKey instanceof ObjectDetectedGroupKey)) {
return false;
}
ObjectDetectedGroupKey otherObjectDetectedGroupKey = (ObjectDetectedGroupKey)otherKey;
return objectDetectedNamesString.equals(otherObjectDetectedGroupKey.objectDetectedNamesString);
}
@Override
public int hashCode() {
return Objects.hash(objectDetectedNamesString);
}
}
/**
* Attribute for grouping/sorting by tag name
*/
static class FileTagAttribute extends AttributeType {
@Override
GroupKey getGroupKey(ResultFile file) {
return new FileTagGroupKey(file);
}
@Override
void addAttributeToResultFiles(List<ResultFile> files, SleuthkitCase caseDb,
EamDb centralRepoDb) throws FileSearchException {
try {
for (ResultFile resultFile : files) {
List<ContentTag> contentTags = caseDb.getContentTagsByContent(resultFile.getAbstractFile());
for (ContentTag tag : contentTags) {
resultFile.addTagName(tag.getName().getDisplayName());
}
}
} catch (TskCoreException ex) {
throw new FileSearchException("Error looking up file tag attributes", ex); // NON-NLS
}
}
}
/**
* Key representing a interesting item set group
*/
private static class FileTagGroupKey extends GroupKey {
private final List<String> tagNames;
private final String tagNamesString;
@NbBundle.Messages({
"FileSearch.FileTagGroupKey.noSets=None",
})
FileTagGroupKey(ResultFile file) {
tagNames = file.getTagNames();
if (tagNames.isEmpty()) {
tagNamesString = Bundle.FileSearch_FileTagGroupKey_noSets();
} else {
tagNamesString = String.join(",", tagNames); // NON-NLS
}
}
@Override
String getDisplayName() {
return tagNamesString;
}
@Override
public int compareTo(GroupKey otherGroupKey) {
if (otherGroupKey instanceof FileTagGroupKey) {
FileTagGroupKey otherFileTagGroupKey = (FileTagGroupKey)otherGroupKey;
// Put the empty list at the end
if (tagNames.isEmpty()) {
if (otherFileTagGroupKey.tagNames.isEmpty()) {
return 0;
} else {
return 1;
}
} else if (otherFileTagGroupKey.tagNames.isEmpty()) {
return -1;
}
return tagNamesString.compareTo(otherFileTagGroupKey.tagNamesString);
} else {
return compareClassNames(otherGroupKey);
}
}
@Override
public boolean equals(Object otherKey) {
if (otherKey == this){
return true;
}
if (!(otherKey instanceof FileTagGroupKey)) {
return false;
}
FileTagGroupKey otherFileTagGroupKey = (FileTagGroupKey)otherKey;
return tagNamesString.equals(otherFileTagGroupKey.tagNamesString);
}
@Override
public int hashCode() {
return Objects.hash(tagNamesString);
}
}
/**
* Default attribute used to make one group
@ -956,6 +1310,28 @@ class FileSearch {
}
}
private static String createSetNameQuery(List<ResultFile> files, SleuthkitCase caseDb,
int artifactTypeID, int setNameAttrID) throws FileSearchException {
// 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.getAbstractFile().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
}

View File

@ -66,37 +66,62 @@
<Component id="jScrollPane6" alignment="0" max="32767" attributes="0"/>
<Component id="filler1" min="-2" pref="265" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="searchButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Component id="errorLabel" alignment="0" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="filler2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="errorLabel" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="344" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel3" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabel4" min="-2" max="-2" attributes="0"/>
<Component id="jLabel5" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="29" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="orderAttrRadioButton" min="-2" max="-2" attributes="0"/>
<Component id="groupComboBox" pref="144" max="32767" attributes="0"/>
<Component id="orderSizeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="fileOrderComboBox" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="hashCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="jScrollPane7" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="intCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane8" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="tagsCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="jScrollPane9" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="objCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="jScrollPane10" max="32767" attributes="0"/>
</Group>
<Component id="filler2" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="25" max="32767" attributes="0"/>
<EmptySpace min="35" pref="35" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel3" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabel4" min="-2" max="-2" attributes="0"/>
<Component id="jLabel5" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="29" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="orderAttrRadioButton" min="-2" max="-2" attributes="0"/>
<Component id="groupComboBox" max="32767" attributes="0"/>
<Component id="orderSizeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="fileOrderComboBox" min="-2" pref="144" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -109,8 +134,29 @@
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<Component id="jScrollPane1" min="-2" pref="82" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<Component id="jScrollPane1" min="-2" pref="82" max="-2" attributes="0"/>
<Component id="jScrollPane7" alignment="0" min="-2" pref="49" max="-2" attributes="0"/>
<Component id="hashCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane10" alignment="0" min="-2" pref="49" max="-2" attributes="0"/>
<Component id="objCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane9" alignment="0" min="-2" pref="49" max="-2" attributes="0"/>
<Component id="tagsCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dsCheckBox" min="-2" max="-2" attributes="0"/>
<Component id="jScrollPane2" min="-2" pref="56" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/>
@ -123,16 +169,16 @@
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="orderSizeRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel5" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="fileOrderComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dsCheckBox" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel5" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="fileOrderComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
<Group type="103" alignment="1" groupAlignment="0" attributes="0">
<Component id="jScrollPane8" alignment="0" min="-2" pref="49" max="-2" attributes="0"/>
<Component id="intCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="jScrollPane2" min="-2" pref="56" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
@ -172,8 +218,8 @@
</Group>
<EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="searchButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="cancelButton" alignment="3" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
@ -534,5 +580,125 @@
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.RigidArea"/>
</AuxValues>
</Component>
<Component class="javax.swing.JCheckBox" name="hashCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filequery/Bundle.properties" key="FileSearchDialog.hashCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="hashCheckBoxActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane7">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="hashList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultListModel&lt;String&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JCheckBox" name="intCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filequery/Bundle.properties" key="FileSearchDialog.intCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="intCheckBoxActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane8">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="intList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultListModel&lt;String&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="jScrollPane9">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="tagsList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultListModel&lt;TagName&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;TagName&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JCheckBox" name="tagsCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filequery/Bundle.properties" key="FileSearchDialog.tagsCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tagsCheckBoxActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane10">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="objList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultListModel&lt;String&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JCheckBox" name="objCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/filequery/Bundle.properties" key="FileSearchDialog.objCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="objCheckBoxActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -26,6 +26,7 @@ import java.util.List;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.swing.DefaultListModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JList;
@ -46,6 +47,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.TagName;
/**
* Dialog to allow the user to choose filtering and grouping options.
@ -98,6 +100,11 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe
setUpKWFilter();
setUpParentPathFilter();
setUpHashFilter();
setUpInterestingItemsFilter();
setUpTagsFilter();
setUpObjectFilter();
// Set up the grouping attributes
for (GroupingAttributeType type : GroupingAttributeType.values()) {
groupComboBox.addItem(type);
@ -202,20 +209,8 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe
try {
DefaultListModel<String> kwListModel = (DefaultListModel<String>)kwList.getModel();
// TODO - create case DB query
List<BlackboardArtifact> arts = caseDb.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT);
List<String> setNames = new ArrayList<>();
for (BlackboardArtifact art : arts) {
for (BlackboardAttribute attr : art.getAttributes()) {
if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
String setName = attr.getValueString();
if ( ! setNames.contains(setName)) {
setNames.add(setName);
}
}
}
}
Collections.sort(setNames);
List<String> setNames = getSetNames(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT,
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME);
for(String name : setNames) {
kwListModel.add(count, name);
}
@ -227,6 +222,116 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe
addListeners(kwCheckBox, kwList);
}
private void setUpHashFilter() {
int count = 0;
try {
DefaultListModel<String> hashListModel = (DefaultListModel<String>)hashList.getModel();
List<String> setNames = getSetNames(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT,
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME);
for(String name : setNames) {
hashListModel.add(count, name);
count++;
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error loading hash set names", ex);
hashCheckBox.setEnabled(false);
hashList.setEnabled(false);
}
addListeners(hashCheckBox, hashList);
}
private void setUpInterestingItemsFilter() {
int count = 0;
try {
DefaultListModel<String> intListModel = (DefaultListModel<String>)intList.getModel();
List<String> setNames = getSetNames(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT,
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME);
for(String name : setNames) {
intListModel.add(count, name);
count++;
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error loading interesting file set names", ex);
intCheckBox.setEnabled(false);
intList.setEnabled(false);
}
addListeners(intCheckBox, intList);
}
private void setUpTagsFilter() {
int count = 0;
try {
DefaultListModel<TagName> tagsListModel = (DefaultListModel<TagName>)tagsList.getModel();
List<TagName> tagNames = caseDb.getTagNamesInUse();
for(TagName name : tagNames) {
//tagsListModel.add(count, name.getDisplayName());
tagsListModel.add(count, name);
count++;
}
tagsList.setCellRenderer(new TagsListCellRenderer());
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error loading tag names", ex);
tagsCheckBox.setEnabled(false);
tagsList.setEnabled(false);
}
addListeners(tagsCheckBox, tagsList);
}
private class TagsListCellRenderer extends DefaultListCellRenderer {
@Override
public java.awt.Component getListCellRendererComponent(
JList<?> list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
if (value instanceof TagName) {
value = ((TagName)value).getDisplayName();
}
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
return this;
}
}
private void setUpObjectFilter() {
int count = 0;
try {
DefaultListModel<String> objListModel = (DefaultListModel<String>)objList.getModel();
List<String> setNames = getSetNames(BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION);
for(String name : setNames) {
objListModel.add(count, name);
count++;
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error loading object detected set names", ex);
objCheckBox.setEnabled(false);
objList.setEnabled(false);
}
addListeners(objCheckBox, objList);
}
private List<String> getSetNames(BlackboardArtifact.ARTIFACT_TYPE artifactType, BlackboardAttribute.ATTRIBUTE_TYPE setNameAttribute) throws TskCoreException {
List<BlackboardArtifact> arts = caseDb.getBlackboardArtifacts(artifactType);
List<String> setNames = new ArrayList<>();
for (BlackboardArtifact art : arts) {
for (BlackboardAttribute attr : art.getAttributes()) {
if (attr.getAttributeType().getTypeID() == setNameAttribute.getTypeID()) {
String setName = attr.getValueString();
if ( ! setNames.contains(setName)) {
setNames.add(setName);
}
}
}
}
Collections.sort(setNames);
return setNames;
}
/**
* Initialize the parent path filter
*/
@ -272,6 +377,22 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe
filters.add(new FileSearchFiltering.KeywordListFilter(kwList.getSelectedValuesList()));
}
if (hashCheckBox.isSelected()) {
filters.add(new FileSearchFiltering.HashSetFilter(hashList.getSelectedValuesList()));
}
if (intCheckBox.isSelected()) {
filters.add(new FileSearchFiltering.InterestingFileSetFilter(intList.getSelectedValuesList()));
}
if (objCheckBox.isSelected()) {
filters.add(new FileSearchFiltering.ObjectDetectionFilter(objList.getSelectedValuesList()));
}
if (tagsCheckBox.isSelected()) {
filters.add(new FileSearchFiltering.TagsFilter(tagsList.getSelectedValuesList()));
}
return filters;
}
@ -385,6 +506,26 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe
return;
}
if (hashCheckBox.isSelected() && hashList.getSelectedValuesList().isEmpty()) {
setInvalid("At least one hash set name must be selected");
return;
}
if (intCheckBox.isSelected() && intList.getSelectedValuesList().isEmpty()) {
setInvalid("At least one interesting file set name must be selected");
return;
}
if (objCheckBox.isSelected() && objList.getSelectedValuesList().isEmpty()) {
setInvalid("At least one object type name must be selected");
return;
}
if (tagsCheckBox.isSelected() && tagsList.getSelectedValuesList().isEmpty()) {
setInvalid("At least one tag name must be selected");
return;
}
setValid();
}
@ -456,6 +597,18 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe
errorLabel = new javax.swing.JLabel();
filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(8, 7), new java.awt.Dimension(8, 7), new java.awt.Dimension(8, 7));
filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(265, 23), new java.awt.Dimension(265, 23), new java.awt.Dimension(265, 23));
hashCheckBox = new javax.swing.JCheckBox();
jScrollPane7 = new javax.swing.JScrollPane();
hashList = new javax.swing.JList<>();
intCheckBox = new javax.swing.JCheckBox();
jScrollPane8 = new javax.swing.JScrollPane();
intList = new javax.swing.JList<>();
jScrollPane9 = new javax.swing.JScrollPane();
tagsList = new javax.swing.JList<>();
tagsCheckBox = new javax.swing.JCheckBox();
jScrollPane10 = new javax.swing.JScrollPane();
objList = new javax.swing.JList<>();
objCheckBox = new javax.swing.JCheckBox();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
@ -580,6 +733,50 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe
errorLabel.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(FileSearchDialog.class, "FileSearchDialog.errorLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(hashCheckBox, org.openide.util.NbBundle.getMessage(FileSearchDialog.class, "FileSearchDialog.hashCheckBox.text")); // NOI18N
hashCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
hashCheckBoxActionPerformed(evt);
}
});
hashList.setModel(new DefaultListModel<String>());
hashList.setEnabled(false);
jScrollPane7.setViewportView(hashList);
org.openide.awt.Mnemonics.setLocalizedText(intCheckBox, org.openide.util.NbBundle.getMessage(FileSearchDialog.class, "FileSearchDialog.intCheckBox.text")); // NOI18N
intCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
intCheckBoxActionPerformed(evt);
}
});
intList.setModel(new DefaultListModel<String>());
intList.setEnabled(false);
jScrollPane8.setViewportView(intList);
tagsList.setModel(new DefaultListModel<TagName>());
tagsList.setEnabled(false);
jScrollPane9.setViewportView(tagsList);
org.openide.awt.Mnemonics.setLocalizedText(tagsCheckBox, org.openide.util.NbBundle.getMessage(FileSearchDialog.class, "FileSearchDialog.tagsCheckBox.text")); // NOI18N
tagsCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
tagsCheckBoxActionPerformed(evt);
}
});
objList.setModel(new DefaultListModel<String>());
objList.setEnabled(false);
jScrollPane10.setViewportView(objList);
org.openide.awt.Mnemonics.setLocalizedText(objCheckBox, org.openide.util.NbBundle.getMessage(FileSearchDialog.class, "FileSearchDialog.objCheckBox.text")); // NOI18N
objCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
objCheckBoxActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
@ -615,30 +812,50 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe
.addComponent(jScrollPane5)
.addComponent(jScrollPane6, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, 265, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGap(18, 18, 18)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(searchButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton))
.addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(cancelButton)
.addContainerGap())
.addGroup(layout.createSequentialGroup()
.addComponent(filler2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGap(344, 344, 344))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel3)
.addComponent(jLabel4)
.addComponent(jLabel5))
.addGap(29, 29, 29)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(orderAttrRadioButton)
.addComponent(groupComboBox, 0, 144, Short.MAX_VALUE)
.addComponent(orderSizeRadioButton)
.addComponent(fileOrderComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addComponent(filler2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 25, Short.MAX_VALUE)))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(hashCheckBox)
.addGap(18, 18, 18)
.addComponent(jScrollPane7))
.addGroup(layout.createSequentialGroup()
.addComponent(intCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane8))
.addGroup(layout.createSequentialGroup()
.addComponent(tagsCheckBox)
.addGap(18, 18, 18)
.addComponent(jScrollPane9))
.addGroup(layout.createSequentialGroup()
.addComponent(objCheckBox)
.addGap(18, 18, 18)
.addComponent(jScrollPane10)))
.addGap(35, 35, 35)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel3)
.addComponent(jLabel4)
.addComponent(jLabel5))
.addGap(29, 29, 29)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(orderAttrRadioButton)
.addComponent(groupComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(orderSizeRadioButton)
.addComponent(fileOrderComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 144, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap())))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -648,8 +865,24 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe
.addComponent(filler2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel1)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel1)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jScrollPane7, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(hashCheckBox))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane10, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(objCheckBox))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane9, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(tagsCheckBox))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dsCheckBox)
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel3)
@ -659,14 +892,14 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe
.addComponent(jLabel4)
.addComponent(orderAttrRadioButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(orderSizeRadioButton)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dsCheckBox)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel5)
.addComponent(fileOrderComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(orderSizeRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel5)
.addComponent(fileOrderComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane8, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(intCheckBox)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(freqCheckBox)
@ -698,8 +931,8 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe
.addComponent(errorLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cancelButton)
.addComponent(searchButton))
.addComponent(searchButton)
.addComponent(cancelButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
@ -767,6 +1000,22 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe
setVisible(false);
}//GEN-LAST:event_searchButtonActionPerformed
private void hashCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hashCheckBoxActionPerformed
hashList.setEnabled(hashCheckBox.isSelected());
}//GEN-LAST:event_hashCheckBoxActionPerformed
private void intCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_intCheckBoxActionPerformed
intList.setEnabled(intCheckBox.isSelected());
}//GEN-LAST:event_intCheckBoxActionPerformed
private void tagsCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tagsCheckBoxActionPerformed
tagsList.setEnabled(tagsCheckBox.isSelected());
}//GEN-LAST:event_tagsCheckBoxActionPerformed
private void objCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_objCheckBoxActionPerformed
objList.setEnabled(objCheckBox.isSelected());
}//GEN-LAST:event_objCheckBoxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton addParentButton;
private javax.swing.JButton cancelButton;
@ -781,19 +1030,29 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe
private javax.swing.JCheckBox freqCheckBox;
private javax.swing.JList<Frequency> freqList;
private javax.swing.JComboBox<GroupingAttributeType> groupComboBox;
private javax.swing.JCheckBox hashCheckBox;
private javax.swing.JList<String> hashList;
private javax.swing.JCheckBox intCheckBox;
private javax.swing.JList<String> intList;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JLabel jLabel4;
private javax.swing.JLabel jLabel5;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane10;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JScrollPane jScrollPane3;
private javax.swing.JScrollPane jScrollPane4;
private javax.swing.JScrollPane jScrollPane5;
private javax.swing.JScrollPane jScrollPane6;
private javax.swing.JScrollPane jScrollPane7;
private javax.swing.JScrollPane jScrollPane8;
private javax.swing.JScrollPane jScrollPane9;
private javax.swing.JCheckBox kwCheckBox;
private javax.swing.JList<String> kwList;
private javax.swing.JCheckBox objCheckBox;
private javax.swing.JList<String> objList;
private javax.swing.JRadioButton orderAttrRadioButton;
private javax.swing.ButtonGroup orderButtonGroup;
private javax.swing.JRadioButton orderSizeRadioButton;
@ -806,5 +1065,7 @@ public class FileSearchDialog extends javax.swing.JDialog implements ActionListe
private javax.swing.JButton searchButton;
private javax.swing.JCheckBox sizeCheckBox;
private javax.swing.JList<FileSize> sizeList;
private javax.swing.JCheckBox tagsCheckBox;
private javax.swing.JList<TagName> tagsList;
// End of variables declaration//GEN-END:variables
}

View File

@ -30,12 +30,15 @@ import org.sleuthkit.autopsy.filequery.FileSearchData.Frequency;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
/**
* Run various filters to return a subset of files from the current case.
@ -381,13 +384,7 @@ class FileSearchFiltering {
@Override
String getWhereClause() {
String keywordListPart = ""; // NON-NLS
for (String listName : listNames) {
if (! keywordListPart.isEmpty()) {
keywordListPart += " OR "; // NON-NLS
}
keywordListPart += "value_text = \'" + listName + "\'"; // TODO - these should really be prepared statements // NON-NLS
}
String keywordListPart = concatenateNamesForSQL(listNames);
String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN " +
"(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = 9 AND attribute_type_ID = 37 " +
@ -399,19 +396,10 @@ class FileSearchFiltering {
@NbBundle.Messages({
"# {0} - filters",
"FileSearchFiltering.KeywordListFilter.desc=Files with keywords in list(s): {0}",
"FileSearchFiltering.KeywordListFilter.comma=, ",
})
@Override
String getDesc() {
String desc = ""; // NON-NLS
for (String listName : listNames) {
if ( ! desc.isEmpty()) {
desc += Bundle.FileSearchFiltering_KeywordListFilter_comma();
}
desc += listName;
}
desc = Bundle.FileSearchFiltering_KeywordListFilter_desc(desc);
return desc;
return Bundle.FileSearchFiltering_KeywordListFilter_desc(concatenateSetNamesForDisplay(listNames));
}
}
@ -543,6 +531,198 @@ class FileSearchFiltering {
}
}
/**
* A filter for specifying hash set names.
* A file must match one of the given sets to pass.
*/
static class HashSetFilter extends FileFilter {
private final List<String> setNames;
/**
* Create the HashSetFilter
* @param setNames
*/
HashSetFilter(List<String> setNames) {
this.setNames = setNames;
}
@Override
String getWhereClause() {
String hashSetPart = concatenateNamesForSQL(setNames);
String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN " +
"(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() +
" AND attribute_type_ID = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " +
"AND (" + hashSetPart + "))))"; // NON-NLS
return queryStr;
}
@NbBundle.Messages({
"# {0} - filters",
"FileSearchFiltering.HashSetFilter.desc=Files with hash set hits in set(s): {0}",
})
@Override
String getDesc() {
return Bundle.FileSearchFiltering_HashSetFilter_desc(concatenateSetNamesForDisplay(setNames));
}
}
/**
* A filter for specifying interesting file set names.
* A file must match one of the given sets to pass.
*/
static class InterestingFileSetFilter extends FileFilter {
private final List<String> setNames;
/**
* Create the InterestingFileSetFilter
* @param setNames
*/
InterestingFileSetFilter(List<String> setNames) {
this.setNames = setNames;
}
@Override
String getWhereClause() {
String intItemSetPart = concatenateNamesForSQL(setNames);
String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN " +
"(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() +
" AND attribute_type_ID = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " +
"AND (" + intItemSetPart + "))))"; // NON-NLS
return queryStr;
}
@NbBundle.Messages({
"# {0} - filters",
"FileSearchFiltering.InterestingItemSetFilter.desc=Files with interesting item hits in set(s): {0}",
})
@Override
String getDesc() {
return Bundle.FileSearchFiltering_InterestingItemSetFilter_desc(concatenateSetNamesForDisplay(setNames));
}
}
/**
* A filter for specifying object types detected.
* A file must match one of the given types to pass.
*/
static class ObjectDetectionFilter extends FileFilter {
private final List<String> typeNames;
/**
* Create the ObjectDetectionFilter
* @param typeNames
*/
ObjectDetectionFilter(List<String> typeNames) {
this.typeNames = typeNames;
}
@Override
String getWhereClause() {
String objTypePart = concatenateNamesForSQL(typeNames);
String queryStr = "(obj_id IN (SELECT obj_id from blackboard_artifacts WHERE artifact_id IN " +
"(SELECT artifact_id FROM blackboard_attributes WHERE artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID() +
" AND attribute_type_ID = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID() + " " +
"AND (" + objTypePart + "))))"; // NON-NLS
return queryStr;
}
@NbBundle.Messages({
"# {0} - filters",
"FileSearchFiltering.ObjectDetectionFilter.desc=Files with objects detected in set(s): {0}",
})
@Override
String getDesc() {
return Bundle.FileSearchFiltering_ObjectDetectionFilter_desc(concatenateSetNamesForDisplay(typeNames));
}
}
/**
* A filter for specifying tag names.
* A file must contain one of the given tags to pass.
*/
static class TagsFilter extends FileFilter {
private final List<TagName> tagNames;
/**
* Create the TagsFilter
* @param tagNames
*/
TagsFilter(List<TagName> tagNames) {
this.tagNames = tagNames;
}
@Override
String getWhereClause() {
String tagIDs = ""; // NON-NLS
for (TagName tagName : tagNames) {
if (! tagIDs.isEmpty()) {
tagIDs += ",";
}
tagIDs += tagName.getId();
}
String queryStr = "(obj_id IN (SELECT obj_id FROM content_tags WHERE tag_name_id IN (" + tagIDs + ")))";
return queryStr;
}
@NbBundle.Messages({
"# {0} - tag names",
"FileSearchFiltering.TagsFilter.desc=Files that have been tagged {0}",
"FileSearchFiltering.TagsFilter.or= or ",
})
@Override
String getDesc() {
String desc = ""; // NON-NLS
for (TagName name : tagNames) {
if ( ! desc.isEmpty()) {
desc += Bundle.FileSearchFiltering_TagsFilter_or();
}
desc += name.getDisplayName();
}
return Bundle.FileSearchFiltering_TagsFilter_desc(desc); // Nope
}
}
@NbBundle.Messages({
"FileSearchFiltering.concatenateSetNamesForDisplay.comma=, ",
})
private static String concatenateSetNamesForDisplay(List<String> setNames) {
String desc = ""; // NON-NLS
for (String setName : setNames) {
if ( ! desc.isEmpty()) {
desc += Bundle.FileSearchFiltering_concatenateSetNamesForDisplay_comma();
}
desc += setName;
}
return desc;
}
/**
* Concatenate the set names into an "OR" separated list.
* This does not do any SQL-escaping.
*
* @param setNames
*
* @return the list to use in the SQL query
*/
private static String concatenateNamesForSQL(List<String> setNames) {
String result = ""; // NON-NLS
for (String setName : setNames) {
if (! result.isEmpty()) {
result += " OR "; // NON-NLS
}
result += "value_text = \'" + setName + "\'"; // NON-NLS
}
return result;
}
private FileSearchFiltering() {
// Class should not be instantiated
}

View File

@ -36,6 +36,7 @@ class ResultFile {
private final List<String> hashSetNames;
private final List<String> tagNames;
private final List<String> interestingSetNames;
private final List<String> objectDetectedNames;
private FileType fileType;
/**
@ -47,9 +48,11 @@ class ResultFile {
this.abstractFile = abstractFile;
this.frequency = FileSearchData.Frequency.UNKNOWN;
keywordListNames = new ArrayList<>();
hashSetNames = new ArrayList();
tagNames = new ArrayList();
interestingSetNames = new ArrayList();
hashSetNames = new ArrayList<>();
tagNames = new ArrayList<>();
interestingSetNames = new ArrayList<>();
objectDetectedNames = new ArrayList<>();
fileType = FileType.OTHER;
}
@ -159,7 +162,7 @@ class ResultFile {
}
/**
* Add a hash set name that matched this file.
* Add an interesting file set name that matched this file.
*
* @param interestingSetName
*/
@ -181,6 +184,29 @@ class ResultFile {
return interestingSetNames;
}
/**
* Add an object detected in this file.
*
* @param objectDetectedName
*/
void addObjectDetectedName (String objectDetectedName) {
if (! objectDetectedNames.contains(objectDetectedName)) {
objectDetectedNames.add(objectDetectedName);
}
// Sort the list so the getObjectDetectedNames() will be consistent regardless of the order added
Collections.sort(objectDetectedNames);
}
/**
* Get the objects detected for this file
*
* @return the objects detected in this file.
*/
List<String> getObjectDetectedNames() {
return objectDetectedNames;
}
/**
* Get the AbstractFile
*