From 4e78ebce05a8c815eb753f5e80f7eacf08bedb39 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 31 Aug 2021 11:26:42 -0400 Subject: [PATCH 01/14] Modified event name used by plaso --- .../sleuthkit/autopsy/modules/plaso/PlasoIngestModule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/plaso/PlasoIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/plaso/PlasoIngestModule.java index 4d4bd63da6..f2b7e5942f 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/plaso/PlasoIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/plaso/PlasoIngestModule.java @@ -326,7 +326,7 @@ public class PlasoIngestModule implements DataSourceIngestModule { // If the description is empty use the event type display name // as the description. if (description == null || description.isEmpty()) { - if (eventType != TimelineEventType.OTHER) { + if (eventType != TimelineEventType.STANDARD_ARTIFACT_CATCH_ALL) { description = eventType.getDisplayName(); } else { continue; @@ -440,7 +440,7 @@ public class PlasoIngestModule implements DataSourceIngestModule { return TimelineEventType.REGISTRY; } default: - return TimelineEventType.OTHER; + return TimelineEventType.STANDARD_ARTIFACT_CATCH_ALL; } } From a24006cae49c28f4d7d1ee4ed838acf8b3b2bb38 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 7 Sep 2021 11:39:45 -0400 Subject: [PATCH 02/14] work towards interesting hit changes --- .../autopsy/datamodel/InterestingHits.java | 268 +++++++++--------- .../DirectoryTreeTopComponent.java | 55 ++-- 2 files changed, 174 insertions(+), 149 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index f636264082..0e8bbb2a8a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -34,6 +34,8 @@ import java.util.Observable; import java.util.Observer; import java.util.Set; import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; @@ -62,6 +64,11 @@ public class InterestingHits implements AutopsyVisitableItem { private static final Logger logger = Logger.getLogger(InterestingHits.class.getName()); private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED); + private static final Map ART_TYPES = Stream.of( + BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, + BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT + ).collect(Collectors.toMap(tp -> tp.getTypeID(), tp -> tp, (tp1, tp2) -> tp1)); + private SleuthkitCase skCase; private final InterestingResults interestingResults = new InterestingResults(); private final long filteringDSObjId; // 0 if not filtering/grouping by data source @@ -92,20 +99,21 @@ public class InterestingHits implements AutopsyVisitableItem { private class InterestingResults extends Observable { // NOTE: the map can be accessed by multiple worker threads and needs to be synchronized - private final Map>> interestingItemsMap = new LinkedHashMap<>(); + private final Map>> interestingItemsMap = new LinkedHashMap<>(); - public List getSetNames() { + public List getSetNames(BlackboardArtifact.Type type) { List setNames; synchronized (interestingItemsMap) { - setNames = new ArrayList<>(interestingItemsMap.keySet()); + Map> setMapping = interestingItemsMap.getOrDefault(type, Collections.emptyMap()); + setNames = new ArrayList<>(setMapping.keySet()); } Collections.sort(setNames); return setNames; } - public Set getArtifactIds(String setName, String typeName) { + public Set getArtifactIds(BlackboardArtifact.Type type, String setName) { synchronized (interestingItemsMap) { - return interestingItemsMap.get(setName).get(typeName); + return interestingItemsMap.getOrDefault(type, Collections.emptyMap()).getOrDefault(setName, Collections.emptySet()); } } @@ -113,8 +121,7 @@ public class InterestingHits implements AutopsyVisitableItem { synchronized (interestingItemsMap) { interestingItemsMap.clear(); } - loadArtifacts(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT); - loadArtifacts(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT); + loadArtifacts(); setChanged(); notifyObservers(); } @@ -124,18 +131,22 @@ public class InterestingHits implements AutopsyVisitableItem { * the interestingItemsMap */ @SuppressWarnings("deprecation") - private void loadArtifacts(BlackboardArtifact.Type artType) { + private void loadArtifacts() { if (skCase == null) { return; } int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(); - int artId = artType.getTypeID(); - String query = "SELECT value_text,blackboard_artifacts.artifact_obj_id,attribute_type_id " //NON-NLS + + String typeIds = ART_TYPES.keySet().stream() + .map(id -> id.toString()) + .collect(Collectors.joining(", ")); + + String query = "SELECT value_text, blackboard_artifacts.artifact_obj_id, artifact_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 + + " AND blackboard_artifacts.artifact_type_id IN (" + typeIds + ")"; //NON-NLS if (filteringDSObjId > 0) { query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId; } @@ -144,14 +155,14 @@ public class InterestingHits implements AutopsyVisitableItem { synchronized (interestingItemsMap) { ResultSet resultSet = dbQuery.getResultSet(); while (resultSet.next()) { + int artTypeId = resultSet.getInt("artifact_type_id"); + BlackboardArtifact.Type artType = ART_TYPES.get(artTypeId); String value = resultSet.getString("value_text"); //NON-NLS long artifactObjId = resultSet.getLong("artifact_obj_id"); //NON-NLS - if (!interestingItemsMap.containsKey(value)) { - interestingItemsMap.put(value, new LinkedHashMap<>()); - interestingItemsMap.get(value).put(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName(), new HashSet<>()); - interestingItemsMap.get(value).put(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName(), new HashSet<>()); - } - interestingItemsMap.get(value).get(artType.getDisplayName()).add(artifactObjId); + interestingItemsMap + .computeIfAbsent(artType, (k) -> new LinkedHashMap<>()) + .computeIfAbsent(value, (k) -> new HashSet<>()) + .add(artifactObjId); } } } catch (TskCoreException | SQLException ex) { @@ -171,7 +182,7 @@ public class InterestingHits implements AutopsyVisitableItem { public class RootNode extends UpdatableCountTypeNode { public RootNode() { - super(Children.create(new SetNameFactory(), true), + super(Children.create(new HitTypeFactory(), true), Lookups.singleton(DISPLAY_NAME), DISPLAY_NAME, filteringDSObjId, @@ -216,6 +227,94 @@ public class InterestingHits implements AutopsyVisitableItem { private class SetNameFactory extends ChildFactory.Detachable implements Observer { + private final BlackboardArtifact.Type type; + + public SetNameFactory(BlackboardArtifact.Type type) { + this.type = type; + } + + @Override + protected boolean createKeys(List list) { + list.addAll(interestingResults.getSetNames(this.type)); + return true; + } + + @Override + protected Node createNodeForKey(String key) { + return new SetNameNode(this.type, key); + } + + @Override + public void update(Observable o, Object arg) { + refresh(true); + } + } + + public class SetNameNode extends DisplayableItemNode implements Observer { + + private final BlackboardArtifact.Type type; + private final String setName; + + public SetNameNode(BlackboardArtifact.Type type, String setName) {//, Set children) { + super(Children.create(new HitFactory(type, setName), true), Lookups.singleton(setName)); + this.setName = setName; + this.type = type; + super.setName(setName); + updateDisplayName(); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS + interestingResults.addObserver(this); + } + + private void updateDisplayName() { + int sizeOfSet = interestingResults.getArtifactIds(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, setName).size() + + interestingResults.getArtifactIds(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, setName).size(); + super.setDisplayName(setName + " (" + sizeOfSet + ")"); + } + + @Override + public boolean isLeafTypeNode() { + return false; + } + + @Override + protected Sheet createSheet() { + Sheet sheet = super.createSheet(); + Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); + if (sheetSet == null) { + sheetSet = Sheet.createPropertiesSet(); + sheet.put(sheetSet); + } + + sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), + NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), + NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"), + getName())); + + return sheet; + } + + @Override + public T accept(DisplayableItemNodeVisitor visitor) { + return visitor.visit(this); + } + + @Override + public void update(Observable o, Object arg) { + updateDisplayName(); + } + + @Override + public String getItemType() { + /** + * For custom settings for each rule set, return + * getClass().getName() + setName instead. + */ + return getClass().getName(); + } + } + + private class HitTypeFactory extends ChildFactory.Detachable implements Observer { + /* * This should probably be in the top-level class, but the factory has * nice methods for its startup and shutdown, so it seemed like a @@ -272,9 +371,14 @@ public class InterestingHits implements AutopsyVisitableItem { } } }; - + private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); - + + private HitTypeFactory() { + super(); + interestingResults.addObserver(this); + } + @Override protected void addNotify() { IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl); @@ -294,104 +398,15 @@ public class InterestingHits implements AutopsyVisitableItem { } @Override - protected boolean createKeys(List list) { - list.addAll(interestingResults.getSetNames()); + protected boolean createKeys(List list) { + list.add(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT); + list.add(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT); return true; } @Override - protected Node createNodeForKey(String key) { - return new SetNameNode(key); - } - - @Override - public void update(Observable o, Object arg) { - refresh(true); - } - } - - public class SetNameNode extends DisplayableItemNode implements Observer { - - private final String setName; - - public SetNameNode(String setName) {//, Set children) { - super(Children.create(new HitTypeFactory(setName), true), Lookups.singleton(setName)); - this.setName = setName; - super.setName(setName); - updateDisplayName(); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS - interestingResults.addObserver(this); - } - - private void updateDisplayName() { - int sizeOfSet = interestingResults.getArtifactIds(setName, BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()).size() - + interestingResults.getArtifactIds(setName, BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName()).size(); - super.setDisplayName(setName + " (" + sizeOfSet + ")"); - } - - @Override - public boolean isLeafTypeNode() { - return false; - } - - @Override - protected Sheet createSheet() { - Sheet sheet = super.createSheet(); - Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); - if (sheetSet == null) { - sheetSet = Sheet.createPropertiesSet(); - sheet.put(sheetSet); - } - - sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), - NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), - NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"), - getName())); - - return sheet; - } - - @Override - public T accept(DisplayableItemNodeVisitor visitor) { - return visitor.visit(this); - } - - @Override - public void update(Observable o, Object arg) { - updateDisplayName(); - } - - @Override - public String getItemType() { - /** - * For custom settings for each rule set, return - * getClass().getName() + setName instead. - */ - return getClass().getName(); - } - } - - private class HitTypeFactory extends ChildFactory implements Observer { - - private final String setName; - private final Map artifactHits = new HashMap<>(); - - private HitTypeFactory(String setName) { - super(); - this.setName = setName; - interestingResults.addObserver(this); - } - - @Override - protected boolean createKeys(List list) { - list.add(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName()); - list.add(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()); - return true; - } - - @Override - protected Node createNodeForKey(String key) { - return new InterestingItemTypeNode(setName, key); + protected Node createNodeForKey(BlackboardArtifact.Type key) { + return new InterestingItemTypeNode(key); } @Override @@ -402,26 +417,25 @@ public class InterestingHits implements AutopsyVisitableItem { public class InterestingItemTypeNode extends DisplayableItemNode implements Observer { - private final String typeName; - private final String setName; + private final BlackboardArtifact.Type type; + + private InterestingItemTypeNode(BlackboardArtifact.Type type) { + super(Children.create(new SetNameFactory(type), true), Lookups.singleton(type)); + this.type = type; - private InterestingItemTypeNode(String setName, String typeName) { - super(Children.create(new HitFactory(setName, typeName), true), Lookups.singleton(setName)); - this.typeName = typeName; - this.setName = setName; /** * We use the combination of setName and typeName as the name of the * node to ensure that nodes have a unique name. This comes into * play when associating paging state with the node. */ - super.setName(setName + "_" + typeName); + super.setName(type.getDisplayName()); updateDisplayName(); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS interestingResults.addObserver(this); } private void updateDisplayName() { - super.setDisplayName(typeName + " (" + interestingResults.getArtifactIds(setName, typeName).size() + ")"); + super.setDisplayName(type.getDisplayName() + " (" + interestingResults.getSetNames(type).size() + ")"); } @Override @@ -466,19 +480,19 @@ public class InterestingHits implements AutopsyVisitableItem { private class HitFactory extends BaseChildFactory implements Observer { + private final BlackboardArtifact.Type type; private final String setName; - private final String typeName; private final Map artifactHits = new HashMap<>(); - private HitFactory(String setName, String typeName) { + private HitFactory(BlackboardArtifact.Type type, String setName) { /** * The node name passed to the parent constructor must be the same * as the name set in the InterestingItemTypeNode constructor, i.e. * setName underscore typeName */ - super(setName + "_" + typeName); + super(setName + "_" + type.getDisplayName()); this.setName = setName; - this.typeName = typeName; + this.type = type; interestingResults.addObserver(this); } @@ -486,7 +500,7 @@ public class InterestingHits implements AutopsyVisitableItem { protected List makeKeys() { if (skCase != null) { - interestingResults.getArtifactIds(setName, typeName).forEach((id) -> { + interestingResults.getArtifactIds(type, setName).forEach((id) -> { try { if (!artifactHits.containsKey(id)) { AnalysisResult art = skCase.getBlackboard().getAnalysisResultById(id); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 975a659aa7..258e692f39 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -1409,34 +1409,45 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat private Node getInterestingItemNode(Children typesChildren, BlackboardArtifact art) { Node interestingItemsRootNode = typesChildren.findChild(NbBundle .getMessage(InterestingHits.class, "InterestingHits.interestingItems.text")); + Children interestingItemsRootChildren = interestingItemsRootNode.getChildren(); + String setName = null; try { - String setName = null; - List attributes = art.getAttributes(); - for (BlackboardAttribute att : attributes) { - int typeId = att.getAttributeType().getTypeID(); - if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { - setName = att.getValueString(); - } - } - Node setNode = interestingItemsRootChildren.findChild(setName); - if (setNode == null) { - return null; - } - - Children fileArtifactChildren = setNode.getChildren(); - Node[] fileArtifactNodes = fileArtifactChildren == null ? null : fileArtifactChildren.getNodes(); - if (fileArtifactNodes == null || fileArtifactNodes.length != 2) { - return null; - } - - return (art.getArtifactTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID()) - ? fileArtifactNodes[0] - : fileArtifactNodes[1]; + setName = art.getAttributes().stream() + .filter(attr -> attr.getAttributeType().getTypeID() == BlackboardAttribute.Type.TSK_SET_NAME.getTypeID()) + .map(attr -> attr.getValueString()) + .findFirst() + .orElse(null); + } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS return null; } + + // if no set name, no set node will be identified. + if (setName == null) { + return null; + } + + Stream typeNodes = interestingItemsRootChildren != null ? Stream.of(interestingItemsRootChildren.getNodes(true)) : Stream.empty(); + + Children setNodeChildren = typeNodes + .filter((nd) -> { + BlackboardArtifact.Type ndType = nd.getLookup().lookup(BlackboardArtifact.Type.class); + return ndType != null && ndType.getTypeID() == art.getArtifactTypeID(); + }) + .findFirst() + .flatMap(typeNode -> Optional.ofNullable(typeNode.getChildren())) + .orElse(null); + + // set node children for type could not be found, so return null. + if (setNodeChildren == null) { + return null; + } + + // make sure data is fully loaded + setNodeChildren.getNodes(true); + return interestingItemsRootChildren.findChild(setName); } /** From 4e38a562c764eb45242e048d8f3abdbebd9be05b Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 7 Sep 2021 12:32:31 -0400 Subject: [PATCH 03/14] commenting --- .../autopsy/datamodel/InterestingHits.java | 72 ++++++++++++++++--- 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 0e8bbb2a8a..3bdd47eca3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -96,12 +96,22 @@ public class InterestingHits implements AutopsyVisitableItem { interestingResults.update(); } + /** + * Cache of result ids mapped by artifact type -> set name -> artifact id. + */ private class InterestingResults extends Observable { // NOTE: the map can be accessed by multiple worker threads and needs to be synchronized private final Map>> interestingItemsMap = new LinkedHashMap<>(); - public List getSetNames(BlackboardArtifact.Type type) { + /** + * Returns all the set names for a given interesting item type. + * + * @param type The interesting item type. + * + * @return The set names. + */ + List getSetNames(BlackboardArtifact.Type type) { List setNames; synchronized (interestingItemsMap) { Map> setMapping = interestingItemsMap.getOrDefault(type, Collections.emptyMap()); @@ -111,13 +121,25 @@ public class InterestingHits implements AutopsyVisitableItem { return setNames; } - public Set getArtifactIds(BlackboardArtifact.Type type, String setName) { + /** + * Returns all artifact ids belonging to the specified interesting item + * type and set name. + * + * @param type The interesting item type. + * @param setName The set name. + * + * @return The artifact ids in that set name and type. + */ + Set getArtifactIds(BlackboardArtifact.Type type, String setName) { synchronized (interestingItemsMap) { return interestingItemsMap.getOrDefault(type, Collections.emptyMap()).getOrDefault(setName, Collections.emptySet()); } } - public void update() { + /** + * Triggers a fetch from the database to update this cache. + */ + void update() { synchronized (interestingItemsMap) { interestingItemsMap.clear(); } @@ -225,11 +247,19 @@ public class InterestingHits implements AutopsyVisitableItem { } } + /** + * Creates nodes for all sets for a specified interesting item type. + */ private class SetNameFactory extends ChildFactory.Detachable implements Observer { private final BlackboardArtifact.Type type; - public SetNameFactory(BlackboardArtifact.Type type) { + /** + * Constructor. + * + * @param type The artifact type to filter these sets. + */ + SetNameFactory(BlackboardArtifact.Type type) { this.type = type; } @@ -250,24 +280,26 @@ public class InterestingHits implements AutopsyVisitableItem { } } + /** + * A node for a set to be displayed in the tree. + */ public class SetNameNode extends DisplayableItemNode implements Observer { - private final BlackboardArtifact.Type type; private final String setName; + private final BlackboardArtifact.Type type; public SetNameNode(BlackboardArtifact.Type type, String setName) {//, Set children) { super(Children.create(new HitFactory(type, setName), true), Lookups.singleton(setName)); this.setName = setName; this.type = type; - super.setName(setName); + super.setName(type.getDisplayName() + "_" + setName); updateDisplayName(); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS interestingResults.addObserver(this); } private void updateDisplayName() { - int sizeOfSet = interestingResults.getArtifactIds(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, setName).size() - + interestingResults.getArtifactIds(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, setName).size(); + int sizeOfSet = interestingResults.getArtifactIds(type, setName).size(); super.setDisplayName(setName + " (" + sizeOfSet + ")"); } @@ -313,6 +345,9 @@ public class InterestingHits implements AutopsyVisitableItem { } } + /** + * Shows an Interesting Item type node (i.e. file hit or artifact hit). + */ private class HitTypeFactory extends ChildFactory.Detachable implements Observer { /* @@ -399,8 +434,7 @@ public class InterestingHits implements AutopsyVisitableItem { @Override protected boolean createKeys(List list) { - list.add(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT); - list.add(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT); + list.addAll(ART_TYPES.values()); return true; } @@ -415,10 +449,18 @@ public class InterestingHits implements AutopsyVisitableItem { } } + /** + * Parent node for interesting item type that shows child set nodes. + */ public class InterestingItemTypeNode extends DisplayableItemNode implements Observer { private final BlackboardArtifact.Type type; + /** + * Main constructor. + * + * @param type The artifact type to display. + */ private InterestingItemTypeNode(BlackboardArtifact.Type type) { super(Children.create(new SetNameFactory(type), true), Lookups.singleton(type)); this.type = type; @@ -478,12 +520,22 @@ public class InterestingHits implements AutopsyVisitableItem { } } + /** + * Factory for creating individual interesting item BlackboardArtifactNodes. + */ private class HitFactory extends BaseChildFactory implements Observer { private final BlackboardArtifact.Type type; private final String setName; private final Map artifactHits = new HashMap<>(); + /** + * Main constructor. + * + * @param type The Interesting Item type of artifacts to be + * displayed. + * @param setName The set name of artifacts to be displayed. + */ private HitFactory(BlackboardArtifact.Type type, String setName) { /** * The node name passed to the parent constructor must be the same From 927a93084b3fcf78e926baa3567182103cfc8eb3 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 7 Sep 2021 13:11:36 -0400 Subject: [PATCH 04/14] bug fixes --- .../autopsy/datamodel/InterestingHits.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 3bdd47eca3..1646210506 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -120,6 +120,19 @@ public class InterestingHits implements AutopsyVisitableItem { Collections.sort(setNames); return setNames; } + + /** + * Returns all types currently in the map. + * @return The types present in the map. + */ + List getTypes() { + List types; + synchronized (interestingItemsMap) { + types = new ArrayList<>(interestingItemsMap.keySet()); + } + Collections.sort(types, (a,b) -> a.getDisplayName().compareToIgnoreCase(b.getDisplayName())); + return types; + } /** * Returns all artifact ids belonging to the specified interesting item @@ -164,7 +177,7 @@ public class InterestingHits implements AutopsyVisitableItem { .map(id -> id.toString()) .collect(Collectors.joining(", ")); - String query = "SELECT value_text, blackboard_artifacts.artifact_obj_id, artifact_type_id " //NON-NLS + String query = "SELECT value_text, blackboard_artifacts.artifact_obj_id, blackboard_artifacts.artifact_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 @@ -434,7 +447,7 @@ public class InterestingHits implements AutopsyVisitableItem { @Override protected boolean createKeys(List list) { - list.addAll(ART_TYPES.values()); + list.addAll(interestingResults.getTypes()); return true; } @@ -482,7 +495,7 @@ public class InterestingHits implements AutopsyVisitableItem { @Override public boolean isLeafTypeNode() { - return true; + return false; } @Override From 7adfcf4b178df287e625c0d51c776e25a14bfc9c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 8 Sep 2021 14:19:52 -0400 Subject: [PATCH 05/14] fixes --- .../autopsy/datamodel/InterestingHits.java | 20 +++++++++++++++---- .../DirectoryTreeTopComponent.java | 17 +++++++++------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 1646210506..4469e76356 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -117,12 +117,13 @@ public class InterestingHits implements AutopsyVisitableItem { Map> setMapping = interestingItemsMap.getOrDefault(type, Collections.emptyMap()); setNames = new ArrayList<>(setMapping.keySet()); } - Collections.sort(setNames); + Collections.sort(setNames, (a, b) -> a.compareToIgnoreCase(b)); return setNames; } - + /** * Returns all types currently in the map. + * * @return The types present in the map. */ List getTypes() { @@ -130,7 +131,7 @@ public class InterestingHits implements AutopsyVisitableItem { synchronized (interestingItemsMap) { types = new ArrayList<>(interestingItemsMap.keySet()); } - Collections.sort(types, (a,b) -> a.getDisplayName().compareToIgnoreCase(b.getDisplayName())); + Collections.sort(types, (a, b) -> a.getDisplayName().compareToIgnoreCase(b.getDisplayName())); return types; } @@ -287,6 +288,17 @@ public class InterestingHits implements AutopsyVisitableItem { return new SetNameNode(this.type, key); } + @Override + protected void addNotify() { + interestingResults.update(); + interestingResults.addObserver(this); + } + + @Override + protected void finalize() throws Throwable { + interestingResults.deleteObserver(this); + } + @Override public void update(Observable o, Object arg) { refresh(true); @@ -318,7 +330,7 @@ public class InterestingHits implements AutopsyVisitableItem { @Override public boolean isLeafTypeNode() { - return false; + return true; } @Override diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 258e692f39..3732f3c219 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -1409,7 +1409,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat private Node getInterestingItemNode(Children typesChildren, BlackboardArtifact art) { Node interestingItemsRootNode = typesChildren.findChild(NbBundle .getMessage(InterestingHits.class, "InterestingHits.interestingItems.text")); - + Children interestingItemsRootChildren = interestingItemsRootNode.getChildren(); String setName = null; try { @@ -1418,17 +1418,17 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat .map(attr -> attr.getValueString()) .findFirst() .orElse(null); - + } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS return null; } - + // if no set name, no set node will be identified. if (setName == null) { return null; } - + Stream typeNodes = interestingItemsRootChildren != null ? Stream.of(interestingItemsRootChildren.getNodes(true)) : Stream.empty(); Children setNodeChildren = typeNodes @@ -1444,10 +1444,13 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat if (setNodeChildren == null) { return null; } - + // make sure data is fully loaded - setNodeChildren.getNodes(true); - return interestingItemsRootChildren.findChild(setName); + final String finalSetName = setName; + return Stream.of(setNodeChildren.getNodes(true)) + .filter(setNode -> finalSetName.equals(setNode.getLookup().lookup(String.class))) + .findFirst() + .orElse(null); } /** From 4bb97995b27dedb89985f2547c7fdbf5a0a0abb1 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 8 Sep 2021 15:33:04 -0400 Subject: [PATCH 06/14] tree structure changes --- .../autopsy/datamodel/Artifacts.java | 40 +- .../datamodel/DisplayableItemNodeVisitor.java | 23 +- .../autopsy/datamodel/InterestingHits.java | 364 ++++++------------ .../DirectoryTreeTopComponent.java | 39 +- 4 files changed, 153 insertions(+), 313 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index cd0b03fd98..3f08b3f0bb 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -250,18 +250,16 @@ public class Artifacts { KeywordHits.RootNode keywordsNode = new KeywordHits(skCase, dsObjId).new RootNode(); return new TypeNodeKey(keywordsNode, TSK_KEYWORD_HIT); - } else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId - || TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) { - - InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, dsObjId).new RootNode(); - return new TypeNodeKey(interestingHitsNode, - TSK_INTERESTING_ARTIFACT_HIT, - TSK_INTERESTING_FILE_HIT); - + } else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId) { + InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, TSK_INTERESTING_ARTIFACT_HIT, dsObjId).new RootNode(); + return new TypeNodeKey(interestingHitsNode, TSK_INTERESTING_ARTIFACT_HIT); + } else if (TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) { + InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, TSK_INTERESTING_FILE_HIT, dsObjId).new RootNode(); + return new TypeNodeKey(interestingHitsNode, TSK_INTERESTING_FILE_HIT); } else if (TSK_HASHSET_HIT.getTypeID() == typeId) { HashsetHits.RootNode hashsetHits = new HashsetHits(skCase, dsObjId).new RootNode(); return new TypeNodeKey(hashsetHits, TSK_HASHSET_HIT); - + } else { return new TypeNodeKey(type, dsObjId); } @@ -278,7 +276,7 @@ public class Artifacts { */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); private final Category category; - + private final PropertyChangeListener weakPcl; /** @@ -293,7 +291,7 @@ public class Artifacts { super(); this.filteringDSObjId = filteringDSObjId; this.category = category; - + PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { String eventType = evt.getPropertyName(); if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { @@ -322,9 +320,9 @@ public class Artifacts { weakPcl = WeakListeners.propertyChange(pcl, null); } - + @Override - protected void addNotify() { + protected void addNotify() { super.addNotify(); refreshThrottler.registerForIngestModuleEvents(); IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl); @@ -632,7 +630,7 @@ public class Artifacts { } } }; - + private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); @Override @@ -643,7 +641,7 @@ public class Artifacts { @Override protected void onRemove() { - if(refreshThrottler != null) { + if (refreshThrottler != null) { refreshThrottler.unregisterEventListener(); } IngestManager.getInstance().removeIngestJobEventListener(weakPcl); @@ -663,14 +661,14 @@ public class Artifacts { case ANALYSIS_RESULT: arts = (filteringDSObjId > 0) - ? blackboard.getAnalysisResultsByType(type.getTypeID(), filteringDSObjId) - : blackboard.getAnalysisResultsByType(type.getTypeID()); + ? blackboard.getAnalysisResultsByType(type.getTypeID(), filteringDSObjId) + : blackboard.getAnalysisResultsByType(type.getTypeID()); break; case DATA_ARTIFACT: default: arts = (filteringDSObjId > 0) - ? blackboard.getDataArtifacts(type.getTypeID(), filteringDSObjId) - : blackboard.getDataArtifacts(type.getTypeID()); + ? blackboard.getDataArtifacts(type.getTypeID(), filteringDSObjId) + : blackboard.getDataArtifacts(type.getTypeID()); break; } @@ -679,9 +677,9 @@ public class Artifacts { //See JIRA-5969 art.getAttributes(); } - + @SuppressWarnings("unchecked") - List toRet = (List)(List)arts; + List toRet = (List) (List) arts; return toRet; } catch (NoCurrentCaseException ex) { logger.log(Level.WARNING, "Trying to access case when no case is open.", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 47db7732ea..1acce2bb7e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -181,15 +181,13 @@ public interface DisplayableItemNodeVisitor { T visit(EmptyNode.MessageNode emptyNode); - T visit(InterestingHits.InterestingItemTypeNode aThis); - /* * Attachments */ T visit(AttachmentNode node); - + T visit(OsAccounts.OsAccountNode node); - + T visit(OsAccounts.OsAccountListNode node); T visit(PersonNode node); @@ -197,12 +195,12 @@ public interface DisplayableItemNodeVisitor { T visit(HostNode node); T visit(DataSourcesNode node); - + /* * Unsupported node */ T visit(UnsupportedContentNode ucn); - + T visit(LocalFilesDataSourceNode lfdsn); /** @@ -332,11 +330,6 @@ public interface DisplayableItemNodeVisitor { return defaultVisit(ftByMimeTypeEmptyNode); } - @Override - public T visit(InterestingHits.InterestingItemTypeNode interestingItemTypeNode) { - return defaultVisit(interestingItemTypeNode); - } - @Override public T visit(DeletedContentNode dcn) { return defaultVisit(dcn); @@ -546,12 +539,12 @@ public interface DisplayableItemNodeVisitor { public T visit(AttachmentNode node) { return defaultVisit(node); } - + @Override public T visit(OsAccounts.OsAccountNode node) { return defaultVisit(node); } - + @Override public T visit(OsAccounts.OsAccountListNode node) { return defaultVisit(node); @@ -571,12 +564,12 @@ public interface DisplayableItemNodeVisitor { public T visit(PersonNode node) { return defaultVisit(node); } - + @Override public T visit(UnsupportedContentNode node) { return defaultVisit(node); } - + @Override public T visit(LocalFilesDataSourceNode node) { return defaultVisit(node); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 4469e76356..c22d095726 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -34,8 +34,6 @@ import java.util.Observable; import java.util.Observer; import java.util.Set; import java.util.logging.Level; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; @@ -53,45 +51,44 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; import org.sleuthkit.datamodel.AnalysisResult; +import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; public class InterestingHits implements AutopsyVisitableItem { - private static final String INTERESTING_ITEMS = NbBundle - .getMessage(InterestingHits.class, "InterestingHits.interestingItems.text"); - private static final String DISPLAY_NAME = NbBundle.getMessage(InterestingHits.class, "InterestingHits.displayName.text"); private static final Logger logger = Logger.getLogger(InterestingHits.class.getName()); private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED); - private static final Map ART_TYPES = Stream.of( - BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, - BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT - ).collect(Collectors.toMap(tp -> tp.getTypeID(), tp -> tp, (tp1, tp2) -> tp1)); private SleuthkitCase skCase; private final InterestingResults interestingResults = new InterestingResults(); private final long filteringDSObjId; // 0 if not filtering/grouping by data source + private final BlackboardArtifact.Type artifactType; /** * Constructor * - * @param skCase Case DB + * @param skCase Case DB + * @param artifactType The artifact type (either interesting file or + * artifact). * */ - public InterestingHits(SleuthkitCase skCase) { - this(skCase, 0); + public InterestingHits(SleuthkitCase skCase, BlackboardArtifact.Type artifactType) { + this(skCase, artifactType, 0); } /** * Constructor * - * @param skCase Case DB - * @param objId Object id of the data source + * @param skCase Case DB + * @param artifactType The artifact type (either interesting file or + * artifact). + * @param objId Object id of the data source * */ - public InterestingHits(SleuthkitCase skCase, long objId) { + public InterestingHits(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, long objId) { this.skCase = skCase; + this.artifactType = artifactType; this.filteringDSObjId = objId; interestingResults.update(); } @@ -102,7 +99,7 @@ public class InterestingHits implements AutopsyVisitableItem { private class InterestingResults extends Observable { // NOTE: the map can be accessed by multiple worker threads and needs to be synchronized - private final Map>> interestingItemsMap = new LinkedHashMap<>(); + private final Map> interestingItemsMap = new LinkedHashMap<>(); /** * Returns all the set names for a given interesting item type. @@ -111,30 +108,15 @@ public class InterestingHits implements AutopsyVisitableItem { * * @return The set names. */ - List getSetNames(BlackboardArtifact.Type type) { + List getSetNames() { List setNames; synchronized (interestingItemsMap) { - Map> setMapping = interestingItemsMap.getOrDefault(type, Collections.emptyMap()); - setNames = new ArrayList<>(setMapping.keySet()); + setNames = new ArrayList<>(interestingItemsMap.keySet()); } Collections.sort(setNames, (a, b) -> a.compareToIgnoreCase(b)); return setNames; } - /** - * Returns all types currently in the map. - * - * @return The types present in the map. - */ - List getTypes() { - List types; - synchronized (interestingItemsMap) { - types = new ArrayList<>(interestingItemsMap.keySet()); - } - Collections.sort(types, (a, b) -> a.getDisplayName().compareToIgnoreCase(b.getDisplayName())); - return types; - } - /** * Returns all artifact ids belonging to the specified interesting item * type and set name. @@ -144,9 +126,9 @@ public class InterestingHits implements AutopsyVisitableItem { * * @return The artifact ids in that set name and type. */ - Set getArtifactIds(BlackboardArtifact.Type type, String setName) { + Set getArtifactIds(String setName) { synchronized (interestingItemsMap) { - return interestingItemsMap.getOrDefault(type, Collections.emptyMap()).getOrDefault(setName, Collections.emptySet()); + return new HashSet<>(interestingItemsMap.getOrDefault(setName, Collections.emptySet())); } } @@ -174,15 +156,11 @@ public class InterestingHits implements AutopsyVisitableItem { int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(); - String typeIds = ART_TYPES.keySet().stream() - .map(id -> id.toString()) - .collect(Collectors.joining(", ")); - - String query = "SELECT value_text, blackboard_artifacts.artifact_obj_id, blackboard_artifacts.artifact_type_id " //NON-NLS + String query = "SELECT value_text, blackboard_artifacts.artifact_obj_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 IN (" + typeIds + ")"; //NON-NLS + + " AND blackboard_artifacts.artifact_type_id = " + artifactType.getTypeID(); //NON-NLS if (filteringDSObjId > 0) { query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId; } @@ -191,12 +169,9 @@ public class InterestingHits implements AutopsyVisitableItem { synchronized (interestingItemsMap) { ResultSet resultSet = dbQuery.getResultSet(); while (resultSet.next()) { - int artTypeId = resultSet.getInt("artifact_type_id"); - BlackboardArtifact.Type artType = ART_TYPES.get(artTypeId); String value = resultSet.getString("value_text"); //NON-NLS long artifactObjId = resultSet.getLong("artifact_obj_id"); //NON-NLS interestingItemsMap - .computeIfAbsent(artType, (k) -> new LinkedHashMap<>()) .computeIfAbsent(value, (k) -> new HashSet<>()) .add(artifactObjId); } @@ -212,97 +187,102 @@ public class InterestingHits implements AutopsyVisitableItem { return visitor.visit(this); } - /** - * Node for the interesting items - */ - public class RootNode extends UpdatableCountTypeNode { - - public RootNode() { - super(Children.create(new HitTypeFactory(), true), - Lookups.singleton(DISPLAY_NAME), - DISPLAY_NAME, - filteringDSObjId, - BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, - BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT); - super.setName(INTERESTING_ITEMS); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS - } - - @Override - public boolean isLeafTypeNode() { - return false; - } - - @Override - public T accept(DisplayableItemNodeVisitor visitor) { - return visitor.visit(this); - } - - @Override - protected Sheet createSheet() { - Sheet sheet = super.createSheet(); - Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); - if (sheetSet == null) { - sheetSet = Sheet.createPropertiesSet(); - sheet.put(sheetSet); - } - - sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.name"), - NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.displayName"), - NbBundle.getMessage(this.getClass(), "InterestingHits.createSheet.name.desc"), - getName())); - - return sheet; - } - - @Override - public String getItemType() { - return getClass().getName(); - } - } - /** * Creates nodes for all sets for a specified interesting item type. */ private class SetNameFactory extends ChildFactory.Detachable implements Observer { - private final BlackboardArtifact.Type type; - - /** - * Constructor. - * - * @param type The artifact type to filter these sets. + /* + * This should probably be in the top-level 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. */ - SetNameFactory(BlackboardArtifact.Type type) { - this.type = type; - } + private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { + String eventType = evt.getPropertyName(); + if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { + /** + * Checking for a current case is a stop gap measure until a + * different way of handling the closing of cases is worked out. + * Currently, remote events may be received for a case that is + * already closed. + */ + try { + Case.getCurrentCaseThrows(); + /** + * Even with the check above, it is still possible that the + * case will be closed in a different thread before this + * code executes. If that happens, it is possible for the + * event to have a null oldValue. + */ + ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); + if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == artifactType.getTypeID())) { + interestingResults.update(); + } + } catch (NoCurrentCaseException notUsed) { + /** + * Case is closed, do nothing. + */ + } + } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) + || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { + /** + * Checking for a current case is a stop gap measure until a + * different way of handling the closing of cases is worked out. + * Currently, remote events may be received for a case that is + * already closed. + */ + try { + Case.getCurrentCaseThrows(); + interestingResults.update(); + } catch (NoCurrentCaseException notUsed) { + /** + * Case is closed, do nothing. + */ + } + } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { + // case was closed. Remove listeners so that we don't get called with a stale case handle + if (evt.getNewValue() == null) { + removeNotify(); + skCase = null; + } + } + }; + + private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); @Override protected boolean createKeys(List list) { - list.addAll(interestingResults.getSetNames(this.type)); + list.addAll(interestingResults.getSetNames()); return true; } @Override protected Node createNodeForKey(String key) { - return new SetNameNode(this.type, key); - } - - @Override - protected void addNotify() { - interestingResults.update(); - interestingResults.addObserver(this); - } - - @Override - protected void finalize() throws Throwable { - interestingResults.deleteObserver(this); + return new SetNameNode(key); } @Override public void update(Observable o, Object arg) { refresh(true); } + + @Override + protected void addNotify() { + IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl); + IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl); + Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); + interestingResults.addObserver(this); + interestingResults.update(); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + IngestManager.getInstance().removeIngestJobEventListener(weakPcl); + IngestManager.getInstance().removeIngestModuleEventListener(weakPcl); + Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); + interestingResults.deleteObserver(this); + } } /** @@ -311,20 +291,18 @@ public class InterestingHits implements AutopsyVisitableItem { public class SetNameNode extends DisplayableItemNode implements Observer { private final String setName; - private final BlackboardArtifact.Type type; - public SetNameNode(BlackboardArtifact.Type type, String setName) {//, Set children) { - super(Children.create(new HitFactory(type, setName), true), Lookups.singleton(setName)); + public SetNameNode(String setName) {//, Set children) { + super(Children.create(new HitFactory(setName), true), Lookups.singleton(setName)); this.setName = setName; - this.type = type; - super.setName(type.getDisplayName() + "_" + setName); + super.setName(setName); updateDisplayName(); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS interestingResults.addObserver(this); } private void updateDisplayName() { - int sizeOfSet = interestingResults.getArtifactIds(type, setName).size(); + int sizeOfSet = interestingResults.getArtifactIds(setName).size(); super.setDisplayName(setName + " (" + sizeOfSet + ")"); } @@ -370,139 +348,28 @@ public class InterestingHits implements AutopsyVisitableItem { } } - /** - * Shows an Interesting Item type node (i.e. file hit or artifact hit). - */ - private class HitTypeFactory extends ChildFactory.Detachable implements Observer { - - /* - * This should probably be in the top-level 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 = (PropertyChangeEvent evt) -> { - String eventType = evt.getPropertyName(); - if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { - /** - * Checking for a current case is a stop gap measure until a - * different way of handling the closing of cases is worked out. - * Currently, remote events may be received for a case that is - * already closed. - */ - try { - Case.getCurrentCaseThrows(); - /** - * Even with the check above, it is still possible that the - * case will be closed in a different thread before this - * code executes. If that happens, it is possible for the - * event to have a null oldValue. - */ - ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); - if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() - || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID())) { - interestingResults.update(); - } - } catch (NoCurrentCaseException notUsed) { - /** - * Case is closed, do nothing. - */ - } - } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) - || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { - /** - * Checking for a current case is a stop gap measure until a - * different way of handling the closing of cases is worked out. - * Currently, remote events may be received for a case that is - * already closed. - */ - try { - Case.getCurrentCaseThrows(); - interestingResults.update(); - } catch (NoCurrentCaseException notUsed) { - /** - * Case is closed, do nothing. - */ - } - } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { - // case was closed. Remove listeners so that we don't get called with a stale case handle - if (evt.getNewValue() == null) { - removeNotify(); - skCase = null; - } - } - }; - - private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); - - private HitTypeFactory() { - super(); - interestingResults.addObserver(this); - } - - @Override - protected void addNotify() { - IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl); - IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl); - Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); - interestingResults.update(); - interestingResults.addObserver(this); - } - - @Override - protected void finalize() throws Throwable { - super.finalize(); - IngestManager.getInstance().removeIngestJobEventListener(weakPcl); - IngestManager.getInstance().removeIngestModuleEventListener(weakPcl); - Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); - interestingResults.deleteObserver(this); - } - - @Override - protected boolean createKeys(List list) { - list.addAll(interestingResults.getTypes()); - return true; - } - - @Override - protected Node createNodeForKey(BlackboardArtifact.Type key) { - return new InterestingItemTypeNode(key); - } - - @Override - public void update(Observable o, Object arg) { - refresh(true); - } - } - /** * Parent node for interesting item type that shows child set nodes. */ - public class InterestingItemTypeNode extends DisplayableItemNode implements Observer { - - private final BlackboardArtifact.Type type; + public class RootNode extends UpdatableCountTypeNode { /** * Main constructor. - * - * @param type The artifact type to display. */ - private InterestingItemTypeNode(BlackboardArtifact.Type type) { - super(Children.create(new SetNameFactory(type), true), Lookups.singleton(type)); - this.type = type; + public RootNode() { + super(Children.create(new SetNameFactory(), true), + Lookups.singleton(artifactType), + artifactType.getDisplayName(), + filteringDSObjId, + artifactType); /** * We use the combination of setName and typeName as the name of the * node to ensure that nodes have a unique name. This comes into * play when associating paging state with the node. */ - super.setName(type.getDisplayName()); - updateDisplayName(); + setName(artifactType.getDisplayName()); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS - interestingResults.addObserver(this); - } - - private void updateDisplayName() { - super.setDisplayName(type.getDisplayName() + " (" + interestingResults.getSetNames(type).size() + ")"); } @Override @@ -530,11 +397,6 @@ public class InterestingHits implements AutopsyVisitableItem { return visitor.visit(this); } - @Override - public void update(Observable o, Object arg) { - updateDisplayName(); - } - @Override public String getItemType() { /** @@ -550,26 +412,22 @@ public class InterestingHits implements AutopsyVisitableItem { */ private class HitFactory extends BaseChildFactory implements Observer { - private final BlackboardArtifact.Type type; private final String setName; private final Map artifactHits = new HashMap<>(); /** * Main constructor. * - * @param type The Interesting Item type of artifacts to be - * displayed. * @param setName The set name of artifacts to be displayed. */ - private HitFactory(BlackboardArtifact.Type type, String setName) { + private HitFactory(String setName) { /** * The node name passed to the parent constructor must be the same * as the name set in the InterestingItemTypeNode constructor, i.e. * setName underscore typeName */ - super(setName + "_" + type.getDisplayName()); + super(setName); this.setName = setName; - this.type = type; interestingResults.addObserver(this); } @@ -577,7 +435,7 @@ public class InterestingHits implements AutopsyVisitableItem { protected List makeKeys() { if (skCase != null) { - interestingResults.getArtifactIds(type, setName).forEach((id) -> { + interestingResults.getArtifactIds(setName).forEach((id) -> { try { if (!artifactHits.containsKey(id)) { AnalysisResult art = skCase.getBlackboard().getAnalysisResultById(id); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 3732f3c219..6cd838b834 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -1271,9 +1271,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat treeNode = getHashsetNode(typesChildren, art); } else if (typeID == BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeID()) { treeNode = getKeywordHitNode(typesChildren, art); - } else if (typeID == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID() - || typeID == BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { - treeNode = getInterestingItemNode(typesChildren, art); + } else if (typeID == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID()) { + treeNode = getInterestingItemNode(typesChildren, BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, art); + } else if (typeID == BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { + treeNode = getInterestingItemNode(typesChildren, BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, art); } else if (typeID == BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeID()) { treeNode = getEmailNode(typesChildren, art); } else if (typeID == BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID()) { @@ -1401,16 +1402,22 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * * @param typesChildren The children object of the same category as * interesting item. + * @param artifactType The type of the artifact (interesting hit or + * artifact). * @param art The artifact. * * @return The interesting item artifact's parent node or null if cannot be * found. */ - private Node getInterestingItemNode(Children typesChildren, BlackboardArtifact art) { - Node interestingItemsRootNode = typesChildren.findChild(NbBundle - .getMessage(InterestingHits.class, "InterestingHits.interestingItems.text")); - - Children interestingItemsRootChildren = interestingItemsRootNode.getChildren(); + private Node getInterestingItemNode(Children typesChildren, BlackboardArtifact.Type artifactType, BlackboardArtifact art) { + Node interestingItemsRootNode = typesChildren.findChild(artifactType.getDisplayName()); + Children setNodeChildren = (interestingItemsRootNode == null) ? null : interestingItemsRootNode.getChildren(); + + // set node children for type could not be found, so return null. + if (setNodeChildren == null) { + return null; + } + String setName = null; try { setName = art.getAttributes().stream() @@ -1429,22 +1436,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat return null; } - Stream typeNodes = interestingItemsRootChildren != null ? Stream.of(interestingItemsRootChildren.getNodes(true)) : Stream.empty(); - - Children setNodeChildren = typeNodes - .filter((nd) -> { - BlackboardArtifact.Type ndType = nd.getLookup().lookup(BlackboardArtifact.Type.class); - return ndType != null && ndType.getTypeID() == art.getArtifactTypeID(); - }) - .findFirst() - .flatMap(typeNode -> Optional.ofNullable(typeNode.getChildren())) - .orElse(null); - - // set node children for type could not be found, so return null. - if (setNodeChildren == null) { - return null; - } - // make sure data is fully loaded final String finalSetName = setName; return Stream.of(setNodeChildren.getNodes(true)) From 6e23197047d291b8ea87b79a7ae9505ff010c6f0 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 8 Sep 2021 19:42:21 -0400 Subject: [PATCH 07/14] remove deprecated method --- .../directorytree/FileSearchAction.java | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java index a3f64f1e13..348d3d5148 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java @@ -23,31 +23,28 @@ import javax.swing.AbstractAction; import org.openide.util.Lookup; /** - * - * @author dfickling + * The “File Search by Attributes” action for data sources in the tree. */ public class FileSearchAction extends AbstractAction { - private final Long dataSourceId; + private final long dataSourceId; + /** + * Main constructor. + * + * @param title The display name for the action. + * @param dataSourceID The data source id of the item that is selected in + * the tree. + */ public FileSearchAction(String title, long dataSourceID) { super(title); dataSourceId = dataSourceID; } - public FileSearchAction(String title) { - super(title); - dataSourceId = null; - } - @Override public void actionPerformed(ActionEvent e) { FileSearchProvider searcher = Lookup.getDefault().lookup(FileSearchProvider.class); - if (dataSourceId == null) { - searcher.showDialog(); - } else { - searcher.showDialog(dataSourceId); - } + searcher.showDialog(dataSourceId); } } From 16a3ca7e72ce328a482d2ad13fdd4dbe764bc360 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 8 Sep 2021 20:37:52 -0400 Subject: [PATCH 08/14] Removed flagging of previously seen personas --- .../eventlisteners/IngestEventsListener.java | 98 +------------------ 1 file changed, 1 insertion(+), 97 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 1dad86dd90..cd9e03c9aa 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -42,7 +42,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeIns import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; -import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -57,15 +56,12 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_TYPE; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_VALUE; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_OTHER_CASES; -import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME; -import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT; import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisEvent; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.centralrepository.datamodel.Persona; import org.sleuthkit.datamodel.Score; import org.sleuthkit.datamodel.TskData; @@ -318,77 +314,7 @@ public class IngestEventsListener { value)); makeAndPostArtifact(BlackboardArtifact.Type.TSK_PREVIOUSLY_UNSEEN, originalArtifact, attributesForNewArtifact, "", Score.SCORE_LIKELY_NOTABLE, "This application has not been previously seen before"); - } - - /** - * *TEMPORARY* Create a "matching persona" hit for an artifact with an account identifier - * associated with a persona - * - * @param originalArtifact the artifact to create the "previously unseen" item - * for - */ - static private void makeAndPostMatchingPersonaArtifact(BlackboardArtifact originalArtifact, Persona persona, - List caseDisplayNames, CorrelationAttributeInstance.Type aType, String value) { - String prevCases = caseDisplayNames.stream().distinct().collect(Collectors.joining(",")); - Collection attributesForNewArtifact = Arrays.asList( - new BlackboardAttribute( - TSK_NAME, MODULE_NAME, - persona.getName()), - new BlackboardAttribute( - TSK_COMMENT, MODULE_NAME, - persona.getComment()), - new BlackboardAttribute( - TSK_CORRELATION_TYPE, MODULE_NAME, - aType.getDisplayName()), - new BlackboardAttribute( - TSK_CORRELATION_VALUE, MODULE_NAME, - value), - new BlackboardAttribute( - TSK_OTHER_CASES, MODULE_NAME, - prevCases) - ); - makeAndPostPersonaArtifact(BlackboardArtifact.Type.TSK_MATCHING_PERSONA, originalArtifact, attributesForNewArtifact, "", - Score.SCORE_LIKELY_NOTABLE, "This account is associated with a persona"); - } - - /** - * *TEMPORARY* Hack to get all the flagged personas associated with the same file to prevent - * duplicates (associate with source file not the account instance artifact). - * Make an artifact to flag the passed in content. - * - * @param originalArtifact Artifact in current case we want to flag - * @param attributesForNewArtifact Attributes to assign to the new artifact - * @param configuration The configuration to be specified for the new artifact hit - * @param score sleuthkit.datamodel.Score to be assigned to this artifact - * @param justification Justification string - */ - private static void makeAndPostPersonaArtifact(BlackboardArtifact.Type newArtifactType, BlackboardArtifact originalArtifact, Collection attributesForNewArtifact, String configuration, - Score score, String justification) { - try { - SleuthkitCase tskCase = originalArtifact.getSleuthkitCase(); - Content originalContent = originalArtifact.getParent(); // Associate artifact with file instead of artifact - Blackboard blackboard = tskCase.getBlackboard(); - // Create artifact if it doesn't already exist. - BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(newArtifactType.getTypeID()); - if (!blackboard.artifactExists(originalContent, type, attributesForNewArtifact)) { - BlackboardArtifact newArtifact = originalContent.newAnalysisResult( - newArtifactType, score, - null, configuration, justification, attributesForNewArtifact) - .getAnalysisResult(); - - try { - // index the artifact for keyword search - blackboard.postArtifact(newArtifact, MODULE_NAME); - } catch (Blackboard.BlackboardException ex) { - LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + newArtifact.getArtifactID(), ex); //NON-NLS - } - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS - } catch (IllegalStateException ex) { - LOGGER.log(Level.SEVERE, "Failed to create BlackboardAttribute.", ex); // NON-NLS - } - } + } /** * Make an artifact to flag the passed in artifact. @@ -669,28 +595,6 @@ public class IngestEventsListener { makeAndPostPreviousSeenArtifact(bbArtifact, caseDisplayNames, eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue()); } - // *TEMPORARY* If we have a field that could be associated with a persona, check whether it is - // and make an artifact if so. Applicable types should be expanded later. - if (flagPreviousItemsEnabled && - ((eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.EMAIL_TYPE_ID) - || eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.PHONE_TYPE_ID)) { - String accountId = eamArtifact.getCorrelationValue(); - Collection personaMatches = Persona.getPersonaByAccountIdentifierLike(accountId); - for (Persona persona : personaMatches) { - // Make sure at least one account is an exact match. - boolean foundExactMatch = false; - for (PersonaAccount personaAccount : persona.getPersonaAccounts()) { - if (accountId.equalsIgnoreCase(personaAccount.getAccount().getIdentifier())) { - foundExactMatch = true; - } - } - if (foundExactMatch) { - List caseDisplayNames = persona.getCases().stream().map(p -> p.getDisplayName()).collect(Collectors.toList()); - makeAndPostMatchingPersonaArtifact(bbArtifact, persona, caseDisplayNames, eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue()); - } - } - } - // flag previously unseen apps and domains if (flagUniqueItemsEnabled && (eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID From 3c7bc6cceff2d185949e319de909c6dc21c7d164 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 9 Sep 2021 12:01:31 -0400 Subject: [PATCH 09/14] Bug fix --- .../experimental/autoingest/Manifest.java | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java index c2b7ae5259..4ed7793489 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,30 +30,45 @@ import javax.annotation.concurrent.Immutable; public final class Manifest implements Serializable { private static final long serialVersionUID = 1L; - private final Path filePath; + + // NOTE: Path is not Serializable. That's why we have to have a String as well, + // for scenarios when we send Manifest via ActiveMQ to other nodes. + private transient Path filePath; + private final String filePathString; + private transient Path dataSourcePath; + private final String dataSourcePathString; + private final Date dateFileCreated; private final String caseName; private final String deviceId; - private final Path dataSourcePath; + private final String dataSourceFileName; private final Map manifestProperties; public Manifest(Path manifestFilePath, Date dateFileCreated, String caseName, String deviceId, Path dataSourcePath, Map manifestProperties) { - this.filePath = Paths.get(manifestFilePath.toString()); + this.filePathString = manifestFilePath.toString(); + this.filePath = Paths.get(filePathString); + this.dateFileCreated = new Date(dateFileCreated.getTime()); this.caseName = caseName; this.deviceId = deviceId; if (null != dataSourcePath) { - this.dataSourcePath = Paths.get(dataSourcePath.toString()); + this.dataSourcePathString = dataSourcePath.toString(); + this.dataSourcePath = Paths.get(dataSourcePathString); dataSourceFileName = dataSourcePath.getFileName().toString(); } else { + this.dataSourcePathString = ""; this.dataSourcePath = Paths.get(""); dataSourceFileName = ""; } this.manifestProperties = new HashMap<>(manifestProperties); - } + } public Path getFilePath() { + // after potential deserialization Path will be null because it is transient + if (filePath == null) { + this.filePath = Paths.get(filePathString); + } return this.filePath; } @@ -70,6 +85,10 @@ public final class Manifest implements Serializable { } public Path getDataSourcePath() { + // after potential deserialization Path will be null because it is transient + if (dataSourcePath == null) { + this.dataSourcePath = Paths.get(dataSourcePathString); + } return dataSourcePath; } From 40857660acb63a5e3b8396ae86a76057378d543d Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 9 Sep 2021 12:02:55 -0400 Subject: [PATCH 10/14] Minor --- .../org/sleuthkit/autopsy/experimental/autoingest/Manifest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java index 4ed7793489..a6edfb4415 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java @@ -41,7 +41,6 @@ public final class Manifest implements Serializable { private final Date dateFileCreated; private final String caseName; private final String deviceId; - private final String dataSourceFileName; private final Map manifestProperties; From 25005cef460a62945105ba80c935e8d4f5b9e341 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 9 Sep 2021 12:03:23 -0400 Subject: [PATCH 11/14] TextViewer tab will now be enabled for Reports --- .../textcontentviewer/TextContentViewer.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewer.java index d7f853caab..426163ef80 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/textcontentviewer/TextContentViewer.java @@ -24,6 +24,7 @@ import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; /** * A DataContentViewer that displays text with the TextViewers available. @@ -91,14 +92,10 @@ public class TextContentViewer implements DataContentViewer { if (node == null) { return false; } + // get the node's File, if it has one AbstractFile file = node.getLookup().lookup(AbstractFile.class); - if (file == null) { - return false; - } - - // disable the text content viewer for directories and empty files - if (file.isDir() || file.getSize() == 0) { + if (file != null && (file.isDir() || file.getSize() == 0)) { return false; } From bff0a03f24e97c303a3219d559624691a4bbd9b0 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 9 Sep 2021 15:29:14 -0400 Subject: [PATCH 12/14] Changed checkbox text --- .../autopsy/centralrepository/ingestmodule/Bundle.properties | 2 +- .../centralrepository/ingestmodule/Bundle.properties-MERGED | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties index 156fb6b343..b00d4d5540 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties @@ -2,4 +2,4 @@ IngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings IngestSettingsPanel.flagTaggedNotableItemsCheckbox.text=Flag items previously tagged as notable IngestSettingsPanel.flagPreviouslySeenDevicesCheckbox.text=Flag devices and users previously seen in other cases IngestSettingsPanel.createCorrelationPropertiesCheckbox.text=Save items to the Central Repository -IngestSettingsPanel.flagUniqueAppsCheckbox.text=Flag unique apps and domains unseen in other cases +IngestSettingsPanel.flagUniqueAppsCheckbox.text=Flag apps and domains not seen in other cases diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties-MERGED index 839209f091..d15eb90cb2 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties-MERGED @@ -13,4 +13,4 @@ IngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings IngestSettingsPanel.flagTaggedNotableItemsCheckbox.text=Flag items previously tagged as notable IngestSettingsPanel.flagPreviouslySeenDevicesCheckbox.text=Flag devices and users previously seen in other cases IngestSettingsPanel.createCorrelationPropertiesCheckbox.text=Save items to the Central Repository -IngestSettingsPanel.flagUniqueAppsCheckbox.text=Flag unique apps and domains unseen in other cases +IngestSettingsPanel.flagUniqueAppsCheckbox.text=Flag apps and domains not seen in other cases From ad8d4e7a9deb3d375a4479313ec4741eff9d9c09 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 9 Sep 2021 15:50:31 -0400 Subject: [PATCH 13/14] Fixed exception create cc bin nodes --- .../autopsy/datamodel/accounts/Accounts.java | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index bf7ee1caba..9c84b85bfe 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -1481,7 +1481,7 @@ final public class Accounts implements AutopsyVisitableItem { } } - final private class CreditCardNumberFactory extends ObservingChildren { + final private class CreditCardNumberFactory extends ObservingChildren { private final BinResult bin; @@ -1502,10 +1502,10 @@ final public class Accounts implements AutopsyVisitableItem { } @Override - protected boolean createKeys(List list) { + protected boolean createKeys(List list) { String query - = "SELECT blackboard_artifacts.artifact_id " //NON-NLS + = "SELECT blackboard_artifacts.artifact_obj_id " //NON-NLS + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS @@ -1517,7 +1517,7 @@ final public class Accounts implements AutopsyVisitableItem { try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); ResultSet rs = results.getResultSet();) { while (rs.next()) { - list.add(rs.getLong("artifact_id")); //NON-NLS + list.add(skCase.getBlackboard().getDataArtifactById(rs.getLong("artifact_obj_id"))); //NON-NLS } } catch (TskCoreException | SQLException ex) { LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS @@ -1527,18 +1527,8 @@ final public class Accounts implements AutopsyVisitableItem { } @Override - protected Node[] createNodesForKey(Long artifactID) { - if (skCase == null) { - return new Node[0]; - } - - try { - DataArtifact art = skCase.getBlackboard().getDataArtifactById(artifactID); - return new Node[]{new AccountArtifactNode(art)}; - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error creating BlackboardArtifactNode for artifact with ID " + artifactID, ex); //NON-NLS - return new Node[0]; - } + protected Node[] createNodesForKey(DataArtifact artifact) { + return new Node[]{new AccountArtifactNode(artifact)}; } } From 3417b526b2848c2346549057b11283114bf1bd7c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 10 Sep 2021 14:22:48 -0400 Subject: [PATCH 14/14] fix --- .../autopsy/directorytree/DirectoryTreeTopComponent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 6cd838b834..70c70fe45b 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -1274,7 +1274,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } else if (typeID == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID()) { treeNode = getInterestingItemNode(typesChildren, BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, art); } else if (typeID == BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { - treeNode = getInterestingItemNode(typesChildren, BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, art); + treeNode = getInterestingItemNode(typesChildren, BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, art); } else if (typeID == BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeID()) { treeNode = getEmailNode(typesChildren, art); } else if (typeID == BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID()) {