desired tree now works, except for the extra layer at the predefined regexps.

This commit is contained in:
Brian Carrier 2017-03-24 09:49:11 -04:00
parent 7fd6536182
commit cb111c22a3
3 changed files with 137 additions and 126 deletions

View File

@ -91,7 +91,7 @@ public interface DisplayableItemNodeVisitor<T> {
T visit(KeywordHits.TermNode khmln);
T visit(KeywordHits.InstanceNode khmln);
T visit(KeywordHits.RegExpInstanceNode khmln);
T visit(HashsetHits.RootNode hhrn);
@ -284,7 +284,7 @@ public interface DisplayableItemNodeVisitor<T> {
}
@Override
public T visit(KeywordHits.InstanceNode khsn) {
public T visit(KeywordHits.RegExpInstanceNode khsn) {
return defaultVisit(khsn);
}

View File

@ -70,6 +70,12 @@ public class KeywordHits implements AutopsyVisitableItem {
this.skCase = skCase;
keywordResults = new KeywordResults();
}
/* All of these maps and code assume the following:
* Regexps will have an 'instance' layer that shows the specific words that matched the regexp
* Exact match and substring will not have the instance layer and instead will have the specific hits
* below their term.
*/
private final class KeywordResults extends Observable {
@ -172,7 +178,9 @@ public class KeywordHits implements AutopsyVisitableItem {
String listName = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()));
String word = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()));
String reg = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()));
// new in 4.4
String kwType = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()));
// part of a list
if (listName != null) {
// get or create list entry
@ -181,14 +189,30 @@ public class KeywordHits implements AutopsyVisitableItem {
}
Map<String, Map<String, Set<Long>>> listMap = listsMap.get(listName);
if (reg != null) {
// substring, treated same as exact match
// Enum for "1" is defined in KeywordSearch.java
if ((kwType != null) && (kwType.equals("1"))) {
// original term should be stored in reg
if (reg != null) {
addExactMatchToList(listMap, reg, id);
} else {
addExactMatchToList(listMap, word, id);
}
}
else if (reg != null) {
addRegExpToList(listMap, reg, word, id);
} else {
addExactMatchToList(listMap, word, id);
}
} // regular expression, single term
else if (reg != null) {
addRegExpToList(regexMap, reg, word, id);
// substring is treated same as exact
if ((kwType != null) && (kwType.equals("1"))) {
// original term should be stored in reg
addExactMatchToList(literalMap, reg, id);
} else {
addRegExpToList(regexMap, reg, word, id);
}
} // literal, single term
else {
addExactMatchToList(literalMap, word, id);
@ -203,35 +227,43 @@ public class KeywordHits implements AutopsyVisitableItem {
@SuppressWarnings("deprecation")
public void update() {
// maps Artifact ID to map of attribute types to attribute values
Map<Long, Map<Long, String>> artifactIds = new LinkedHashMap<>();
if (skCase == null) {
return;
}
// query attributes table for the ones that we need for the tree
int setId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
int wordId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID();
int regexId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID();
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID();
String query = "SELECT blackboard_attributes.value_text,blackboard_attributes.artifact_id," //NON-NLS
String query = "SELECT blackboard_attributes.value_text,blackboard_attributes.value_int32,"
+ "blackboard_attributes.artifact_id," //NON-NLS
+ "blackboard_attributes.attribute_type_id FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
+ "(blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id AND " //NON-NLS
+ "blackboard_artifacts.artifact_type_id=" + artId //NON-NLS
+ ") AND (attribute_type_id=" + setId + " OR " //NON-NLS
+ "attribute_type_id=" + wordId + " OR " //NON-NLS
+ "attribute_type_id=" + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID() + " OR " //NON-NLS
+ "attribute_type_id=" + regexId + ")"; //NON-NLS
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
ResultSet resultSet = dbQuery.getResultSet();
while (resultSet.next()) {
String value = resultSet.getString("value_text"); //NON-NLS
String valueStr = resultSet.getString("value_text"); //NON-NLS
long artifactId = resultSet.getLong("artifact_id"); //NON-NLS
long typeId = resultSet.getLong("attribute_type_id"); //NON-NLS
if (!artifactIds.containsKey(artifactId)) {
artifactIds.put(artifactId, new LinkedHashMap<Long, String>());
}
if (!value.equals("")) {
artifactIds.get(artifactId).put(typeId, value);
if (valueStr != null && !valueStr.equals("")) {
artifactIds.get(artifactId).put(typeId, valueStr);
} else {
// Keyword Search Type is an int
Long valueLong = resultSet.getLong("value_int32");
artifactIds.get(artifactId).put(typeId, valueLong.toString());
}
}
} catch (TskCoreException | SQLException ex) {
@ -290,6 +322,9 @@ public class KeywordHits implements AutopsyVisitableItem {
}
}
/**
* Creates the list nodes
*/
private class ListFactory extends ChildFactory.Detachable<String> implements Observer {
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@ -380,6 +415,9 @@ public class KeywordHits implements AutopsyVisitableItem {
}
}
/**
* Represents the keyword search lists (or default groupings if list was not given)
*/
public class ListNode extends DisplayableItemNode implements Observer {
private final String listName;
@ -447,6 +485,9 @@ public class KeywordHits implements AutopsyVisitableItem {
}
}
/**
* Creates the nodes that represent search terms
*/
private class TermFactory extends ChildFactory.Detachable<String> implements Observer {
private final String setName;
@ -483,13 +524,16 @@ public class KeywordHits implements AutopsyVisitableItem {
}
}
/**
* Represents the search term or regexp that user searched for
*/
public class TermNode extends DisplayableItemNode implements Observer {
private final String setName;
private final String keyword;
public TermNode(String setName, String keyword) {
super(Children.create(new InstancesFactory(setName, keyword), true), Lookups.singleton(keyword));
super(Children.create(new RegExpInstancesFactory(setName, keyword), true), Lookups.singleton(keyword));
super.setName(keyword);
this.setName = setName;
this.keyword = keyword;
@ -563,15 +607,15 @@ public class KeywordHits implements AutopsyVisitableItem {
// as they keys for different types of nodes at the
// same level. Probably a better way to do this, but
// it works.
class InstanceKey {
private boolean isRegExp;
class RegExpInstanceKey {
private final boolean isRegExp;
private String strKey;
private Long longKey;
public InstanceKey(String key) {
public RegExpInstanceKey(String key) {
isRegExp = true;
strKey = key;
}
public InstanceKey(Long key) {
public RegExpInstanceKey(Long key) {
isRegExp = false;
longKey = key;
}
@ -586,11 +630,14 @@ public class KeywordHits implements AutopsyVisitableItem {
}
}
public class InstancesFactory extends ChildFactory.Detachable<InstanceKey> implements Observer {
/**
* Creates the nodes for a given regexp that represent the specific terms that were found
*/
public class RegExpInstancesFactory extends ChildFactory.Detachable<RegExpInstanceKey> implements Observer {
private final String keyword;
private final String setName;
public InstancesFactory(String setName, String keyword) {
public RegExpInstancesFactory(String setName, String keyword) {
super();
this.setName = setName;
this.keyword = keyword;
@ -607,18 +654,18 @@ public class KeywordHits implements AutopsyVisitableItem {
}
@Override
protected boolean createKeys(List<InstanceKey> list) {
protected boolean createKeys(List<RegExpInstanceKey> list) {
List <String>instances = keywordResults.getKeywordInstances(setName, keyword);
// The keys are different depending on what we are displaying.
// regexp get another layer to show instances.
// Exact matches don't.
if ((instances.size() == 1) && (instances.get(0).equals(DUMMY_INSTANCE))) {
for (Long id : keywordResults.getArtifactIds(setName, keyword, DUMMY_INSTANCE) ) {
list.add(new InstanceKey(id));
list.add(new RegExpInstanceKey(id));
}
} else {
for (String instance : instances) {
list.add(new InstanceKey(instance));
list.add(new RegExpInstanceKey(instance));
}
}
@ -626,62 +673,13 @@ public class KeywordHits implements AutopsyVisitableItem {
}
@Override
protected Node createNodeForKey(InstanceKey key) {
//
protected Node createNodeForKey(RegExpInstanceKey key) {
// if it isn't not a regexp, then skip the 'instance' layer of the tree
if (key.isRegExp() == false) {
// COPY AND PASTED from below,
// TODO make single method
if (skCase == null) {
return null;
}
Long artifactId = key.getIdKey();
try {
BlackboardArtifact art = skCase.getBlackboardArtifact(artifactId);
BlackboardArtifactNode n = new BlackboardArtifactNode(art);
AbstractFile file;
try {
file = skCase.getAbstractFileById(art.getObjectID());
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren"); //NON-NLS
return n;
}
// It is possible to get a keyword hit on artifacts generated
// for the underlying image in which case MAC times are not
// available/applicable/useful.
if (file == null) {
return n;
}
n.addNodeProperty(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.modTime.name"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.modTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.modTime.desc"),
ContentUtils.getStringTime(file.getMtime(), file)));
n.addNodeProperty(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.accessTime.name"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.accessTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.accessTime.desc"),
ContentUtils.getStringTime(file.getAtime(), file)));
n.addNodeProperty(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.chgTime.name"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.chgTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.chgTime.desc"),
ContentUtils.getStringTime(file.getCtime(), file)));
return n;
} catch (TskException ex) {
logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
}
return null;
return createBlackboardArtifactNode(key.getIdKey());
} else {
return new RegExpInstanceNode(setName, keyword, key.getRegExpKey());
}
return new InstanceNode(setName, keyword, key.getRegExpKey());
}
@Override
@ -691,13 +689,16 @@ public class KeywordHits implements AutopsyVisitableItem {
}
public class InstanceNode extends DisplayableItemNode implements Observer {
/**
* Represents a specific term that was found from a regexp
*/
public class RegExpInstanceNode extends DisplayableItemNode implements Observer {
private final String setName;
private final String keyword;
private final String instance;
public InstanceNode(String setName, String keyword, String instance) {
public RegExpInstanceNode(String setName, String keyword, String instance) {
super(Children.create(new HitsFactory(setName, keyword, instance), true), Lookups.singleton(keyword));
super.setName(keyword);
this.setName = setName;
@ -756,7 +757,65 @@ public class KeywordHits implements AutopsyVisitableItem {
}
}
/**
* Create a blackboard node for the given Keyword Hit artifact
* @param artifactId
* @return Node or null on error
*/
private BlackboardArtifactNode createBlackboardArtifactNode (Long artifactId) {
if (skCase == null) {
return null;
}
try {
BlackboardArtifact art = skCase.getBlackboardArtifact(artifactId);
BlackboardArtifactNode n = new BlackboardArtifactNode(art);
AbstractFile file;
try {
file = skCase.getAbstractFileById(art.getObjectID());
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren"); //NON-NLS
return n;
}
// It is possible to get a keyword hit on artifacts generated
// for the underlying image in which case MAC times are not
// available/applicable/useful.
if (file == null) {
return n;
}
n.addNodeProperty(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.modTime.name"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.modTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.modTime.desc"),
ContentUtils.getStringTime(file.getMtime(), file)));
n.addNodeProperty(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.accessTime.name"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.accessTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.accessTime.desc"),
ContentUtils.getStringTime(file.getAtime(), file)));
n.addNodeProperty(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.chgTime.name"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.chgTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.chgTime.desc"),
ContentUtils.getStringTime(file.getCtime(), file)));
return n;
} catch (TskException ex) {
logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
}
return null;
}
/**
* Creates nodes for individual files that had hits
*/
public class HitsFactory extends ChildFactory.Detachable<Long> implements Observer {
private final String keyword;
@ -788,56 +847,7 @@ public class KeywordHits implements AutopsyVisitableItem {
@Override
protected Node createNodeForKey(Long artifactId) {
// TODO Move to private method that can be used
// with copy and pasted code above
if (skCase == null) {
return null;
}
try {
BlackboardArtifact art = skCase.getBlackboardArtifact(artifactId);
BlackboardArtifactNode n = new BlackboardArtifactNode(art);
AbstractFile file;
try {
file = skCase.getAbstractFileById(art.getObjectID());
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren"); //NON-NLS
return n;
}
// It is possible to get a keyword hit on artifacts generated
// for the underlying image in which case MAC times are not
// available/applicable/useful.
if (file == null) {
return n;
}
n.addNodeProperty(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.modTime.name"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.modTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.modTime.desc"),
ContentUtils.getStringTime(file.getMtime(), file)));
n.addNodeProperty(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.accessTime.name"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.accessTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.accessTime.desc"),
ContentUtils.getStringTime(file.getAtime(), file)));
n.addNodeProperty(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.chgTime.name"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.chgTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.chgTime.desc"),
ContentUtils.getStringTime(file.getCtime(), file)));
return n;
} catch (TskException ex) {
logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
}
return null;
return createBlackboardArtifactNode(artifactId);
}
@Override

View File

@ -42,8 +42,9 @@ public class KeywordSearch {
private static final Logger TIKA_LOGGER = Logger.getLogger("Tika"); //NON-NLS
private static final org.sleuthkit.autopsy.coreutils.Logger logger = org.sleuthkit.autopsy.coreutils.Logger.getLogger(Case.class.getName());
// @@@ We should move this into TskData (or somewhere) because we are using
// this value in the results tree to display substring differently from regexp (KeywordHit.java)
public enum QueryType {
LITERAL, SUBSTRING, REGEX
};
public static final String NUM_FILES_CHANGE_EVT = "NUM_FILES_CHANGE_EVT"; //NON-NLS