interim commit of refresh updates in tree. Still need to do interestingitems.

This commit is contained in:
Brian Carrier 2014-05-05 01:07:58 -04:00
parent b37615e581
commit 33b463cd16
17 changed files with 1224 additions and 545 deletions

View File

@ -50,13 +50,13 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
protected void refreshDirectoryTree() {
// The way the "directory tree" currently works, a new tags sub-tree
// needs to be made to reflect the results of invoking tag Actions. The
// way to do this is to call DirectoryTreeTopComponent.refreshTree(),
// way to do this is to call DirectoryTreeTopComponent.refreshResultsTree(),
// which calls RootContentChildren.refreshKeys(BlackboardArtifact.ARTIFACT_TYPE... types)
// for the RootContentChildren object that is the child factory for the
// ResultsNode that is the root of the tags sub-tree. There is a switch
// statement in RootContentChildren.refreshKeys() that maps both
// BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE and BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT
// to making a call to refreshKey(TagsNodeKey).
DirectoryTreeTopComponent.findInstance().refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
DirectoryTreeTopComponent.findInstance().refreshResultsTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
}
}

View File

@ -22,7 +22,6 @@ import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children.Keys;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.Directory;
@ -119,8 +118,8 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
static class CreateAutopsyNodeVisitor extends AutopsyItemVisitor.Default<AbstractNode> {
@Override
public ExtractedContentNode visit(ExtractedContent ec) {
return new ExtractedContentNode(ec.getSleuthkitCase());
public ExtractedContent.RootNode visit(ExtractedContent ec) {
return ec.new RootNode(ec.getSleuthkitCase());
}
@Override
@ -145,22 +144,22 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
@Override
public AbstractNode visit(KeywordHits kh) {
return kh.new KeywordHitsRootNode();
return kh.new RootNode();
}
@Override
public AbstractNode visit(HashsetHits hh) {
return hh.new HashsetHitsRootNode();
return hh.new RootNode();
}
@Override
public AbstractNode visit(InterestingHits ih) {
return ih.new InterestingHitsRootNode();
return ih.new RootNode();
}
@Override
public AbstractNode visit(EmailExtracted ee) {
return ee.new EmailExtractedRootNode();
return ee.new RootNode();
}
@Override

View File

@ -19,8 +19,6 @@
package org.sleuthkit.autopsy.datamodel;
/**
*
* @author dfickling
*/
interface AutopsyItemVisitor<T> {

View File

@ -41,8 +41,8 @@ import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException;
/**
* Node wrapping a blackboard artifact object. This represents a single artifact.
* Its parent is typically an ArtifactTypeNode.
* Node wrapping a blackboard artifact object. This is generated from several
* places in the tree.
*/
public class BlackboardArtifactNode extends DisplayableItemNode {

View File

@ -20,18 +20,8 @@ package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode;
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedAccountNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedFolderNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedRootNode;
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode;
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode;
import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsRootNode;
import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode;
import org.sleuthkit.autopsy.datamodel.InterestingHits.InterestingHitsRootNode;
import org.sleuthkit.autopsy.datamodel.InterestingHits.InterestingHitsSetNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsKeywordNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsListNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode;
/**
@ -49,9 +39,9 @@ public interface DisplayableItemNodeVisitor<T> {
T visit(BlackboardArtifactNode ban);
T visit(ArtifactTypeNode atn);
T visit(ExtractedContent.TypeNode atn);
T visit(ExtractedContentNode ecn);
T visit(ExtractedContent.RootNode ecn);
T visit(FileTypeNode fsfn);
@ -69,27 +59,27 @@ public interface DisplayableItemNodeVisitor<T> {
T visit(RecentFilesFilterNode rffn);
T visit(KeywordHitsRootNode khrn);
T visit(KeywordHits.RootNode khrn);
T visit(KeywordHitsListNode khsn);
T visit(KeywordHits.ListNode khsn);
T visit(KeywordHitsKeywordNode khmln);
T visit(KeywordHits.TermNode khmln);
T visit(HashsetHitsRootNode hhrn);
T visit(HashsetHits.RootNode hhrn);
T visit(HashsetHitsSetNode hhsn);
T visit(HashsetHits.HashsetNameNode hhsn);
T visit(EmailExtractedRootNode eern);
T visit(EmailExtracted.RootNode eern);
T visit(EmailExtractedAccountNode eean);
T visit(EmailExtracted.AccountNode eean);
T visit(EmailExtractedFolderNode eefn);
T visit(EmailExtracted.FolderNode eefn);
T visit(TagsNode node);
T visit(InterestingHitsRootNode ihrn);
T visit(InterestingHits.RootNode ihrn);
T visit(InterestingHitsSetNode ihsn);
T visit(InterestingHits.SetNameNode ihsn);
T visit(TagNameNode node);
@ -155,12 +145,12 @@ public interface DisplayableItemNodeVisitor<T> {
}
@Override
public T visit(ArtifactTypeNode atn) {
public T visit(ExtractedContent.TypeNode atn) {
return defaultVisit(atn);
}
@Override
public T visit(ExtractedContentNode ecn) {
public T visit(ExtractedContent.RootNode ecn) {
return defaultVisit(ecn);
}
@ -205,17 +195,17 @@ public interface DisplayableItemNodeVisitor<T> {
}
@Override
public T visit(KeywordHitsRootNode khrn) {
public T visit(KeywordHits.RootNode khrn) {
return defaultVisit(khrn);
}
@Override
public T visit(KeywordHitsListNode khsn) {
public T visit(KeywordHits.ListNode khsn) {
return defaultVisit(khsn);
}
@Override
public T visit(KeywordHitsKeywordNode khmln) {
public T visit(KeywordHits.TermNode khmln) {
return defaultVisit(khmln);
}
@ -235,37 +225,37 @@ public interface DisplayableItemNodeVisitor<T> {
}
@Override
public T visit(HashsetHitsRootNode hhrn) {
public T visit(HashsetHits.RootNode hhrn) {
return defaultVisit(hhrn);
}
@Override
public T visit(HashsetHitsSetNode hhsn) {
public T visit(HashsetHits.HashsetNameNode hhsn) {
return defaultVisit(hhsn);
}
@Override
public T visit(InterestingHitsRootNode ihrn) {
public T visit(InterestingHits.RootNode ihrn) {
return defaultVisit(ihrn);
}
@Override
public T visit(InterestingHitsSetNode ihsn) {
public T visit(InterestingHits.SetNameNode ihsn) {
return defaultVisit(ihsn);
}
@Override
public T visit(EmailExtractedRootNode eern) {
public T visit(EmailExtracted.RootNode eern) {
return defaultVisit(eern);
}
@Override
public T visit(EmailExtractedAccountNode eean) {
public T visit(EmailExtracted.AccountNode eean) {
return defaultVisit(eean);
}
@Override
public T visit(EmailExtractedFolderNode eefn) {
public T visit(EmailExtracted.FolderNode eefn) {
return defaultVisit(eefn);
}

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
@ -25,6 +27,9 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import java.util.logging.Level;
import org.openide.util.NbBundle;
@ -34,11 +39,14 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskException;
/**
* Support for TSK_EMAIL_MSG nodes and displaying emails in the directory tree
* Email messages are grouped into parent folders, and the folders are grouped
@ -54,64 +62,85 @@ public class EmailExtracted implements AutopsyVisitableItem {
private static final String MAIL_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text");
private static final String MAIL_PATH_SEPARATOR = "/";
private SleuthkitCase skCase;
private Map<String, Map<String, List<Long>>> accounts;
private EmailResults emailResults;
public EmailExtracted(SleuthkitCase skCase) {
this.skCase = skCase;
accounts = new LinkedHashMap<>();
emailResults = new EmailResults();
}
@SuppressWarnings("deprecation")
private void initArtifacts() {
accounts.clear();
try {
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID();
int pathAttrId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID();
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS
+ "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
+ "attribute_type_id=" + pathAttrId //NON-NLS
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
ResultSet rs = skCase.runQuery(query);
while (rs.next()) {
final String path = rs.getString("value_text"); //NON-NLS
final long artifactId = rs.getLong("artifact_id"); //NON-NLS
final Map<String, String> parsedPath = parsePath(path);
final String account = parsedPath.get(MAIL_ACCOUNT);
final String folder = parsedPath.get(MAIL_FOLDER);
Map<String, List<Long>> folders = accounts.get(account);
if (folders == null) {
folders = new LinkedHashMap<>();
accounts.put(account, folders);
}
List<Long> messages = folders.get(folder);
if (messages == null) {
messages = new ArrayList<>();
folders.put(folder, messages);
}
messages.add(artifactId);
}
skCase.closeRunQuery(rs);
} catch (SQLException ex) {
logger.log(Level.WARNING, "Cannot initialize email extraction", ex); //NON-NLS
private final class EmailResults extends Observable {
private Map<String, Map<String, List<Long>>> accounts = new LinkedHashMap<>();
EmailResults() {
update();
}
}
public Set<String> getAccounts() {
return accounts.keySet();
}
public Set<String> getFolders(String account) {
return accounts.get(account).keySet();
}
public List<Long> getArtifactIds(String account, String folder) {
return accounts.get(account).get(folder);
}
public void update() {
accounts.clear();
try {
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID();
int pathAttrId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID();
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS
+ "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
+ "attribute_type_id=" + pathAttrId //NON-NLS
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
ResultSet rs = skCase.runQuery(query);
while (rs.next()) {
final String path = rs.getString("value_text"); //NON-NLS
final long artifactId = rs.getLong("artifact_id"); //NON-NLS
final Map<String, String> parsedPath = parsePath(path);
final String account = parsedPath.get(MAIL_ACCOUNT);
final String folder = parsedPath.get(MAIL_FOLDER);
private static Map<String, String> parsePath(String path) {
Map<String, String> parsed = new HashMap<>();
String[] split = path.split(MAIL_PATH_SEPARATOR);
if (split.length < 4) {
logger.log(Level.WARNING, "Unexpected number of tokens when parsing email PATH: {0}, will use defaults", split.length); //NON-NLS
parsed.put(MAIL_ACCOUNT, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text"));
parsed.put(MAIL_FOLDER, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text"));
Map<String, List<Long>> folders = accounts.get(account);
if (folders == null) {
folders = new LinkedHashMap<>();
accounts.put(account, folders);
}
List<Long> messages = folders.get(folder);
if (messages == null) {
messages = new ArrayList<>();
folders.put(folder, messages);
}
messages.add(artifactId);
}
skCase.closeRunQuery(rs);
} catch (SQLException ex) {
logger.log(Level.WARNING, "Cannot initialize email extraction", ex); //NON-NLS
}
}
private Map<String, String> parsePath(String path) {
Map<String, String> parsed = new HashMap<>();
String[] split = path.split(MAIL_PATH_SEPARATOR);
if (split.length < 4) {
logger.log(Level.WARNING, "Unexpected number of tokens when parsing email PATH: {0}, will use defaults", split.length); //NON-NLS
parsed.put(MAIL_ACCOUNT, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text"));
parsed.put(MAIL_FOLDER, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text"));
return parsed;
}
parsed.put(MAIL_ACCOUNT, split[2]);
parsed.put(MAIL_FOLDER, split[3]);
return parsed;
}
parsed.put(MAIL_ACCOUNT, split[2]);
parsed.put(MAIL_FOLDER, split[3]);
return parsed;
}
@Override
@ -122,94 +151,94 @@ public class EmailExtracted implements AutopsyVisitableItem {
/**
* Mail root node showing all emails
*/
public class EmailExtractedRootNodeFlat extends DisplayableItemNode {
public EmailExtractedRootNodeFlat() {
super(Children.create(new EmailExtractedRootChildrenFlat(), true), Lookups.singleton(DISPLAY_NAME));
super.setName(LABEL_NAME);
super.setDisplayName(DISPLAY_NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/mail-icon-16.png"); //NON-NLS
initArtifacts();
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
//return v.visit(this);
return null;
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
Sheet.Set ss = s.get(Sheet.PROPERTIES);
if (ss == null) {
ss = Sheet.createPropertiesSet();
s.put(ss);
}
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.displayName"),
NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.desc"),
getName()));
return s;
}
}
/**
* Mail root child node showing flattened emails
*/
private class EmailExtractedRootChildrenFlat extends ChildFactory<BlackboardArtifact> {
private EmailExtractedRootChildrenFlat() {
super();
}
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
//flatten all emails
List<BlackboardArtifact> tempList = new ArrayList<>();
for (String account : accounts.keySet()) {
Map<String, List<Long>> folders = accounts.get(account);
for (String folder : folders.keySet()) {
List<Long> messages = folders.get(folder);
for (long l : messages) {
try {
//TODO: bulk artifact gettings
tempList.add(skCase.getBlackboardArtifact(l));
} catch (TskException ex) {
logger.log(Level.WARNING, "Error creating mail messages nodes", ex); //NON-NLS
}
}
}
}
list.addAll(tempList);
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact artifact) {
return new BlackboardArtifactNode(artifact);
}
}
// public class FlatRootNode extends DisplayableItemNode {
//
// public FlatRootNode() {
// super(Children.create(new FlatRootFactory(), true), Lookups.singleton(DISPLAY_NAME));
// super.setName(LABEL_NAME);
// super.setDisplayName(DISPLAY_NAME);
// this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/mail-icon-16.png"); //NON-NLS
// initArtifacts();
// }
//
// @Override
// public boolean isLeafTypeNode() {
// return false;
// }
//
// @Override
// public <T> T accept(DisplayableItemNodeVisitor<T> v) {
// //return v.visit(this);
// return null;
// }
//
// @Override
// protected Sheet createSheet() {
// Sheet s = super.createSheet();
// Sheet.Set ss = s.get(Sheet.PROPERTIES);
// if (ss == null) {
// ss = Sheet.createPropertiesSet();
// s.put(ss);
// }
//
// ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.name"),
// NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.displayName"),
// NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.desc"),
// getName()));
// return s;
// }
// }
//
// /**
// * Mail root child node showing flattened emails
// */
// private class FlatRootFactory extends ChildFactory<BlackboardArtifact> {
//
// private FlatRootFactory() {
// super();
// }
//
// @Override
// protected boolean createKeys(List<BlackboardArtifact> list) {
// //flatten all emails
// List<BlackboardArtifact> tempList = new ArrayList<>();
// for (String account : accounts.keySet()) {
// Map<String, List<Long>> folders = accounts.get(account);
// for (String folder : folders.keySet()) {
// List<Long> messages = folders.get(folder);
// for (long l : messages) {
// try {
// //TODO: bulk artifact gettings
// tempList.add(skCase.getBlackboardArtifact(l));
// } catch (TskException ex) {
// logger.log(Level.WARNING, "Error creating mail messages nodes", ex); //NON-NLS
// }
// }
// }
// }
//
// list.addAll(tempList);
// return true;
// }
//
// @Override
// protected Node createNodeForKey(BlackboardArtifact artifact) {
// return new BlackboardArtifactNode(artifact);
// }
// }
/**
* Mail root node grouping all mail accounts, supports account-> folder
* structure
*/
public class EmailExtractedRootNode extends DisplayableItemNode {
public class RootNode extends DisplayableItemNode {
public EmailExtractedRootNode() {
super(Children.create(new EmailExtractedRootChildren(), true), Lookups.singleton(DISPLAY_NAME));
public RootNode() {
super(Children.create(new AccountFactory(), true), Lookups.singleton(DISPLAY_NAME));
super.setName(LABEL_NAME);
super.setDisplayName(DISPLAY_NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/mail-icon-16.png"); //NON-NLS
initArtifacts();
emailResults.update();
}
@Override
@ -220,7 +249,6 @@ public class EmailExtracted implements AutopsyVisitableItem {
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
//return null;
}
@Override
@ -244,30 +272,74 @@ public class EmailExtracted implements AutopsyVisitableItem {
/**
* Mail root child node creating each account node
*/
private class EmailExtractedRootChildren extends ChildFactory<String> {
private class AccountFactory extends ChildFactory.Detachable<String> implements Observer {
/* The pcl is in the class because it has the easiest mechanisms to add and remove itself
* during its life cycles.
*/
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestEvent.DATA.toString())) {
if (((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG) {
emailResults.update();
}
}
else if (eventType.equals(IngestManager.IngestEvent.INGEST_JOB_COMPLETED.toString())
|| eventType.equals(IngestManager.IngestEvent.INGEST_JOB_CANCELLED.toString())) {
emailResults.update();
}
}
};
@Override
protected void addNotify() {
IngestManager.addPropertyChangeListener(pcl);
emailResults.addObserver(this);
}
@Override
protected void removeNotify() {
IngestManager.removePropertyChangeListener(pcl);
emailResults.deleteObserver(this);
}
@Override
protected boolean createKeys(List<String> list) {
list.addAll(accounts.keySet());
list.addAll(emailResults.getAccounts());
return true;
}
@Override
protected Node createNodeForKey(String key) {
return new EmailExtractedAccountNode(key, accounts.get(key));
return new AccountNode(key);
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
}
}
/**
* Account node representation
*/
public class EmailExtractedAccountNode extends DisplayableItemNode {
public EmailExtractedAccountNode(String name, Map<String, List<Long>> children) {
super(Children.create(new EmailExtractedAccountChildrenNode(children), true), Lookups.singleton(name));
super.setName(name);
super.setDisplayName(name + " (" + children.size() + ")");
public class AccountNode extends DisplayableItemNode implements Observer {
private String accountName;
public AccountNode(String accountName) {
super(Children.create(new FolderFactory(accountName), true), Lookups.singleton(accountName));
super.setName(accountName);
this.accountName = accountName;
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account-icon-16.png"); //NON-NLS
updateDisplayName();
emailResults.addObserver(this);
}
private void updateDisplayName() {
super.setDisplayName(accountName + " (" + emailResults.getFolders(accountName) + ")");
}
@Override
@ -296,43 +368,61 @@ public class EmailExtracted implements AutopsyVisitableItem {
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public void update(Observable o, Object arg) {
updateDisplayName();
}
}
/**
* Account node child creating sub nodes for every folder
*/
private class EmailExtractedAccountChildrenNode extends ChildFactory<String> {
private class FolderFactory extends ChildFactory<String> implements Observer {
private Map<String, List<Long>> folders;
private String accountName;
private EmailExtractedAccountChildrenNode(Map<String, List<Long>> folders) {
private FolderFactory(String accountName) {
super();
this.folders = folders;
this.accountName = accountName;
emailResults.addObserver(this);
}
@Override
protected boolean createKeys(List<String> list) {
list.addAll(folders.keySet());
list.addAll(emailResults.getFolders(accountName));
return true;
}
@Override
protected Node createNodeForKey(String key) {
return new EmailExtractedFolderNode(key, folders.get(key));
protected Node createNodeForKey(String folderName) {
return new FolderNode(accountName, folderName);
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
}
}
/**
* Node representing mail folder
*/
public class EmailExtractedFolderNode extends DisplayableItemNode {
public EmailExtractedFolderNode(String name, List<Long> children) {
super(Children.create(new EmailExtractedFolderChildrenNode(children), true), Lookups.singleton(name));
super.setName(name);
super.setDisplayName(name + " (" + children.size() + ")");
public class FolderNode extends DisplayableItemNode implements Observer {
private String accountName;
private String folderName;
public FolderNode(String accountName, String folderName) {
super(Children.create(new MessageFactory(accountName, folderName), true), Lookups.singleton(accountName));
super.setName(folderName);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-16.png"); //NON-NLS
updateDisplayName();
emailResults.addObserver(this);
}
private void updateDisplayName() {
super.setDisplayName(folderName + " (" + emailResults.getArtifactIds(accountName, folderName).size() + ")");
}
@Override
@ -361,38 +451,48 @@ public class EmailExtracted implements AutopsyVisitableItem {
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public void update(Observable o, Object arg) {
updateDisplayName();
}
}
/**
* Node representing mail folder content (mail messages)
*/
private class EmailExtractedFolderChildrenNode extends ChildFactory<BlackboardArtifact> {
private class MessageFactory extends ChildFactory<Long> implements Observer {
private List<Long> messages;
private String accountName;
private String folderName;
private EmailExtractedFolderChildrenNode(List<Long> messages) {
private MessageFactory(String accountName, String folderName) {
super();
this.messages = messages;
this.accountName = accountName;
this.folderName = folderName;
emailResults.addObserver(this);
}
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
List<BlackboardArtifact> tempList = new ArrayList<>();
for (long l : messages) {
try {
//TODO: bulk artifact gettings
tempList.add(skCase.getBlackboardArtifact(l));
} catch (TskException ex) {
logger.log(Level.WARNING, "Error creating mail messages nodes", ex); //NON-NLS
}
}
list.addAll(tempList);
protected boolean createKeys(List<Long> list) {
list.addAll(emailResults.getArtifactIds(accountName, folderName));
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact artifact) {
return new BlackboardArtifactNode(artifact);
protected Node createNodeForKey(Long artifactId) {
try {
BlackboardArtifact artifact = skCase.getBlackboardArtifact(artifactId);
return new BlackboardArtifactNode(artifact);
} catch (TskException ex) {
logger.log(Level.WARNING, "Error creating mail messages nodes", ex); //NON-NLS
}
return null;
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,17 +18,59 @@
*/
package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CALENDAR_ENTRY;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INSTALLED_PROG;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_SPEED_DIAL_ENTRY;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException;
/**
* Parent of the "extracted content" artifacts to be displayed in the tree. Other
* artifacts are displayed under other more specific parents.
* Parent of the "extracted content" artifacts to be displayed in the tree.
* Other artifacts are displayed under other more specific parents.
*/
class ExtractedContent implements AutopsyVisitableItem{
public class ExtractedContent implements AutopsyVisitableItem {
SleuthkitCase skCase;
private SleuthkitCase skCase;
public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text");
public ExtractedContent(SleuthkitCase skCase){
public ExtractedContent(SleuthkitCase skCase) {
this.skCase = skCase;
}
@ -37,7 +79,310 @@ import org.sleuthkit.datamodel.SleuthkitCase;
return v.visit(this);
}
public SleuthkitCase getSleuthkitCase(){
public SleuthkitCase getSleuthkitCase() {
return skCase;
}
public class RootNode extends DisplayableItemNode {
public RootNode(SleuthkitCase skCase) {
super(Children.create(new TypeFactory(skCase), true), Lookups.singleton(NAME));
super.setName(NAME);
super.setDisplayName(NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png"); //NON-NLS
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
Sheet.Set ss = s.get(Sheet.PROPERTIES);
if (ss == null) {
ss = Sheet.createPropertiesSet();
s.put(ss);
}
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.displayName"),
NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.desc"),
NAME));
return s;
}
}
/**
* Creates the children for the ExtractedContent area of the results tree.
* This area has all of the blackboard artifacts that are not displayed in a
* more specific form elsewhere in the tree.
*/
private class TypeFactory extends ChildFactory.Detachable<BlackboardArtifact.ARTIFACT_TYPE> {
private SleuthkitCase skCase;
private final ArrayList<BlackboardArtifact.ARTIFACT_TYPE> doNotShow;
// maps the artifact type to its child node
private HashMap<BlackboardArtifact.ARTIFACT_TYPE, TypeNode> typeNodeList = new HashMap<>();
public TypeFactory(SleuthkitCase skCase) {
super();
this.skCase = skCase;
// these are shown in other parts of the UI tree
doNotShow = new ArrayList<>();
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT);
}
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestEvent.DATA.toString())) {
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue();
if (doNotShow.contains(event.getArtifactType()) == false) {
refresh(true);
}
} else if (eventType.equals(IngestManager.IngestEvent.INGEST_JOB_COMPLETED.toString())
|| eventType.equals(IngestManager.IngestEvent.INGEST_JOB_CANCELLED.toString())) {
refresh(true);
}
}
};
@Override
protected void addNotify() {
IngestManager.addPropertyChangeListener(pcl);
}
@Override
protected void removeNotify() {
IngestManager.removePropertyChangeListener(pcl);
typeNodeList.clear();
}
@Override
protected boolean createKeys(List<BlackboardArtifact.ARTIFACT_TYPE> list) {
try {
List<BlackboardArtifact.ARTIFACT_TYPE> inUse = skCase.getBlackboardArtifactTypesInUse();
inUse.removeAll(doNotShow);
Collections.sort(inUse,
new Comparator<BlackboardArtifact.ARTIFACT_TYPE>() {
@Override
public int compare(BlackboardArtifact.ARTIFACT_TYPE a, BlackboardArtifact.ARTIFACT_TYPE b) {
return a.getDisplayName().compareTo(b.getDisplayName());
}
});
list.addAll(inUse);
// the create node method will get called only for new types
// refresh the counts if we already created them from a previous update
for (BlackboardArtifact.ARTIFACT_TYPE art : inUse) {
TypeNode node = typeNodeList.get(art);
if (node != null) {
node.updateDisplayName();
}
}
} catch (TskCoreException ex) {
Logger.getLogger(TypeFactory.class.getName()).log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage()); //NON-NLS
return false;
}
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact.ARTIFACT_TYPE key) {
TypeNode node = new TypeNode(key, skCase);
typeNodeList.put(key, node);
return node;
}
}
/**
* Node encapsulating blackboard artifact type. This is used on the
* left-hand navigation side of the Autopsy UI as the parent node for all of
* the artifacts of a given type. Its children will be
* BlackboardArtifactNode objects.
*/
public class TypeNode extends DisplayableItemNode {
private BlackboardArtifact.ARTIFACT_TYPE type;
private long childCount = 0;
private SleuthkitCase skCase;
TypeNode(BlackboardArtifact.ARTIFACT_TYPE type, SleuthkitCase skCase) {
super(Children.create(new ArtifactFactory(type, skCase), true), Lookups.singleton(type.getDisplayName()));
super.setName(type.getLabel());
this.skCase = skCase;
this.type = type;
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/" + getIcon(type)); //NON-NLS
updateDisplayName();
}
final void updateDisplayName() {
// NOTE: This completely destroys our lazy-loading ideal
// a performance increase might be had by adding a
// "getBlackboardArtifactCount()" method to skCase
try {
this.childCount = skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
} catch (TskException ex) {
Logger.getLogger(TypeNode.class.getName())
.log(Level.WARNING, "Error getting child count", ex); //NON-NLS
}
super.setDisplayName(type.getDisplayName() + " (" + childCount + ")");
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
Sheet.Set ss = s.get(Sheet.PROPERTIES);
if (ss == null) {
ss = Sheet.createPropertiesSet();
s.put(ss);
}
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.name"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.displayName"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.desc"),
type.getDisplayName()));
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.name"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.displayName"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.desc"),
childCount));
return s;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
// @@@ TODO: Merge with BlackboartArtifactNode.getIcon()
private String getIcon(BlackboardArtifact.ARTIFACT_TYPE type) {
switch (type) {
case TSK_WEB_BOOKMARK:
return "bookmarks.png"; //NON-NLS
case TSK_WEB_COOKIE:
return "cookies.png"; //NON-NLS
case TSK_WEB_HISTORY:
return "history.png"; //NON-NLS
case TSK_WEB_DOWNLOAD:
return "downloads.png"; //NON-NLS
case TSK_INSTALLED_PROG:
return "programs.png"; //NON-NLS
case TSK_RECENT_OBJECT:
return "recent_docs.png"; //NON-NLS
case TSK_DEVICE_ATTACHED:
return "usb_devices.png"; //NON-NLS
case TSK_WEB_SEARCH_QUERY:
return "searchquery.png"; //NON-NLS
case TSK_METADATA_EXIF:
return "camera-icon-16.png"; //NON-NLS
case TSK_CONTACT:
return "contact.png"; //NON-NLS
case TSK_MESSAGE:
return "message.png"; //NON-NLS
case TSK_CALLLOG:
return "calllog.png"; //NON-NLS
case TSK_CALENDAR_ENTRY:
return "calendar.png"; //NON-NLS
case TSK_SPEED_DIAL_ENTRY:
return "speeddialentry.png"; //NON-NLS
case TSK_BLUETOOTH_PAIRING:
return "bluetooth.png"; //NON-NLS
case TSK_GPS_BOOKMARK:
return "gpsfav.png"; //NON-NLS
case TSK_GPS_LAST_KNOWN_LOCATION:
return "gps-lastlocation.png"; //NON-NLS
case TSK_GPS_SEARCH:
return "gps-search.png"; //NON-NLS
case TSK_SERVICE_ACCOUNT:
return "account-icon-16.png"; //NON-NLS
case TSK_ENCRYPTION_DETECTED:
return "encrypted-file.png"; //NON-NLS
case TSK_EXT_MISMATCH_DETECTED:
return "mismatch-16.png"; //NON-NLS
}
return "artifact-icon.png"; //NON-NLS
}
@Override
public boolean isLeafTypeNode() {
return true;
}
}
/**
* Creates children for a given artifact type
*/
private static class ArtifactFactory extends ChildFactory.Detachable<BlackboardArtifact> {
private SleuthkitCase skCase;
private BlackboardArtifact.ARTIFACT_TYPE type;
public ArtifactFactory(BlackboardArtifact.ARTIFACT_TYPE type, SleuthkitCase skCase) {
super();
this.skCase = skCase;
this.type = type;
}
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestEvent.DATA.toString())) {
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue();
if (event.getArtifactType() == type) {
refresh(true);
}
} else if (eventType.equals(IngestManager.IngestEvent.INGEST_JOB_COMPLETED.toString())
|| eventType.equals(IngestManager.IngestEvent.INGEST_JOB_CANCELLED.toString())) {
refresh(true);
}
}
};
@Override
protected void addNotify() {
IngestManager.addPropertyChangeListener(pcl);
}
@Override
protected void removeNotify() {
IngestManager.removePropertyChangeListener(pcl);
}
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
try {
List<BlackboardArtifact> arts = skCase.getBlackboardArtifacts(type.getTypeID());
list.addAll(arts);
} catch (TskException ex) {
Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS
}
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact key) {
return new BlackboardArtifactNode(key);
}
}
}

View File

@ -18,12 +18,16 @@
*/
package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import java.util.logging.Level;
@ -34,13 +38,16 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskException;
/**
* Hash set hits node support
* Hash set hits node support. Inner classes have all of the nodes in the tree.
*/
public class HashsetHits implements AutopsyVisitableItem {
@ -48,65 +55,85 @@ public class HashsetHits implements AutopsyVisitableItem {
private static final String DISPLAY_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName();
private static final Logger logger = Logger.getLogger(HashsetHits.class.getName());
private SleuthkitCase skCase;
private Map<String, Set<Long>> hashSetHitsMap;
private HashsetResults hashsetResults;
public HashsetHits(SleuthkitCase skCase) {
this.skCase = skCase;
hashSetHitsMap = new LinkedHashMap<>();
}
@SuppressWarnings("deprecation")
private void initArtifacts() {
hashSetHitsMap.clear();
ResultSet rs = null;
try {
int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID();
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS
+ "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
+ "attribute_type_id=" + setNameId //NON-NLS
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
rs = skCase.runQuery(query);
while (rs.next()) {
String value = rs.getString("value_text"); //NON-NLS
long artifactId = rs.getLong("artifact_id"); //NON-NLS
if (!hashSetHitsMap.containsKey(value)) {
hashSetHitsMap.put(value, new HashSet<Long>());
}
hashSetHitsMap.get(value).add(artifactId);
}
} catch (SQLException ex) {
logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS
} finally {
if (rs != null) {
try {
skCase.closeRunQuery(rs);
} catch (SQLException ex) {
logger.log(Level.WARNING, "Error closing result set after getting hashset hits", ex); //NON-NLS
}
}
}
hashsetResults = new HashsetResults();
}
@Override
public <T> T accept(AutopsyItemVisitor<T> v) {
return v.visit(this);
}
/**
* Stores all of the hashset results in a single class that is observable for the
* child nodes
*/
private class HashsetResults extends Observable {
// maps hashset name to list of artifacts for that set
private Map<String, Set<Long>> hashSetHitsMap = new LinkedHashMap<>();
HashsetResults() {
update();
}
Set<String> getSetNames() {
return hashSetHitsMap.keySet();
}
Set<Long> getArtifactIds(String hashSetName) {
return hashSetHitsMap.get(hashSetName);
}
final void update() {
hashSetHitsMap.clear();
ResultSet rs = null;
try {
int setNameId = ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
int artId = ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID();
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS
+ "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
+ "attribute_type_id=" + setNameId //NON-NLS
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
rs = skCase.runQuery(query);
while (rs.next()) {
String setName = rs.getString("value_text"); //NON-NLS
long artifactId = rs.getLong("artifact_id"); //NON-NLS
if (!hashSetHitsMap.containsKey(setName)) {
hashSetHitsMap.put(setName, new HashSet<Long>());
}
hashSetHitsMap.get(setName).add(artifactId);
}
} catch (SQLException ex) {
logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS
} finally {
if (rs != null) {
try {
skCase.closeRunQuery(rs);
} catch (SQLException ex) {
logger.log(Level.WARNING, "Error closing result set after getting hashset hits", ex); //NON-NLS
}
}
}
setChanged();
notifyObservers();
}
}
/**
* Node for the hash set hits
* Top-level node for all hash sets
*/
public class HashsetHitsRootNode extends DisplayableItemNode {
public class RootNode extends DisplayableItemNode {
public HashsetHitsRootNode() {
super(Children.create(new HashsetHitsRootChildren(), true), Lookups.singleton(DISPLAY_NAME));
public RootNode() {
super(Children.create(new HashsetNameFactory(), true), Lookups.singleton(DISPLAY_NAME));
super.setName(HASHSET_HITS);
super.setDisplayName(DISPLAY_NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); //NON-NLS
initArtifacts();
}
@Override
@ -137,27 +164,80 @@ public class HashsetHits implements AutopsyVisitableItem {
}
}
private class HashsetHitsRootChildren extends ChildFactory<String> {
/**
* Creates child nodes for each hashset name
*/
private class HashsetNameFactory extends ChildFactory.Detachable<String> implements Observer {
/* This should probably be in the HashsetHits class, but the factory has nice methods
* for its startup and shutdown, so it seemed like a cleaner place to register the
* property change listener.
*/
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestEvent.DATA.toString())) {
if (((ModuleDataEvent) evt.getOldValue()).getArtifactType() == ARTIFACT_TYPE.TSK_HASHSET_HIT) {
hashsetResults.update();
}
}
else if (eventType.equals(IngestManager.IngestEvent.INGEST_JOB_COMPLETED.toString())
|| eventType.equals(IngestManager.IngestEvent.INGEST_JOB_CANCELLED.toString())) {
hashsetResults.update();
}
}
};
@Override
protected boolean createKeys(List<String> list) {
list.addAll(hashSetHitsMap.keySet());
protected void addNotify() {
IngestManager.addPropertyChangeListener(pcl);
hashsetResults.addObserver(this);
}
@Override
protected void removeNotify() {
IngestManager.removePropertyChangeListener(pcl);
hashsetResults.deleteObserver(this);
}
@Override
protected boolean createKeys(List<String> list) {
list.addAll(hashsetResults.getSetNames());
return true;
}
@Override
protected Node createNodeForKey(String key) {
return new HashsetHitsSetNode(key, hashSetHitsMap.get(key));
return new HashsetNameNode(key);
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
}
}
public class HashsetHitsSetNode extends DisplayableItemNode {
public HashsetHitsSetNode(String name, Set<Long> children) {
super(Children.create(new HashsetHitsSetChildren(children), true), Lookups.singleton(name));
super.setName(name);
super.setDisplayName(name + " (" + children.size() + ")");
/**
* Node for a hash set name
*/
public class HashsetNameNode extends DisplayableItemNode implements Observer {
private String hashSetName;
public HashsetNameNode(String hashSetName) {
super(Children.create(new HitFactory(hashSetName), true), Lookups.singleton(hashSetName));
super.setName(hashSetName);
super.setDisplayName(hashSetName + " (0)");
this.hashSetName = hashSetName;
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); //NON-NLS
hashsetResults.addObserver(this);
}
/**
* Update the count in the display name
*/
private void updateName() {
super.setDisplayName(hashSetName + " (" + hashsetResults.getArtifactIds(hashSetName).size() + ")");
}
@Override
@ -186,33 +266,54 @@ public class HashsetHits implements AutopsyVisitableItem {
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public void update(Observable o, Object arg) {
updateName();
}
}
private class HashsetHitsSetChildren extends ChildFactory<BlackboardArtifact> {
private Set<Long> children;
private HashsetHitsSetChildren(Set<Long> children) {
/**
* Creates the nodes for the hits in a given set.
*/
private class HitFactory extends ChildFactory.Detachable<Long> implements Observer {
private String hashsetName;
private HitFactory(String hashsetName) {
super();
this.children = children;
this.hashsetName = hashsetName;
}
@Override
protected void addNotify() {
hashsetResults.addObserver(this);
}
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
for (long l : children) {
try {
//TODO: bulk artifact gettings
list.add(skCase.getBlackboardArtifact(l));
} catch (TskException ex) {
logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
}
}
protected void removeNotify() {
hashsetResults.deleteObserver(this);
}
@Override
protected boolean createKeys(List<Long> list) {
list.addAll(hashsetResults.getArtifactIds(hashsetName));
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact artifact) {
return new BlackboardArtifactNode(artifact);
protected Node createNodeForKey(Long id) {
try {
BlackboardArtifact art = skCase.getBlackboardArtifact(id);
return new BlackboardArtifactNode(art);
} catch (TskException ex) {
logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
}
return null;
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
}
}
}
}

View File

@ -106,10 +106,10 @@ public class InterestingHits implements AutopsyVisitableItem {
/**
* Node for the interesting items
*/
public class InterestingHitsRootNode extends DisplayableItemNode {
public class RootNode extends DisplayableItemNode {
public InterestingHitsRootNode() {
super(Children.create(new InterestingHitsRootChildren(), true), Lookups.singleton(DISPLAY_NAME));
public RootNode() {
super(Children.create(new SetNameFactory(), true), Lookups.singleton(DISPLAY_NAME));
super.setName(INTERESTING_ITEMS);
super.setDisplayName(DISPLAY_NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS
@ -144,7 +144,7 @@ public class InterestingHits implements AutopsyVisitableItem {
}
}
private class InterestingHitsRootChildren extends ChildFactory<String> {
private class SetNameFactory extends ChildFactory<String> {
@Override
protected boolean createKeys(List<String> list) {
@ -154,14 +154,14 @@ public class InterestingHits implements AutopsyVisitableItem {
@Override
protected Node createNodeForKey(String key) {
return new InterestingHitsSetNode(key, interestingItemsMap.get(key));
return new SetNameNode(key, interestingItemsMap.get(key));
}
}
public class InterestingHitsSetNode extends DisplayableItemNode {
public class SetNameNode extends DisplayableItemNode {
public InterestingHitsSetNode(String name, Set<Long> children) {
super(Children.create(new InterestingHitsSetChildren(children), true), Lookups.singleton(name));
public SetNameNode(String name, Set<Long> children) {
super(Children.create(new HitFactory(children), true), Lookups.singleton(name));
super.setName(name);
super.setDisplayName(name + " (" + children.size() + ")");
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS
@ -195,11 +195,11 @@ public class InterestingHits implements AutopsyVisitableItem {
}
}
private class InterestingHitsSetChildren extends ChildFactory<BlackboardArtifact> {
private class HitFactory extends ChildFactory<BlackboardArtifact> {
private Set<Long> children;
private InterestingHitsSetChildren(Set<Long> children) {
private HitFactory(Set<Long> children) {
super();
this.children = children;
}

View File

@ -18,13 +18,16 @@
*/
package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import java.util.logging.Level;
import org.openide.util.NbBundle;
@ -34,6 +37,8 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.SleuthkitCase;
@ -54,101 +59,123 @@ public class KeywordHits implements AutopsyVisitableItem {
.getMessage(KeywordHits.class, "KeywordHits.simpleLiteralSearch.text");
public static final String SIMPLE_REGEX_SEARCH = NbBundle
.getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text");
// Map from String (list name) to Map from string (keyword) to set<long> (artifact ids)
private Map<String, Map<String, Set<Long>>> topLevelMap;
private Map<String, Map<String, Set<Long>>> listsMap;
// Map from String (literal keyword) to set<long> (artifact ids)
private Map<String, Set<Long>> literalMap;
// Map from String (regex keyword) to set<long> (artifact ids);
private Map<String, Set<Long>> regexMap;
Map<Long, Map<Long, String>> artifacts;
private KeywordResults keywordResults;
public KeywordHits(SleuthkitCase skCase) {
this.skCase = skCase;
artifacts = new LinkedHashMap<>();
listsMap = new LinkedHashMap<>();
literalMap = new LinkedHashMap<>();
regexMap = new LinkedHashMap<>();
topLevelMap = new LinkedHashMap<>();
keywordResults = new KeywordResults();
}
private void initMaps() {
topLevelMap.clear();
topLevelMap.put(SIMPLE_LITERAL_SEARCH, literalMap);
topLevelMap.put(SIMPLE_REGEX_SEARCH, regexMap);
listsMap.clear();
regexMap.clear();
literalMap.clear();
for (Map.Entry<Long, Map<Long, String>> art : artifacts.entrySet()) {
long id = art.getKey();
Map<Long, String> attributes = art.getValue();
// I think we can use attributes.remove(...) here?
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()));
if (listName != null) {
if (!listsMap.containsKey(listName)) {
listsMap.put(listName, new LinkedHashMap<String, Set<Long>>());
}
if (!listsMap.get(listName).containsKey(word)) {
listsMap.get(listName).put(word, new HashSet<Long>());
}
listsMap.get(listName).get(word).add(id);
} else if (reg != null) {
if (!regexMap.containsKey(reg)) {
regexMap.put(reg, new HashSet<Long>());
}
regexMap.get(reg).add(id);
} else {
if (!literalMap.containsKey(word)) {
literalMap.put(word, new HashSet<Long>());
}
literalMap.get(word).add(id);
}
topLevelMap.putAll(listsMap);
private final class KeywordResults extends Observable {
// Map from listName/Type to Map of keyword to set of artifact Ids
private Map<String, Map<String, Set<Long>>> topLevelMap;
KeywordResults() {
topLevelMap = new LinkedHashMap<>();
update();
}
Set<String> getListNames() {
return topLevelMap.keySet();
}
Set<String> getKeywords(String listName) {
return topLevelMap.get(listName).keySet();
}
Set<Long> getArtifactIds(String listName, String keyword) {
return topLevelMap.get(listName).get(keyword);
}
}
@SuppressWarnings("deprecation")
private void initArtifacts() {
artifacts.clear();
ResultSet rs = null;
try {
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
+ "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=" + regexId + ")"; //NON-NLS
rs = skCase.runQuery(query);
while (rs.next()) {
String value = rs.getString("value_text"); //NON-NLS
long artifactId = rs.getLong("artifact_id"); //NON-NLS
long typeId = rs.getLong("attribute_type_id"); //NON-NLS
if (!artifacts.containsKey(artifactId)) {
artifacts.put(artifactId, new LinkedHashMap<Long, String>());
// populate maps based on artifactIds
void populateMaps(Map<Long, Map<Long, String>> artifactIds) {
topLevelMap.clear();
Map<String, Map<String, Set<Long>>> listsMap = new LinkedHashMap<>();
// Map from String (literal keyword) to set<long> (artifact ids)
Map<String, Set<Long>> literalMap = new LinkedHashMap<>();
// Map from String (regex keyword) to set<long> (artifact ids);
Map<String, Set<Long>> regexMap = new LinkedHashMap<>();
// top-level nodes
topLevelMap.put(SIMPLE_LITERAL_SEARCH, literalMap);
topLevelMap.put(SIMPLE_REGEX_SEARCH, regexMap);
for (Map.Entry<Long, Map<Long, String>> art : artifactIds.entrySet()) {
long id = art.getKey();
Map<Long, String> attributes = art.getValue();
// I think we can use attributes.remove(...) here?
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()));
if (listName != null) {
if (!listsMap.containsKey(listName)) {
listsMap.put(listName, new LinkedHashMap<String, Set<Long>>());
}
if (!listsMap.get(listName).containsKey(word)) {
listsMap.get(listName).put(word, new HashSet<Long>());
}
listsMap.get(listName).get(word).add(id);
} else if (reg != null) {
if (!regexMap.containsKey(reg)) {
regexMap.put(reg, new HashSet<Long>());
}
regexMap.get(reg).add(id);
} else {
if (!literalMap.containsKey(word)) {
literalMap.put(word, new HashSet<Long>());
}
literalMap.get(word).add(id);
}
if (!value.equals("")) {
artifacts.get(artifactId).put(typeId, value);
}
topLevelMap.putAll(listsMap);
}
} catch (SQLException ex) {
logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS
} finally {
if (rs != null) {
try {
skCase.closeRunQuery(rs);
} catch (SQLException ex) {
logger.log(Level.WARNING, "Error closing result set after getting keyword hits", ex); //NON-NLS
setChanged();
notifyObservers();
}
public void update() {
Map<Long, Map<Long, String>> artifactIds = new LinkedHashMap<>();
ResultSet rs = null;
try {
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
+ "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=" + regexId + ")"; //NON-NLS
rs = skCase.runQuery(query);
while (rs.next()) {
String value = rs.getString("value_text"); //NON-NLS
long artifactId = rs.getLong("artifact_id"); //NON-NLS
long typeId = rs.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);
}
}
} catch (SQLException ex) {
logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS
} finally {
if (rs != null) {
try {
skCase.closeRunQuery(rs);
} catch (SQLException ex) {
logger.log(Level.WARNING, "Error closing result set after getting keyword hits", ex); //NON-NLS
}
}
}
populateMaps(artifactIds);
}
}
@ -157,15 +184,14 @@ public class KeywordHits implements AutopsyVisitableItem {
return v.visit(this);
}
public class KeywordHitsRootNode extends DisplayableItemNode {
// Created by CreateAutopsyNodeVisitor
public class RootNode extends DisplayableItemNode {
public KeywordHitsRootNode() {
super(Children.create(new KeywordHitsRootChildren(), true), Lookups.singleton(KEYWORD_HITS));
public RootNode() {
super(Children.create(new ListFactory(), true), Lookups.singleton(KEYWORD_HITS));
super.setName(NAME);
super.setDisplayName(KEYWORD_HITS);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
initArtifacts();
initMaps();
}
@Override
@ -196,36 +222,73 @@ public class KeywordHits implements AutopsyVisitableItem {
}
}
private class KeywordHitsRootChildren extends ChildFactory<String> {
private class ListFactory extends ChildFactory.Detachable<String> implements Observer {
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestEvent.DATA.toString())) {
if (((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT) {
keywordResults.update();
}
}
else if (eventType.equals(IngestManager.IngestEvent.INGEST_JOB_COMPLETED.toString())
|| eventType.equals(IngestManager.IngestEvent.INGEST_JOB_CANCELLED.toString())) {
keywordResults.update();
}
}
};
@Override
protected void addNotify() {
IngestManager.addPropertyChangeListener(pcl);
keywordResults.addObserver(this);
}
@Override
protected void removeNotify() {
IngestManager.removePropertyChangeListener(pcl);
keywordResults.deleteObserver(this);
}
@Override
protected boolean createKeys(List<String> list) {
list.addAll(topLevelMap.keySet());
list.addAll(keywordResults.getListNames());
return true;
}
@Override
protected Node createNodeForKey(String key) {
return new KeywordHitsListNode(key, topLevelMap.get(key));
return new ListNode(key);
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
}
}
public class KeywordHitsListNode extends DisplayableItemNode {
public class ListNode extends DisplayableItemNode implements Observer {
private String listName;
private String name;
private Map<String, Set<Long>> children;
public KeywordHitsListNode(String name, Map<String, Set<Long>> children) {
super(Children.create(new KeywordHitsListChildren(children), true), Lookups.singleton(name));
super.setName(name);
int totalDescendants = 0;
for (Set<Long> grandChildren : children.values()) {
totalDescendants += grandChildren.size();
}
super.setDisplayName(name + " (" + totalDescendants + ")");
public ListNode(String listName) {
super(Children.create(new TermFactory(listName), true), Lookups.singleton(listName));
super.setName(listName);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
this.name = name;
this.children = children;
this.listName = listName;
updateDisplayName();
keywordResults.addObserver(this);
}
private void updateDisplayName() {
int totalDescendants = 0;
for (String word : keywordResults.getKeywords(listName)) {
Set<Long> ids = keywordResults.getArtifactIds(listName, word);
totalDescendants += ids.size();
}
super.setDisplayName(listName + " (" + totalDescendants + ")");
}
@Override
@ -240,13 +303,13 @@ public class KeywordHits implements AutopsyVisitableItem {
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.name"),
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.displayName"),
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.desc"),
name));
listName));
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.numChildren.name"),
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.numChildren.displayName"),
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.numChildren.desc"),
children.size()));
keywordResults.getKeywords(listName).size()));
return s;
}
@ -260,39 +323,71 @@ public class KeywordHits implements AutopsyVisitableItem {
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
public void update(Observable o, Object arg) {
updateDisplayName();
}
}
private class KeywordHitsListChildren extends ChildFactory<String> {
private Map<String, Set<Long>> children;
private KeywordHitsListChildren(Map<String, Set<Long>> children) {
private class TermFactory extends ChildFactory.Detachable<String> implements Observer {
private String setName;
private TermFactory(String setName) {
super();
this.children = children;
this.setName = setName;
}
@Override
protected void addNotify() {
keywordResults.addObserver(this);
}
@Override
protected void removeNotify() {
keywordResults.deleteObserver(this);
}
@Override
protected boolean createKeys(List<String> list) {
list.addAll(children.keySet());
list.addAll(keywordResults.getKeywords(setName));
return true;
}
@Override
protected Node createNodeForKey(String key) {
return new KeywordHitsKeywordNode(key, children.get(key));
return new TermNode(setName, key);
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
}
}
public class KeywordHitsKeywordNode extends DisplayableItemNode {
public class TermNode extends DisplayableItemNode implements Observer {
private Set<Long> children;
private String setName;
private String keyword;
public KeywordHitsKeywordNode(String name, Set<Long> children) {
super(Children.create(new KeywordHitsKeywordChildren(children), true), Lookups.singleton(name));
super.setName(name);
super.setDisplayName(name + " (" + children.size() + ")");
public TermNode(String setName, String keyword) {
super(Children.create(new HitsFactory (setName, keyword), true), Lookups.singleton(keyword));
super.setName(keyword);
this.setName = setName;
this.keyword = keyword;
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
this.children = children;
updateDisplayName();
keywordResults.addObserver(this);
}
private void updateDisplayName() {
super.setDisplayName(keyword + " (" + keywordResults.getArtifactIds(setName, keyword).size() + ")");
}
@Override
public void update(Observable o, Object arg) {
updateDisplayName();
}
@Override
@ -322,70 +417,83 @@ public class KeywordHits implements AutopsyVisitableItem {
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.name"),
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.displayName"),
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.desc"),
children.size()));
keywordResults.getArtifactIds(setName, keyword).size()));
return s;
}
}
private class KeywordHitsKeywordChildren extends ChildFactory<BlackboardArtifact> {
private Set<Long> children;
private KeywordHitsKeywordChildren(Set<Long> children) {
public class HitsFactory extends ChildFactory.Detachable<Long> implements Observer {
private String keyword;
private String setName;
public HitsFactory(String setName, String keyword) {
super();
this.children = children;
this.setName = setName;
this.keyword = keyword;
}
@Override
protected void addNotify() {
keywordResults.addObserver(this);
}
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
List<BlackboardArtifact> tempList = new ArrayList<>();
for (long l : children) {
try {
//TODO: bulk artifact gettings
tempList.add(skCase.getBlackboardArtifact(l));
} catch (TskException ex) {
logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
}
}
list.addAll(tempList);
protected void removeNotify() {
keywordResults.deleteObserver(this);
}
@Override
protected boolean createKeys(List<Long> list) {
list.addAll(keywordResults.getArtifactIds(setName, keyword));
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact artifact) {
BlackboardArtifactNode n = new BlackboardArtifactNode(artifact);
AbstractFile file;
protected Node createNodeForKey(Long artifactId) {
try {
file = artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID());
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren"); //NON-NLS
return n;
BlackboardArtifact art = skCase.getBlackboardArtifact(artifactId);
BlackboardArtifactNode n = new BlackboardArtifactNode(art);
AbstractFile file;
try {
file = art.getSleuthkitCase().getAbstractFileById(art.getObjectID());
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren"); //NON-NLS
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;
}
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;
@Override
public void update(Observable o, Object arg) {
refresh(true);
}
}
}

View File

@ -65,6 +65,8 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
//TODO this will be removed, Children should be listening for interesting
//events from datamodel and calling refresh / refreshKey() themselves
public void refreshKeys(BlackboardArtifact.ARTIFACT_TYPE... types) {
// find the corresponding top-level node and refresh its children.
// should be more effeciently stored than a list.
for (Object o : contentKeys) {
for (BlackboardArtifact.ARTIFACT_TYPE type : types) {
switch (type) {
@ -91,8 +93,10 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
this.refreshKey(o);
break;
default:
if (o instanceof ExtractedContent)
if (o instanceof ExtractedContent) {
this.refreshKey(o);
}
break;
}
}

View File

@ -27,6 +27,7 @@ import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode;
import org.sleuthkit.datamodel.TagName;
@ -52,22 +53,26 @@ public class TagNameNode extends DisplayableItemNode {
NbBundle.getMessage(TagNameNode.class, "TagNameNode.namePlusTags.text", tagName.getDisplayName())));
this.tagName = tagName;
long tagsCount = 0;
try {
tagsCount = Case.getCurrentCase().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
tagsCount += Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
} catch (TskCoreException ex) {
Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS
}
super.setName(tagName.getDisplayName());
super.setDisplayName(tagName.getDisplayName() + " (" + tagsCount + ")");
setName(tagName.getDisplayName());
updateDisplayName();
if (tagName.getDisplayName().equals(NbBundle.getMessage(this.getClass(), "TagNameNode.bookmark.text"))) {
setIconBaseWithExtension(BOOKMARK_TAG_ICON_PATH);
} else {
setIconBaseWithExtension(ICON_PATH);
}
}
private void updateDisplayName() {
long tagsCount = 0;
try {
TagsManager tm = Case.getCurrentCase().getServices().getTagsManager();
tagsCount = tm.getContentTagsCountByTagName(tagName);
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName);
} catch (TskCoreException ex) {
Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS
}
setDisplayName(tagName.getDisplayName() + " (" + tagsCount + ")");
}
@Override
protected Sheet createSheet() {

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
@ -28,6 +30,9 @@ import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
@ -76,8 +81,36 @@ class TagsNode extends DisplayableItemNode {
return propertySheet;
}
private static class TagNameNodeFactory extends ChildFactory<TagName> {
private static class TagNameNodeFactory extends ChildFactory.Detachable<TagName> {
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestEvent.DATA.toString())) {
if ((((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT) ||
((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) {
refresh(true);
}
}
else if (eventType.equals(IngestManager.IngestEvent.INGEST_JOB_COMPLETED.toString())
|| eventType.equals(IngestManager.IngestEvent.INGEST_JOB_CANCELLED.toString())) {
refresh(true);
}
}
};
@Override
protected void addNotify() {
IngestManager.addPropertyChangeListener(pcl);
}
@Override
protected void removeNotify() {
IngestManager.removePropertyChangeListener(pcl);
}
@Override
protected boolean createKeys(List<TagName> keys) {
try {

View File

@ -33,14 +33,12 @@ import javax.swing.AbstractAction;
import javax.swing.Action;
import org.openide.explorer.ExplorerManager;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.FilterNode;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType;
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
import org.sleuthkit.autopsy.datamodel.ArtifactTypeNode;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.ContentTagTypeNode;
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
@ -48,27 +46,27 @@ import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.De
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedAccountNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedFolderNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedRootNode;
import org.sleuthkit.autopsy.datamodel.ExtractedContentNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.AccountNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.FolderNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted;
import org.sleuthkit.autopsy.datamodel.ExtractedContent.TypeNode;
import org.sleuthkit.autopsy.datamodel.ExtractedContent;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.datamodel.FileTypeNode;
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode;
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode;
import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsRootNode;
import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode;
import org.sleuthkit.autopsy.datamodel.InterestingHits.InterestingHitsRootNode;
import org.sleuthkit.autopsy.datamodel.InterestingHits.InterestingHitsSetNode;
import org.sleuthkit.autopsy.datamodel.HashsetHits;
import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetNameNode;
import org.sleuthkit.autopsy.datamodel.ImageNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsKeywordNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsListNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
import org.sleuthkit.autopsy.datamodel.InterestingHits;
import org.sleuthkit.autopsy.datamodel.KeywordHits.TermNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.ListNode;
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode;
import org.sleuthkit.autopsy.datamodel.RecentFilesNode;
import org.sleuthkit.autopsy.datamodel.FileTypesNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits;
import org.sleuthkit.autopsy.datamodel.TagNameNode;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -367,47 +365,47 @@ public class DataResultFilterNode extends FilterNode {
}
@Override
public AbstractAction visit(ExtractedContentNode ecn) {
public AbstractAction visit(ExtractedContent.RootNode ecn) {
return openChild(ecn);
}
@Override
public AbstractAction visit(KeywordHitsRootNode khrn) {
public AbstractAction visit(KeywordHits.RootNode khrn) {
return openChild(khrn);
}
@Override
public AbstractAction visit(HashsetHitsRootNode hhrn) {
public AbstractAction visit(HashsetHits.RootNode hhrn) {
return openChild(hhrn);
}
@Override
public AbstractAction visit(HashsetHitsSetNode hhsn) {
public AbstractAction visit(HashsetNameNode hhsn) {
return openChild(hhsn);
}
@Override
public AbstractAction visit(InterestingHitsRootNode iarn) {
public AbstractAction visit(InterestingHits.RootNode iarn) {
return openChild(iarn);
}
@Override
public AbstractAction visit(InterestingHitsSetNode iasn) {
public AbstractAction visit(InterestingHits.SetNameNode iasn) {
return openChild(iasn);
}
@Override
public AbstractAction visit(EmailExtractedRootNode eern) {
public AbstractAction visit(EmailExtracted.RootNode eern) {
return openChild(eern);
}
@Override
public AbstractAction visit(EmailExtractedAccountNode eean) {
public AbstractAction visit(AccountNode eean) {
return openChild(eean);
}
@Override
public AbstractAction visit(EmailExtractedFolderNode eefn) {
public AbstractAction visit(FolderNode eefn) {
return openChild(eefn);
}
@ -443,7 +441,7 @@ public class DataResultFilterNode extends FilterNode {
}
@Override
public AbstractAction visit(ArtifactTypeNode atn) {
public AbstractAction visit(TypeNode atn) {
return openChild(atn);
}
@ -516,12 +514,12 @@ public class DataResultFilterNode extends FilterNode {
}
@Override
public AbstractAction visit(KeywordHitsListNode khsn) {
public AbstractAction visit(ListNode khsn) {
return openChild(khsn);
}
@Override
public AbstractAction visit(KeywordHitsKeywordNode khmln) {
public AbstractAction visit(TermNode khmln) {
return openChild(khmln);
}

View File

@ -53,7 +53,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.ExtractedContentNode;
import org.sleuthkit.autopsy.datamodel.ExtractedContent.RootNode;
import org.sleuthkit.autopsy.datamodel.DataSources;
import org.sleuthkit.autopsy.datamodel.DataSourcesNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits;
@ -73,6 +73,7 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.datamodel.ExtractedContent;
/**
* Top component which displays something.
@ -387,7 +388,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
Children resultsChilds = results.getChildren();
tree.expandNode(resultsChilds.findChild(KeywordHits.NAME));
tree.expandNode(resultsChilds.findChild(ExtractedContentNode.NAME));
tree.expandNode(resultsChilds.findChild(ExtractedContent.NAME));
Node views = childNodes.findChild(ViewsNode.NAME);
@ -587,7 +588,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
// change in node selection
else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
respondSelection((Node[]) oldValue, (Node[]) newValue);
} else if (changed.equals(IngestEvent.DATA.toString())) {
}
else if (changed.equals(IngestEvent.DATA.toString())) {
final ModuleDataEvent event = (ModuleDataEvent) oldValue;
if (event.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO) {
return;
@ -595,7 +597,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
refreshTree(event.getArtifactType());
// @@@ refreshResultsTree(event.getArtifactType());
}
});
} else if (changed.equals(IngestEvent.INGEST_JOB_COMPLETED.toString())
@ -603,15 +605,15 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
refreshContentTree();
refreshTree();
refreshDataSourceTree();
refreshResultsTree();
}
});
} else if (changed.equals(IngestEvent.CONTENT_CHANGED.toString())) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
refreshContentTree();
refreshDataSourceTree();
}
});
}
@ -768,7 +770,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
refreshContentTree();
refreshDataSourceTree();
}
});
}
@ -776,7 +778,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
/**
* Refreshes changed content nodes
*/
void refreshContentTree() {
private void refreshDataSourceTree() {
Node selectedNode = getSelectedNode();
final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
@ -809,7 +811,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
* Refreshes the nodes in the tree to reflect updates in the database should
* be called in the gui thread
*/
public void refreshTree(final BlackboardArtifact.ARTIFACT_TYPE... types) {
public void refreshResultsTree(final BlackboardArtifact.ARTIFACT_TYPE... types) {
//save current selection
Node selectedNode = getSelectedNode();
final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
@ -820,44 +822,40 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
Children dirChilds = em.getRootContext().getChildren();
Node results = dirChilds.findChild(ResultsNode.NAME);
if (results == null) {
logger.log(Level.SEVERE, "Cannot find Results filter node, won't refresh the bb tree"); //NON-NLS
return;
}
OriginalNode original = results.getLookup().lookup(OriginalNode.class);
ResultsNode resultsNode = (ResultsNode) original.getNode();
RootContentChildren resultsNodeChilds = (RootContentChildren) resultsNode.getChildren();
resultsNodeChilds.refreshKeys(types);
final TreeView tree = getTree();
tree.expandNode(results);
// @@@ tree.expandNode(results);
Children resultsChilds = results.getChildren();
if (resultsChilds == null) //intermediate state check
{
if (resultsChilds == null) {
return;
}
Node childNode = resultsChilds.findChild(KeywordHits.NAME);
if (childNode == null) //intermediate state check
{
if (childNode == null) {
return;
}
tree.expandNode(childNode);
// @@@tree.expandNode(childNode);
childNode = resultsChilds.findChild(ExtractedContentNode.NAME);
if (childNode == null) //intermediate state check
{
childNode = resultsChilds.findChild(ExtractedContent.NAME);
if (childNode == null) {
return;
}
tree.expandNode(childNode);
//restores selection if it was under the Results node
setSelectedNode(selectedPath, ResultsNode.NAME);
//@@@ setSelectedNode(selectedPath, ResultsNode.NAME);
}
/**
@ -983,7 +981,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
}
} else {
Node extractedContent = resultsChilds.findChild(ExtractedContentNode.NAME);
Node extractedContent = resultsChilds.findChild(ExtractedContent.NAME);
Children extractedChilds = extractedContent.getChildren();
treeNode = extractedChilds.findChild(type.getLabel());
}

View File

@ -1,5 +1,5 @@
#Updated by build script
#Tue, 22 Apr 2014 16:06:14 -0400
#Sat, 03 May 2014 22:45:39 -0400
LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=288
SPLASH_WIDTH=538

View File

@ -1,5 +1,5 @@
#Updated by build script
#Tue, 22 Apr 2014 16:06:14 -0400
#Sat, 03 May 2014 22:45:39 -0400
CTL_MainWindow_Title=Autopsy 3.1.0_Beta
CTL_MainWindow_Title_No_Project=Autopsy 3.1.0_Beta