From 949c43d56d481ef49c88176052625503fd0d34f2 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 28 Apr 2021 16:11:04 -0400 Subject: [PATCH 01/16] start on hierarchy --- .../autopsy/datamodel/AnalysisResults.java | 59 ++++++ .../autopsy/datamodel/AutopsyItemVisitor.java | 15 ++ .../datamodel/AutopsyTreeChildFactory.java | 1 + .../autopsy/datamodel/Bundle.properties | 2 +- .../datamodel/Bundle.properties-MERGED | 2 +- .../autopsy/datamodel/DataArtifacts.java | 59 ++++++ .../datamodel/DataSourceGroupingNode.java | 29 +-- .../autopsy/datamodel/ExtractedContent.java | 176 ++++++++++++------ .../datamodel/RootContentChildren.java | 10 + 9 files changed, 275 insertions(+), 78 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java new file mode 100644 index 0000000000..2a55ce2e4b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java @@ -0,0 +1,59 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.datamodel; + +/** + * Analysis Results node support + */ +public class AnalysisResults implements AutopsyVisitableItem { + + private final long datasourceObjId; + + /** + * Main constructor. + */ + public AnalysisResults() { + this(null); + } + + /** + * Main constructor. + * + * @param dsObjId The data source object id. + */ + public AnalysisResults(Long dsObjId) { + this.datasourceObjId = dsObjId; + } + + @Override + public T accept(AutopsyItemVisitor visitor) { + return visitor.visit(this); + } + + /** + * Returns whether or not there is a data source object for which results + * should be filtered. + * + * @return Whether or not there is a data source object for which results + * should be filtered. + */ + Long filteringDataSourceObjId() { + return datasourceObjId; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java index aabb21bbec..ed719a341e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java @@ -85,6 +85,11 @@ public interface AutopsyItemVisitor { T visit(DataSourcesByType aThis); + T visit(AnalysisResults aThis); + + T visit(DataArtifacts aThis); + + static abstract public class Default implements AutopsyItemVisitor { protected abstract T defaultVisit(AutopsyVisitableItem ec); @@ -233,5 +238,15 @@ public interface AutopsyItemVisitor { public T visit(DataSourcesByType dataSourceHosts) { return defaultVisit(dataSourceHosts); } + + @Override + public T visit(DataArtifacts aThis) { + return defaultVisit(aThis); + } + + @Override + public T visit(AnalysisResults aThis) { + return defaultVisit(aThis); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java index 22b340d5f1..c037a72251 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java @@ -127,6 +127,7 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.datamodel; + +/** + * Analysis Results node support + */ +public class DataArtifacts implements AutopsyVisitableItem { + + private final long datasourceObjId; + + /** + * Main constructor. + */ + public DataArtifacts() { + this(null); + } + + /** + * Main constructor. + * + * @param dsObjId The data source object id. + */ + public DataArtifacts(Long dsObjId) { + this.datasourceObjId = dsObjId; + } + + @Override + public T accept(AutopsyItemVisitor visitor) { + return visitor.visit(this); + } + + /** + * Returns whether or not there is a data source object for which results + * should be filtered. + * + * @return Whether or not there is a data source object for which results + * should be filtered. + */ + Long filteringDataSourceObjId() { + return datasourceObjId; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java index 214ab3ead9..9dc7529729 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java @@ -30,24 +30,23 @@ import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.LocalFilesDataSource; - /** - * Data source grouping node - an optional grouping node in the data tree view - * + * Data source grouping node - an optional grouping node in the data tree view + * */ class DataSourceGroupingNode extends DisplayableItemNode { private static final Logger logger = Logger.getLogger(DataSourceGroupingNode.class.getName()); /** - * Creates a data source grouping node for the given data source. - * - * @param dataSource specifies the data source + * Creates a data source grouping node for the given data source. + * + * @param dataSource specifies the data source */ DataSourceGroupingNode(DataSource dataSource) { - super (Optional.ofNullable(createDSGroupingNodeChildren(dataSource)) - .orElse(new RootContentChildren(Arrays.asList(Collections.EMPTY_LIST))), + super(Optional.ofNullable(createDSGroupingNodeChildren(dataSource)) + .orElse(new RootContentChildren(Arrays.asList(Collections.EMPTY_LIST))), Lookups.singleton(dataSource)); if (dataSource instanceof Image) { @@ -70,7 +69,7 @@ class DataSourceGroupingNode extends DisplayableItemNode { public boolean isLeafTypeNode() { return false; } - + private static RootContentChildren createDSGroupingNodeChildren(DataSource dataSource) { long dsObjId = dataSource.getId(); @@ -78,11 +77,13 @@ class DataSourceGroupingNode extends DisplayableItemNode { return new RootContentChildren(Arrays.asList( new DataSources(dsObjId), new Views(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId), - new Results(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId), - new Tags(dsObjId) ) - - ); - + new DataArtifacts(dsObjId), + new AnalysisResults(dsObjId), + new OsAccounts(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId), + new Tags(dsObjId), + new Reports(dsObjId) + )); + } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Error getting open case.", ex); //NON-NLS return null; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 8408c0c74a..af132a3f56 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -37,6 +37,7 @@ import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.RootContentChildren.CreateAutopsyNodeVisitor; import org.sleuthkit.autopsy.datamodel.utils.IconsUtil; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -99,7 +100,7 @@ public class ExtractedContent implements AutopsyVisitableItem { return skCase; } - public class RootNode extends DisplayableItemNode { + public static class RootNode extends DisplayableItemNode { public RootNode(SleuthkitCase skCase) { super(Children.create(new TypeFactory(), true), Lookups.singleton(NAME)); @@ -139,17 +140,51 @@ public class ExtractedContent implements AutopsyVisitableItem { return getClass().getName(); } } + + static class DataArtifactTypeFactory extends TypeFactory { + + } + + static class ArtifactKey { + private static final CreateAutopsyNodeVisitor visitor new CreateAutopsyNodeVisitor(); + private final AutopsyVisitableItem visitable; + private final BlackboardArtifact.Type type; + private final Long dsFilteringObjId; + + ArtifactKey(AutopsyVisitableItem visitable, BlackboardArtifact.Type type, long dsFilteringObjId) { + this.visitable = visitable; + this.type = type; + this.dsFilteringObjId = dsFilteringObjId; + } + + Node getNode() { + if (visitable!= null) { + return visitable.accept(visitor); + } else { + TypeNode node = new TypeNode(type, dsFilteringObjId); + node.updateDisplayName(); + return node; + } + } + + String getName() { + + } + } /** * 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 implements RefreshThrottler.Refresher { + abstract static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { + + private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); private final ArrayList doNotShow = new ArrayList<>(); // maps the artifact type to its child node private final HashMap typeNodeList = new HashMap<>(); + private final Long filteringDSObjId; /** * RefreshThrottler is used to limit the number of refreshes performed @@ -159,8 +194,9 @@ public class ExtractedContent implements AutopsyVisitableItem { private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); @SuppressWarnings("deprecation") - TypeFactory() { + TypeFactory(Long filteringDSObjId) { super(); + this.filteringDSObjId = filteringDSObjId; // these are shown in other parts of the UI doNotShow.add(new BlackboardArtifact.Type(TSK_GEN_INFO)); @@ -184,7 +220,6 @@ public class ExtractedContent implements AutopsyVisitableItem { // case was closed. Remove listeners so that we don't get called with a stale case handle if (evt.getNewValue() == null) { removeNotify(); - skCase = null; } } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { @@ -219,42 +254,59 @@ public class ExtractedContent implements AutopsyVisitableItem { typeNodeList.clear(); } + /** + * Retrieves all the artifact types that should be displayed for this + * factory. + * + * @param filteringDSObjId The data source object id to filter on or + * null if no filtering on data source should + * occur. + * + * @return The list of artifact types to be displayed. + * + * @throws NoCurrentCaseException + * @throws TskCoreException + */ + protected abstract List getTypes(Long filteringDSObjId) throws NoCurrentCaseException, TskCoreException; + + // Potentially can reuse +// (filteringDSObjId > 0) +// ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactTypesInUse(filteringDSObjId) +// : Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse(); + // types.removeAll(doNotShow); @Override - protected boolean createKeys(List list) { - if (skCase != null) { - try { - List types = (filteringDSObjId > 0) - ? blackboard.getArtifactTypesInUse(filteringDSObjId) - : skCase.getArtifactTypesInUse(); + protected boolean createKeys(List list) { - types.removeAll(doNotShow); - Collections.sort(types, - new Comparator() { - @Override - public int compare(BlackboardArtifact.Type a, BlackboardArtifact.Type b) { - return a.getDisplayName().compareTo(b.getDisplayName()); - } - }); - list.addAll(types); - - // 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.Type art : types) { - TypeNode node = typeNodeList.get(art); - if (node != null) { - node.updateDisplayName(); - } + try { + List types = getTypes(this.filteringDSObjId); + Collections.sort(types, + new Comparator() { + @Override + public int compare(BlackboardArtifact.Type a, BlackboardArtifact.Type b) { + return a.getDisplayName().compareTo(b.getDisplayName()); + } + }); + list.addAll(types); + + // 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.Type art : types) { + 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 } + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Trying to access case when no case is open.", ex); //NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage()); //NON-NLS } return true; } @Override protected Node createNodeForKey(BlackboardArtifact.Type key) { - TypeNode node = new TypeNode(key); + TypeNode node = new TypeNode(key, filteringDSObjId); typeNodeList.put(key, node); return node; } @@ -300,35 +352,33 @@ public class ExtractedContent implements AutopsyVisitableItem { * the artifacts of a given type. Its children will be * BlackboardArtifactNode objects. */ - public class TypeNode extends DisplayableItemNode { + public static class TypeNode extends DisplayableItemNode { + + private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); private final BlackboardArtifact.Type type; private long childCount = 0; + private final Long filteringDSObjId; - TypeNode(BlackboardArtifact.Type type) { - super(Children.create(new ArtifactFactory(type), true), Lookups.singleton(type.getDisplayName())); + TypeNode(BlackboardArtifact.Type type, Long filteringDSObjId) { + super(Children.create(new ArtifactFactory(type, filteringDSObjId), true), Lookups.singleton(type.getDisplayName())); super.setName(type.getTypeName()); this.type = type; + this.filteringDSObjId = filteringDSObjId; String iconPath = IconsUtil.getIconFilePath(type.getTypeID()); setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath); updateDisplayName(); } final void updateDisplayName() { - if (skCase == null) { - return; - } - - // NOTE: This completely destroys our lazy-loading ideal - // a performance increase might be had by adding a - // "getBlackboardArtifactCount()" method to skCase try { this.childCount = (filteringDSObjId > 0) - ? blackboard.getArtifactsCount(type.getTypeID(), filteringDSObjId) - : skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); + ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactsCount(type.getTypeID(), filteringDSObjId) + : Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifactsTypeCount(type.getTypeID()); + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Error fetching data when case closed.", ex); } catch (TskCoreException ex) { - Logger.getLogger(TypeNode.class.getName()) - .log(Level.WARNING, "Error getting child count", ex); //NON-NLS + logger.log(Level.WARNING, "Error getting child count", ex); //NON-NLS } super.setDisplayName(type.getDisplayName() + " \u200E(\u200E" + childCount + ")\u200E"); } @@ -374,8 +424,9 @@ public class ExtractedContent implements AutopsyVisitableItem { /** * Creates children for a given artifact type */ - private class ArtifactFactory extends BaseChildFactory implements RefreshThrottler.Refresher { + private static class ArtifactFactory extends BaseChildFactory implements RefreshThrottler.Refresher { + private static final Logger logger = Logger.getLogger(ArtifactFactory.class.getName()); private final BlackboardArtifact.Type type; /** @@ -384,10 +435,12 @@ public class ExtractedContent implements AutopsyVisitableItem { * received. */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); + private final Long filteringDSObjId; - ArtifactFactory(BlackboardArtifact.Type type) { + ArtifactFactory(BlackboardArtifact.Type type, Long filteringDSObjId) { super(type.getTypeName()); this.type = type; + this.filteringDSObjId = filteringDSObjId; } private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { @@ -430,23 +483,22 @@ public class ExtractedContent implements AutopsyVisitableItem { @Override protected List makeKeys() { - if (skCase != null) { - try { - List arts; - if (filteringDSObjId > 0) { - arts = blackboard.getArtifacts(type.getTypeID(), filteringDSObjId); - } else { - arts = skCase.getBlackboardArtifacts(type.getTypeID()); - } - for (BlackboardArtifact art : arts) { - //Cache attributes while we are off the EDT. - //See JIRA-5969 - art.getAttributes(); - } - return arts; - } catch (TskCoreException ex) { - Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS + try { + List arts; + arts = (filteringDSObjId != null) + ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(type.getTypeID(), filteringDSObjId) + : Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifacts(type.getTypeID()); + + for (BlackboardArtifact art : arts) { + //Cache attributes while we are off the EDT. + //See JIRA-5969 + art.getAttributes(); } + return arts; + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Trying to access case when no case is open.", ex); //NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS } return Collections.emptyList(); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index 07ea924d82..355790976e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -204,5 +204,15 @@ public class RootContentChildren extends Children.Keys { public AbstractNode visit(DataSourcesByType dataSourceHosts) { return new DataSourcesByTypeNode(); } + + @Override + public AbstractNode visit(AnalysisResults analysisResults) { + return new AnalysisResultsNode(analysisResults); + } + + @Override + public AbstractNode visit(DataArtifacts dataArtifacts) { + return new DataArtifactsNode(dataArtifacts); + } } } From bfd41bd6831000bc853f0f97dce03a3cd9e14dde Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 28 Apr 2021 20:46:21 -0400 Subject: [PATCH 02/16] work on type factory --- .../autopsy/datamodel/ExtractedContent.java | 298 +++++++++++++----- 1 file changed, 219 insertions(+), 79 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index af132a3f56..a65bd7dc3e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.datamodel; +import com.google.common.collect.ImmutableSet; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; @@ -26,8 +27,13 @@ import java.util.Comparator; import java.util.EnumSet; import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; @@ -38,6 +44,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.RootContentChildren.CreateAutopsyNodeVisitor; +import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.autopsy.datamodel.utils.IconsUtil; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -57,6 +64,7 @@ import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNL import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.guiutils.RefreshThrottler; +import org.sleuthkit.datamodel.BlackboardArtifact.Category; /** * Parent of the "extracted content" artifacts to be displayed in the tree. @@ -140,36 +148,184 @@ public class ExtractedContent implements AutopsyVisitableItem { return getClass().getName(); } } + - static class DataArtifactTypeFactory extends TypeFactory { + // The “Email Messages” and “Accounts” nodes should become children of the “Data Artifacts” node, but should retain their current structure. + + // The “Keyword Hits,” “Hashset Hits,” and “Interesting Items” nodes should become children of the “Analysis Results” node, but should retain their current structure. + +// new KeywordHits(sleuthkitCase, dsObjId), +// new HashsetHits(sleuthkitCase, dsObjId), +// new EmailExtracted(sleuthkitCase, dsObjId), +// new InterestingHits(sleuthkitCase, dsObjId ), +// new Accounts(sleuthkitCase, dsObjId), +// new OsAccounts(sleuthkitCase, dsObjId)) + + + static class AnalysisResultsTypeFactory extends TypeFactory { + private static Map getVisitableItems(Long filteringDSObjId) throws NoCurrentCaseException { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return new HashMap<>() {{ + put(filteringDSObjId == null ? new KeywordHits(skCase) : new KeywordHits(skCase, filteringDSObjId), TODO); //BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getDisplayName()); + put(filteringDSObjId == null ? new HashsetHits(skCase) : new HashsetHits(skCase, filteringDSObjId), TODO); // Bundle.Accounts_RootNode_displayName()); + put(filteringDSObjId == null ? new InterestingHits(skCase) : new InterestingHits(skCase, filteringDSObjId), TODO); // Bundle.Accounts_RootNode_displayName()); + }}; + } + + public AnalysisResultsTypeFactory(Long filteringDSObjId) throws NoCurrentCaseException { + super(getVisitableItems(filteringDSObjId), Category.DATA_ARTIFACT, filteringDSObjId); + } } - static class ArtifactKey { - private static final CreateAutopsyNodeVisitor visitor new CreateAutopsyNodeVisitor(); + + static class DataArtifactsTypeFactory extends TypeFactory { + + private static Map getVisitableItems(Long filteringDSObjId) throws NoCurrentCaseException { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return new HashMap<>() {{ + put(filteringDSObjId == null ? new EmailExtracted(skCase) : new EmailExtracted(skCase, filteringDSObjId), TODO); //BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getDisplayName()); + put(filteringDSObjId == null ? new Accounts(skCase) : new Accounts(skCase, filteringDSObjId), TODO); // Bundle.Accounts_RootNode_displayName()); + }}; + } + + public DataArtifactsTypeFactory(Long filteringDSObjId) throws NoCurrentCaseException { + super(getVisitableItems(filteringDSObjId), Category.DATA_ARTIFACT, filteringDSObjId); + } + } + + interface ArtifactKey { + + Node getNode(); + + String getName(); + + void update(); + } + + static class VisitableArtifactKey implements ArtifactKey { + + private static final CreateAutopsyNodeVisitor visitor = new CreateAutopsyNodeVisitor(); private final AutopsyVisitableItem visitable; - private final BlackboardArtifact.Type type; + private final String name; private final Long dsFilteringObjId; - ArtifactKey(AutopsyVisitableItem visitable, BlackboardArtifact.Type type, long dsFilteringObjId) { + VisitableArtifactKey(AutopsyVisitableItem visitable, String name, Long dsFilteringObjId) { this.visitable = visitable; - this.type = type; + this.name = name; this.dsFilteringObjId = dsFilteringObjId; } - Node getNode() { - if (visitable!= null) { - return visitable.accept(visitor); - } else { - TypeNode node = new TypeNode(type, dsFilteringObjId); - node.updateDisplayName(); - return node; - } + @Override + public Node getNode() { + return visitable.accept(visitor); } - - String getName() { + @Override + public String getName() { + return this.name; } + + @Override + public void update() { + // no need to handle updates for a visitable item + } + + @Override + public int hashCode() { + int hash = 5; + hash = 37 * hash + Objects.hashCode(this.visitable); + hash = 37 * hash + Objects.hashCode(this.name); + hash = 37 * hash + Objects.hashCode(this.dsFilteringObjId); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final VisitableArtifactKey other = (VisitableArtifactKey) obj; + if (!Objects.equals(this.name, other.name)) { + return false; + } + if (!Objects.equals(this.visitable, other.visitable)) { + return false; + } + if (!Objects.equals(this.dsFilteringObjId, other.dsFilteringObjId)) { + return false; + } + return true; + } + + } + + static class TypeArtifactKey implements ArtifactKey { + + private final BlackboardArtifact.Type type; + private final Map typeMapping; + private final Long dsFilteringObjId; + + TypeArtifactKey(BlackboardArtifact.Type type, Map typeMapping, Long dsFilteringObjId) { + this.type = type; + this.typeMapping = typeMapping; + this.dsFilteringObjId = dsFilteringObjId; + } + + @Override + public TypeNode getNode() { + return typeMapping.computeIfAbsent(type, (tp) -> new TypeNode(type, dsFilteringObjId)); + } + + @Override + public String getName() { + return this.type.getDisplayName(); + } + + @Override + public void update() { + getNode().updateDisplayName(); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 83 * hash + Objects.hashCode(this.type); + hash = 83 * hash + Objects.hashCode(this.typeMapping); + hash = 83 * hash + Objects.hashCode(this.dsFilteringObjId); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final TypeArtifactKey other = (TypeArtifactKey) obj; + if (!Objects.equals(this.type, other.type)) { + return false; + } + if (!Objects.equals(this.typeMapping, other.typeMapping)) { + return false; + } + if (!Objects.equals(this.dsFilteringObjId, other.dsFilteringObjId)) { + return false; + } + return true; + } + } /** @@ -177,13 +333,29 @@ public class ExtractedContent implements AutopsyVisitableItem { * This area has all of the blackboard artifacts that are not displayed in a * more specific form elsewhere in the tree. */ - abstract static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { + static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { + + @SuppressWarnings("deprecation") + private static final Set DO_NOT_SHOW = Stream.of( + // these are shown in other parts of the UI (and different node types) + new BlackboardArtifact.Type(TSK_GEN_INFO), + new BlackboardArtifact.Type(TSK_EMAIL_MSG), + new BlackboardArtifact.Type(TSK_HASHSET_HIT), + new BlackboardArtifact.Type(TSK_KEYWORD_HIT), + new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT), + new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), + new BlackboardArtifact.Type(TSK_ACCOUNT), + new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE), + new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE), + new BlackboardArtifact.Type(TSK_TL_EVENT), + //This is not meant to be shown in the UI at all. It is more of a meta artifact. + new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) + ).collect(Collectors.toSet()); private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); - private final ArrayList doNotShow = new ArrayList<>(); // maps the artifact type to its child node - private final HashMap typeNodeList = new HashMap<>(); + private final HashMap typeNodeMap = new HashMap<>(); private final Long filteringDSObjId; /** @@ -192,26 +364,15 @@ public class ExtractedContent implements AutopsyVisitableItem { * received. */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); + private final Map visitableItems; + private final Category category; @SuppressWarnings("deprecation") - TypeFactory(Long filteringDSObjId) { + TypeFactory(Map visitableItems, Category category, Long filteringDSObjId) { super(); this.filteringDSObjId = filteringDSObjId; - - // these are shown in other parts of the UI - doNotShow.add(new BlackboardArtifact.Type(TSK_GEN_INFO)); - doNotShow.add(new BlackboardArtifact.Type(TSK_EMAIL_MSG)); - doNotShow.add(new BlackboardArtifact.Type(TSK_HASHSET_HIT)); - doNotShow.add(new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); - doNotShow.add(new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT)); - doNotShow.add(new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT)); - doNotShow.add(new BlackboardArtifact.Type(TSK_ACCOUNT)); - doNotShow.add(new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE)); - doNotShow.add(new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE)); - doNotShow.add(new BlackboardArtifact.Type(TSK_TL_EVENT)); - - //This is not meant to be shown in the UI at all. It is more of a meta artifact. - doNotShow.add(new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT)); + this.visitableItems = visitableItems; + this.category = category; } private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { @@ -251,51 +412,32 @@ public class ExtractedContent implements AutopsyVisitableItem { refreshThrottler.unregisterEventListener(); IngestManager.getInstance().removeIngestJobEventListener(pcl); Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl); - typeNodeList.clear(); + typeNodeMap.clear(); } - /** - * Retrieves all the artifact types that should be displayed for this - * factory. - * - * @param filteringDSObjId The data source object id to filter on or - * null if no filtering on data source should - * occur. - * - * @return The list of artifact types to be displayed. - * - * @throws NoCurrentCaseException - * @throws TskCoreException - */ - protected abstract List getTypes(Long filteringDSObjId) throws NoCurrentCaseException, TskCoreException; - - // Potentially can reuse -// (filteringDSObjId > 0) -// ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactTypesInUse(filteringDSObjId) -// : Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse(); - // types.removeAll(doNotShow); @Override protected boolean createKeys(List list) { - try { - List types = getTypes(this.filteringDSObjId); - Collections.sort(types, - new Comparator() { - @Override - public int compare(BlackboardArtifact.Type a, BlackboardArtifact.Type b) { - return a.getDisplayName().compareTo(b.getDisplayName()); - } - }); - list.addAll(types); + // Potentially can reuse + List types = (this.filteringDSObjId != null) + ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactTypesInUse(this.filteringDSObjId) + : Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse(); + + Stream typeArtifactKeys = types.stream() + .filter(tp -> category.equals(tp.getCategory())) + .filter(tp -> !DO_NOT_SHOW.contains(tp)) + .map(tp -> new TypeArtifactKey(tp, this.typeNodeMap, this.filteringDSObjId)); + + Stream visitableKeys = visitableItems.entrySet().stream() + .map(entry -> new VisitableArtifactKey(entry.getKey(), entry.getValue(), filteringDSObjId)); + + Stream.concat(typeArtifactKeys, visitableKeys) + .sorted((a, b) -> StringUtils.compareIgnoreCase(a.getName(), b.getName())) + .forEach((artifactTypeKey -> { + artifactTypeKey.update(); + list.add(artifactTypeKey); + })); - // 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.Type art : types) { - TypeNode node = typeNodeList.get(art); - if (node != null) { - node.updateDisplayName(); - } - } } catch (NoCurrentCaseException ex) { logger.log(Level.WARNING, "Trying to access case when no case is open.", ex); //NON-NLS } catch (TskCoreException ex) { @@ -305,10 +447,8 @@ public class ExtractedContent implements AutopsyVisitableItem { } @Override - protected Node createNodeForKey(BlackboardArtifact.Type key) { - TypeNode node = new TypeNode(key, filteringDSObjId); - typeNodeList.put(key, node); - return node; + protected Node createNodeForKey(ArtifactKey key) { + return key.getNode(); } @Override @@ -333,7 +473,7 @@ public class ExtractedContent implements AutopsyVisitableItem { * the event is a remote event. */ final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); - if (null != event && !(this.doNotShow.contains(event.getBlackboardArtifactType()))) { + if (null != event && !(DO_NOT_SHOW.contains(event.getBlackboardArtifactType()))) { return true; } } catch (NoCurrentCaseException notUsed) { From 58993d7e6224531d1b66c510e080b0ee1c2f54af Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 29 Apr 2021 09:00:21 -0400 Subject: [PATCH 03/16] beginning debug --- .../autopsy/datamodel/AnalysisResults.java | 6 +- .../datamodel/AutopsyTreeChildFactory.java | 11 +- .../autopsy/datamodel/DataArtifacts.java | 6 +- .../datamodel/DataSourceGroupingNode.java | 2 +- .../autopsy/datamodel/EmailExtracted.java | 8 + .../autopsy/datamodel/ExtractedContent.java | 188 +++++++++++------- .../autopsy/datamodel/HashsetHits.java | 8 + .../autopsy/datamodel/InterestingHits.java | 8 + .../autopsy/datamodel/KeywordHits.java | 9 + .../datamodel/RootContentChildren.java | 12 +- .../autopsy/datamodel/accounts/Accounts.java | 12 +- 11 files changed, 179 insertions(+), 91 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java index 2a55ce2e4b..ed6bd37319 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java @@ -29,7 +29,7 @@ public class AnalysisResults implements AutopsyVisitableItem { * Main constructor. */ public AnalysisResults() { - this(null); + this(0); } /** @@ -37,7 +37,7 @@ public class AnalysisResults implements AutopsyVisitableItem { * * @param dsObjId The data source object id. */ - public AnalysisResults(Long dsObjId) { + public AnalysisResults(long dsObjId) { this.datasourceObjId = dsObjId; } @@ -53,7 +53,7 @@ public class AnalysisResults implements AutopsyVisitableItem { * @return Whether or not there is a data source object for which results * should be filtered. */ - Long filteringDataSourceObjId() { + Long getFilteringDataSourceObjId() { return datasourceObjId; } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java index c037a72251..9ebb44cb40 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java @@ -92,6 +92,7 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable keys = new ArrayList<>(Arrays.asList( new DataSourcesByType(), - new Views(tskCase), - new Results(tskCase), - new OsAccounts(tskCase), + new Views(Case.getCurrentCaseThrows().getSleuthkitCase()), + new DataArtifacts(), + new AnalysisResults(), + new OsAccounts(Case.getCurrentCaseThrows().getSleuthkitCase()), new Tags(), - new Reports())); + new Reports() + )); list.addAll(keys); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java index d327da0f4a..e273d8cf12 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java @@ -29,7 +29,7 @@ public class DataArtifacts implements AutopsyVisitableItem { * Main constructor. */ public DataArtifacts() { - this(null); + this(0); } /** @@ -37,7 +37,7 @@ public class DataArtifacts implements AutopsyVisitableItem { * * @param dsObjId The data source object id. */ - public DataArtifacts(Long dsObjId) { + public DataArtifacts(long dsObjId) { this.datasourceObjId = dsObjId; } @@ -53,7 +53,7 @@ public class DataArtifacts implements AutopsyVisitableItem { * @return Whether or not there is a data source object for which results * should be filtered. */ - Long filteringDataSourceObjId() { + Long getFilteringDataSourceObjId() { return datasourceObjId; } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java index 9dc7529729..28ad25fe59 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java @@ -81,7 +81,7 @@ class DataSourceGroupingNode extends DisplayableItemNode { new AnalysisResults(dsObjId), new OsAccounts(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId), new Tags(dsObjId), - new Reports(dsObjId) + new Reports() )); } catch (NoCurrentCaseException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 58becb183c..6495e9d7fe 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -92,6 +92,14 @@ public class EmailExtracted implements AutopsyVisitableItem { private final EmailResults emailResults; private final long filteringDSObjId; // 0 if not filtering/grouping by data source + /** + * Returns the display name for this module. + * @return The display name for this module. + */ + static String getDisplayName() { + return DISPLAY_NAME; + } + /** * Constructor * diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index a65bd7dc3e..8f3f737e41 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -38,6 +38,7 @@ import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; @@ -74,9 +75,11 @@ public class ExtractedContent implements AutopsyVisitableItem { private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text"); + private static final Category DEFAULT_CATEGORY = Category.DATA_ARTIFACT; + private final long filteringDSObjId; // 0 if not filtering/grouping by data source private SleuthkitCase skCase; // set to null after case has been closed - private Blackboard blackboard; + private final Category category; /** * Constructs extracted content object @@ -84,7 +87,11 @@ public class ExtractedContent implements AutopsyVisitableItem { * @param skCase Case DB */ public ExtractedContent(SleuthkitCase skCase) { - this(skCase, 0); + this(skCase, 0, DEFAULT_CATEGORY); + } + + public ExtractedContent(SleuthkitCase skCase, Category category) { + this(skCase, 0, DEFAULT_CATEGORY); } /** @@ -94,9 +101,13 @@ public class ExtractedContent implements AutopsyVisitableItem { * @param objId Object id of the parent datasource */ public ExtractedContent(SleuthkitCase skCase, long objId) { + this(skCase, objId, DEFAULT_CATEGORY); + } + + public ExtractedContent(SleuthkitCase skCase, long dataSourceObjId, Category category) { this.skCase = skCase; - this.filteringDSObjId = objId; - this.blackboard = skCase.getBlackboard(); + this.filteringDSObjId = dataSourceObjId; + this.category = category; } @Override @@ -107,11 +118,38 @@ public class ExtractedContent implements AutopsyVisitableItem { public SleuthkitCase getSleuthkitCase() { return skCase; } + + long getFilteringDSObjId() { + return filteringDSObjId; + } + + Category getCategory() { + return category; + } + + + + + + + static class RootNode extends DisplayableItemNode { + private static final Logger logger = Logger.getLogger(RootNode.class.getName()); + + private static Children getFactory(Category category, long filteringDSObjId) { + try { + TypeFactory factory = Category.ANALYSIS_RESULT.equals(category) ? + new AnalysisResultsTypeFactory(filteringDSObjId) : + new DataArtifactsTypeFactory(filteringDSObjId); + + return Children.create(factory, true); + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Attempt to instantiate TypeFactory with no open case.", ex); + return null; + } + } - public static class RootNode extends DisplayableItemNode { - - public RootNode(SleuthkitCase skCase) { - super(Children.create(new TypeFactory(), true), Lookups.singleton(NAME)); + RootNode(Category category, long filteringDSObjId) { + super(getFactory(category, filteringDSObjId), Lookups.singleton(NAME)); super.setName(NAME); super.setDisplayName(NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png"); //NON-NLS @@ -150,47 +188,59 @@ public class ExtractedContent implements AutopsyVisitableItem { } - // The “Email Messages” and “Accounts” nodes should become children of the “Data Artifacts” node, but should retain their current structure. + private static class AnalysisResultsTypeFactory extends TypeFactory { - // The “Keyword Hits,” “Hashset Hits,” and “Interesting Items” nodes should become children of the “Analysis Results” node, but should retain their current structure. - -// new KeywordHits(sleuthkitCase, dsObjId), -// new HashsetHits(sleuthkitCase, dsObjId), -// new EmailExtracted(sleuthkitCase, dsObjId), -// new InterestingHits(sleuthkitCase, dsObjId ), -// new Accounts(sleuthkitCase, dsObjId), -// new OsAccounts(sleuthkitCase, dsObjId)) + private static final Set EXCLUDED_ANALYSIS_RESULTS = Stream.of( + // these are shown in other parts of the UI (and different node types) + new BlackboardArtifact.Type(TSK_HASHSET_HIT), + new BlackboardArtifact.Type(TSK_KEYWORD_HIT), + new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT), + new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), + new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE) + ).collect(Collectors.toSet()); - - static class AnalysisResultsTypeFactory extends TypeFactory { - - private static Map getVisitableItems(Long filteringDSObjId) throws NoCurrentCaseException { + private static Map getVisitableItems(long filteringDSObjId) throws NoCurrentCaseException { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return new HashMap<>() {{ - put(filteringDSObjId == null ? new KeywordHits(skCase) : new KeywordHits(skCase, filteringDSObjId), TODO); //BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getDisplayName()); - put(filteringDSObjId == null ? new HashsetHits(skCase) : new HashsetHits(skCase, filteringDSObjId), TODO); // Bundle.Accounts_RootNode_displayName()); - put(filteringDSObjId == null ? new InterestingHits(skCase) : new InterestingHits(skCase, filteringDSObjId), TODO); // Bundle.Accounts_RootNode_displayName()); - }}; + return new HashMap() { + { + put(new KeywordHits(skCase, filteringDSObjId), KeywordHits.getDisplayName()); + put(new HashsetHits(skCase, filteringDSObjId), HashsetHits.getDisplayName()); + put(new InterestingHits(skCase, filteringDSObjId), InterestingHits.getDisplayName()); + } + }; } - - public AnalysisResultsTypeFactory(Long filteringDSObjId) throws NoCurrentCaseException { - super(getVisitableItems(filteringDSObjId), Category.DATA_ARTIFACT, filteringDSObjId); + + AnalysisResultsTypeFactory(long filteringDSObjId) throws NoCurrentCaseException { + super(getVisitableItems(filteringDSObjId), EXCLUDED_ANALYSIS_RESULTS, Category.DATA_ARTIFACT, filteringDSObjId); } } - - - static class DataArtifactsTypeFactory extends TypeFactory { - - private static Map getVisitableItems(Long filteringDSObjId) throws NoCurrentCaseException { + + private static class DataArtifactsTypeFactory extends TypeFactory { + + @SuppressWarnings("deprecation") + private static final Set EXCLUDED_DATA_ARTIFACTS = Stream.of( + // these are shown in other parts of the UI (and different node types) + new BlackboardArtifact.Type(TSK_GEN_INFO), + new BlackboardArtifact.Type(TSK_EMAIL_MSG), + new BlackboardArtifact.Type(TSK_ACCOUNT), + new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE), + new BlackboardArtifact.Type(TSK_TL_EVENT), + //This is not meant to be shown in the UI at all. It is more of a meta artifact. + new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) + ).collect(Collectors.toSet()); + + private static Map getVisitableItems(long filteringDSObjId) throws NoCurrentCaseException { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return new HashMap<>() {{ - put(filteringDSObjId == null ? new EmailExtracted(skCase) : new EmailExtracted(skCase, filteringDSObjId), TODO); //BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getDisplayName()); - put(filteringDSObjId == null ? new Accounts(skCase) : new Accounts(skCase, filteringDSObjId), TODO); // Bundle.Accounts_RootNode_displayName()); - }}; + return new HashMap() { + { + put(new EmailExtracted(skCase, filteringDSObjId), EmailExtracted.getDisplayName()); + put(new Accounts(skCase, filteringDSObjId), Accounts.getDisplayName()); + } + }; } - - public DataArtifactsTypeFactory(Long filteringDSObjId) throws NoCurrentCaseException { - super(getVisitableItems(filteringDSObjId), Category.DATA_ARTIFACT, filteringDSObjId); + + DataArtifactsTypeFactory(long filteringDSObjId) throws NoCurrentCaseException { + super(getVisitableItems(filteringDSObjId), EXCLUDED_DATA_ARTIFACTS, Category.DATA_ARTIFACT, filteringDSObjId); } } @@ -203,14 +253,14 @@ public class ExtractedContent implements AutopsyVisitableItem { void update(); } - static class VisitableArtifactKey implements ArtifactKey { + private static class VisitableArtifactKey implements ArtifactKey { private static final CreateAutopsyNodeVisitor visitor = new CreateAutopsyNodeVisitor(); private final AutopsyVisitableItem visitable; private final String name; - private final Long dsFilteringObjId; + private final long dsFilteringObjId; - VisitableArtifactKey(AutopsyVisitableItem visitable, String name, Long dsFilteringObjId) { + VisitableArtifactKey(AutopsyVisitableItem visitable, String name, long dsFilteringObjId) { this.visitable = visitable; this.name = name; this.dsFilteringObjId = dsFilteringObjId; @@ -266,13 +316,13 @@ public class ExtractedContent implements AutopsyVisitableItem { } - static class TypeArtifactKey implements ArtifactKey { + private static class TypeArtifactKey implements ArtifactKey { private final BlackboardArtifact.Type type; private final Map typeMapping; - private final Long dsFilteringObjId; + private final long dsFilteringObjId; - TypeArtifactKey(BlackboardArtifact.Type type, Map typeMapping, Long dsFilteringObjId) { + TypeArtifactKey(BlackboardArtifact.Type type, Map typeMapping, long dsFilteringObjId) { this.type = type; this.typeMapping = typeMapping; this.dsFilteringObjId = dsFilteringObjId; @@ -333,30 +383,13 @@ public class ExtractedContent implements AutopsyVisitableItem { * This area has all of the blackboard artifacts that are not displayed in a * more specific form elsewhere in the tree. */ - static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { - - @SuppressWarnings("deprecation") - private static final Set DO_NOT_SHOW = Stream.of( - // these are shown in other parts of the UI (and different node types) - new BlackboardArtifact.Type(TSK_GEN_INFO), - new BlackboardArtifact.Type(TSK_EMAIL_MSG), - new BlackboardArtifact.Type(TSK_HASHSET_HIT), - new BlackboardArtifact.Type(TSK_KEYWORD_HIT), - new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT), - new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), - new BlackboardArtifact.Type(TSK_ACCOUNT), - new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE), - new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE), - new BlackboardArtifact.Type(TSK_TL_EVENT), - //This is not meant to be shown in the UI at all. It is more of a meta artifact. - new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) - ).collect(Collectors.toSet()); + private static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); // maps the artifact type to its child node private final HashMap typeNodeMap = new HashMap<>(); - private final Long filteringDSObjId; + private final long filteringDSObjId; /** * RefreshThrottler is used to limit the number of refreshes performed @@ -366,11 +399,14 @@ public class ExtractedContent implements AutopsyVisitableItem { private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); private final Map visitableItems; private final Category category; + private final Set excludeTypes; @SuppressWarnings("deprecation") - TypeFactory(Map visitableItems, Category category, Long filteringDSObjId) { + TypeFactory(Map visitableItems, Set excludeTypes, + Category category, long filteringDSObjId) { super(); this.filteringDSObjId = filteringDSObjId; + this.excludeTypes = excludeTypes; this.visitableItems = visitableItems; this.category = category; } @@ -419,13 +455,12 @@ public class ExtractedContent implements AutopsyVisitableItem { protected boolean createKeys(List list) { try { // Potentially can reuse - List types = (this.filteringDSObjId != null) + List types = (this.filteringDSObjId > 0) ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactTypesInUse(this.filteringDSObjId) : Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse(); Stream typeArtifactKeys = types.stream() - .filter(tp -> category.equals(tp.getCategory())) - .filter(tp -> !DO_NOT_SHOW.contains(tp)) + .filter(tp -> category.equals(tp.getCategory()) && !excludeTypes.contains(tp)) .map(tp -> new TypeArtifactKey(tp, this.typeNodeMap, this.filteringDSObjId)); Stream visitableKeys = visitableItems.entrySet().stream() @@ -473,7 +508,8 @@ public class ExtractedContent implements AutopsyVisitableItem { * the event is a remote event. */ final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); - if (null != event && !(DO_NOT_SHOW.contains(event.getBlackboardArtifactType()))) { + if (null != event && category.equals(event.getBlackboardArtifactType().getCategory()) + && !(excludeTypes.contains(event.getBlackboardArtifactType()))) { return true; } } catch (NoCurrentCaseException notUsed) { @@ -498,9 +534,9 @@ public class ExtractedContent implements AutopsyVisitableItem { private final BlackboardArtifact.Type type; private long childCount = 0; - private final Long filteringDSObjId; + private final long filteringDSObjId; - TypeNode(BlackboardArtifact.Type type, Long filteringDSObjId) { + TypeNode(BlackboardArtifact.Type type, long filteringDSObjId) { super(Children.create(new ArtifactFactory(type, filteringDSObjId), true), Lookups.singleton(type.getDisplayName())); super.setName(type.getTypeName()); this.type = type; @@ -575,9 +611,9 @@ public class ExtractedContent implements AutopsyVisitableItem { * received. */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); - private final Long filteringDSObjId; + private final long filteringDSObjId; - ArtifactFactory(BlackboardArtifact.Type type, Long filteringDSObjId) { + ArtifactFactory(BlackboardArtifact.Type type, long filteringDSObjId) { super(type.getTypeName()); this.type = type; this.filteringDSObjId = filteringDSObjId; @@ -625,7 +661,7 @@ public class ExtractedContent implements AutopsyVisitableItem { protected List makeKeys() { try { List arts; - arts = (filteringDSObjId != null) + arts = (filteringDSObjId > 0) ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(type.getTypeID(), filteringDSObjId) : Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifacts(type.getTypeID()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index a939d977d0..e9eeb392d0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -66,6 +66,14 @@ public class HashsetHits implements AutopsyVisitableItem { private final HashsetResults hashsetResults; private final long filteringDSObjId; // 0 if not filtering/grouping by data source + /** + * Returns the display name for this module. + * @return The display name for this module. + */ + static String getDisplayName() { + return DISPLAY_NAME; + } + /** * Constructor * diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 677aef8df3..8db8588338 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -63,6 +63,14 @@ public class InterestingHits implements AutopsyVisitableItem { private final InterestingResults interestingResults = new InterestingResults(); private final long filteringDSObjId; // 0 if not filtering/grouping by data source + /** + * Returns the display name for this module. + * @return The display name for this module. + */ + static String getDisplayName() { + return DISPLAY_NAME; + } + /** * Constructor * diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 79c6b9a32e..230e35ff65 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -103,6 +103,15 @@ public class KeywordHits implements AutopsyVisitableItem { static private boolean isOnlyDefaultInstance(List instances) { return (instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME)); } + + + /** + * Returns the display name for KeywordHits. + * @return The display name for KeywordHits. + */ + static String getDisplayName() { + return KEYWORD_HITS; + } /** * Constructor diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index 355790976e..48193fde3c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -25,6 +25,8 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardArtifact.Category; import org.sleuthkit.datamodel.SleuthkitVisitableItem; /** @@ -85,7 +87,7 @@ public class RootContentChildren extends Children.Keys { @Override public ExtractedContent.RootNode visit(ExtractedContent ec) { - return ec.new RootNode(ec.getSleuthkitCase()); + return new ExtractedContent.RootNode(ec.getCategory(), ec.getFilteringDSObjId()); } @Override @@ -207,12 +209,16 @@ public class RootContentChildren extends Children.Keys { @Override public AbstractNode visit(AnalysisResults analysisResults) { - return new AnalysisResultsNode(analysisResults); + return new ExtractedContent.RootNode( + Category.ANALYSIS_RESULT, + analysisResults.getFilteringDataSourceObjId()); } @Override public AbstractNode visit(DataArtifacts dataArtifacts) { - return new DataArtifactsNode(dataArtifacts); + return new ExtractedContent.RootNode( + Category.ANALYSIS_RESULT, + dataArtifacts.getFilteringDataSourceObjId()); } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index 39f4303ef1..5ca9ba08c5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -93,6 +93,7 @@ final public class Accounts implements AutopsyVisitableItem { private static final String ICON_BASE_PATH = "/org/sleuthkit/autopsy/images/"; //NON-NLS 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 String DISPLAY_NAME = Bundle.Accounts_RootNode_displayName(); @NbBundle.Messages("AccountsRootNode.name=Accounts") final public static String NAME = Bundle.AccountsRootNode_name(); @@ -113,6 +114,15 @@ final public class Accounts implements AutopsyVisitableItem { // tracks the number of each account type found private final AccountTypeResults accountTypeResults; + + /** + * Returns the display name for this module. + * @return The display name for this module. + */ + public static String getDisplayName() { + return DISPLAY_NAME; + } + /** * Constructor * @@ -236,7 +246,7 @@ final public class Accounts implements AutopsyVisitableItem { public AccountsRootNode() { super(Children.create(new AccountTypeFactory(), true), Lookups.singleton(Accounts.this)); setName(Accounts.NAME); - setDisplayName(Bundle.Accounts_RootNode_displayName()); + setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/accounts.png"); //NON-NLS } From 1d1904478c0e0a967d47f8cd9fa80f2447b3543c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 29 Apr 2021 13:59:07 -0400 Subject: [PATCH 04/16] fixes --- .../datamodel/Bundle.properties-MERGED | 2 + .../autopsy/datamodel/ExtractedContent.java | 184 +++++++++--------- .../datamodel/RootContentChildren.java | 10 +- .../autopsy/images/analysis_result.png | Bin 0 -> 443 bytes 4 files changed, 102 insertions(+), 94 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/images/analysis_result.png diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED index 49d648c6c0..aa955c23e8 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED @@ -39,6 +39,7 @@ AbstractAbstractFileNode.useridColLbl=UserID AbstractContentNode.nodescription=no description AbstractContentNode.valueLoading=value loading AbstractFsContentNode.noDesc.text=no description +AnalysisResultsNode_name=Analysis Results ArtifactStringContent.attrsTableHeader.sources=Source(s) ArtifactStringContent.attrsTableHeader.type=Type ArtifactStringContent.attrsTableHeader.value=Value @@ -93,6 +94,7 @@ ContentTagNode.createSheet.artifactMD5.displayName=MD5 Hash ContentTagNode.createSheet.artifactMD5.name=MD5 Hash ContentTagNode.createSheet.origFileName=Original Name ContentTagNode.createSheet.userName.text=User Name +DataArtifactsNode_name=Data Artifacts DataSourcesHostsNode_name=Data Sources DeletedContent.allDelFilter.text=All DeletedContent.createSheet.filterType.desc=no description diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 8f3f737e41..4c2caa54d8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -18,12 +18,9 @@ */ package org.sleuthkit.autopsy.datamodel; -import com.google.common.collect.ImmutableSet; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.EnumSet; import java.util.HashMap; import java.util.List; @@ -33,13 +30,12 @@ import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.lang3.StringUtils; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -49,7 +45,6 @@ import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.autopsy.datamodel.utils.IconsUtil; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.Blackboard; import org.sleuthkit.datamodel.BlackboardArtifact; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT; @@ -76,7 +71,7 @@ public class ExtractedContent implements AutopsyVisitableItem { private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text"); private static final Category DEFAULT_CATEGORY = Category.DATA_ARTIFACT; - + private final long filteringDSObjId; // 0 if not filtering/grouping by data source private SleuthkitCase skCase; // set to null after case has been closed private final Category category; @@ -89,7 +84,7 @@ public class ExtractedContent implements AutopsyVisitableItem { public ExtractedContent(SleuthkitCase skCase) { this(skCase, 0, DEFAULT_CATEGORY); } - + public ExtractedContent(SleuthkitCase skCase, Category category) { this(skCase, 0, DEFAULT_CATEGORY); } @@ -103,7 +98,7 @@ public class ExtractedContent implements AutopsyVisitableItem { public ExtractedContent(SleuthkitCase skCase, long objId) { this(skCase, objId, DEFAULT_CATEGORY); } - + public ExtractedContent(SleuthkitCase skCase, long dataSourceObjId, Category category) { this.skCase = skCase; this.filteringDSObjId = dataSourceObjId; @@ -118,41 +113,45 @@ public class ExtractedContent implements AutopsyVisitableItem { public SleuthkitCase getSleuthkitCase() { return skCase; } - + long getFilteringDSObjId() { return filteringDSObjId; } - + Category getCategory() { return category; } - - - - - - - static class RootNode extends DisplayableItemNode { - private static final Logger logger = Logger.getLogger(RootNode.class.getName()); - - private static Children getFactory(Category category, long filteringDSObjId) { - try { - TypeFactory factory = Category.ANALYSIS_RESULT.equals(category) ? - new AnalysisResultsTypeFactory(filteringDSObjId) : - new DataArtifactsTypeFactory(filteringDSObjId); - - return Children.create(factory, true); - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Attempt to instantiate TypeFactory with no open case.", ex); - return null; - } - } - RootNode(Category category, long filteringDSObjId) { - super(getFactory(category, filteringDSObjId), Lookups.singleton(NAME)); - super.setName(NAME); - super.setDisplayName(NAME); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png"); //NON-NLS + @Messages({ + "AnalysisResultsNode_name=Analysis Results",}) + static class AnalysisResultsNode extends RootNode { + + AnalysisResultsNode(long filteringDSObjId) { + super(Children.create(new AnalysisResultsTypeFactory(filteringDSObjId), true), + "org/sleuthkit/autopsy/images/analysis_result.png", + Bundle.AnalysisResultsNode_name(), + Bundle.AnalysisResultsNode_name()); + } + } + + @Messages({ + "DataArtifactsNode_name=Data Artifacts",}) + static class DataArtifactsNode extends RootNode { + + DataArtifactsNode(long filteringDSObjId) { + super(Children.create(new DataArtifactsTypeFactory(filteringDSObjId), true), + "org/sleuthkit/autopsy/images/extracted_content.png", + Bundle.DataArtifactsNode_name(), + Bundle.DataArtifactsNode_name()); + } + } + + static class RootNode extends DisplayableItemNode { + RootNode(Children children, String icon, String name, String displayName) { + super(children, Lookups.singleton(name)); + super.setName(name); + super.setDisplayName(displayName); + this.setIconBaseWithExtension(icon); //NON-NLS } @Override @@ -187,9 +186,10 @@ public class ExtractedContent implements AutopsyVisitableItem { } } - private static class AnalysisResultsTypeFactory extends TypeFactory { + private static final Logger logger = Logger.getLogger(AnalysisResultsTypeFactory.class.getName()); + private static final Set EXCLUDED_ANALYSIS_RESULTS = Stream.of( // these are shown in other parts of the UI (and different node types) new BlackboardArtifact.Type(TSK_HASHSET_HIT), @@ -199,24 +199,31 @@ public class ExtractedContent implements AutopsyVisitableItem { new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE) ).collect(Collectors.toSet()); - private static Map getVisitableItems(long filteringDSObjId) throws NoCurrentCaseException { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return new HashMap() { - { - put(new KeywordHits(skCase, filteringDSObjId), KeywordHits.getDisplayName()); - put(new HashsetHits(skCase, filteringDSObjId), HashsetHits.getDisplayName()); - put(new InterestingHits(skCase, filteringDSObjId), InterestingHits.getDisplayName()); - } - }; + private static Map getVisitableItems(long filteringDSObjId) { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return new HashMap() { + { + put(KeywordHits.getDisplayName(), new KeywordHits(skCase, filteringDSObjId)); + put(HashsetHits.getDisplayName(), new HashsetHits(skCase, filteringDSObjId)); + put(InterestingHits.getDisplayName(), new InterestingHits(skCase, filteringDSObjId)); + } + }; + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Trying to create AnalysisResultsTypeFactory with no open case.", ex); + return Collections.emptyMap(); + } } - AnalysisResultsTypeFactory(long filteringDSObjId) throws NoCurrentCaseException { - super(getVisitableItems(filteringDSObjId), EXCLUDED_ANALYSIS_RESULTS, Category.DATA_ARTIFACT, filteringDSObjId); + AnalysisResultsTypeFactory(long filteringDSObjId) { + super(getVisitableItems(filteringDSObjId), EXCLUDED_ANALYSIS_RESULTS, Category.ANALYSIS_RESULT, filteringDSObjId); } } private static class DataArtifactsTypeFactory extends TypeFactory { + private static final Logger logger = Logger.getLogger(DataArtifactsTypeFactory.class.getName()); + @SuppressWarnings("deprecation") private static final Set EXCLUDED_DATA_ARTIFACTS = Stream.of( // these are shown in other parts of the UI (and different node types) @@ -229,17 +236,22 @@ public class ExtractedContent implements AutopsyVisitableItem { new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) ).collect(Collectors.toSet()); - private static Map getVisitableItems(long filteringDSObjId) throws NoCurrentCaseException { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return new HashMap() { - { - put(new EmailExtracted(skCase, filteringDSObjId), EmailExtracted.getDisplayName()); - put(new Accounts(skCase, filteringDSObjId), Accounts.getDisplayName()); - } - }; + private static Map getVisitableItems(long filteringDSObjId) { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return new HashMap() { + { + put(EmailExtracted.getDisplayName(), new EmailExtracted(skCase, filteringDSObjId)); + put(Accounts.getDisplayName(), new Accounts(skCase, filteringDSObjId)); + } + }; + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Trying to create DataArtifactsTypeFactory with no open case.", ex); + return Collections.emptyMap(); + } } - DataArtifactsTypeFactory(long filteringDSObjId) throws NoCurrentCaseException { + DataArtifactsTypeFactory(long filteringDSObjId) { super(getVisitableItems(filteringDSObjId), EXCLUDED_DATA_ARTIFACTS, Category.DATA_ARTIFACT, filteringDSObjId); } } @@ -283,10 +295,9 @@ public class ExtractedContent implements AutopsyVisitableItem { @Override public int hashCode() { - int hash = 5; - hash = 37 * hash + Objects.hashCode(this.visitable); - hash = 37 * hash + Objects.hashCode(this.name); - hash = 37 * hash + Objects.hashCode(this.dsFilteringObjId); + int hash = 7; + hash = 53 * hash + Objects.hashCode(this.name); + hash = 53 * hash + (int) (this.dsFilteringObjId ^ (this.dsFilteringObjId >>> 32)); return hash; } @@ -302,18 +313,14 @@ public class ExtractedContent implements AutopsyVisitableItem { return false; } final VisitableArtifactKey other = (VisitableArtifactKey) obj; + if (this.dsFilteringObjId != other.dsFilteringObjId) { + return false; + } if (!Objects.equals(this.name, other.name)) { return false; } - if (!Objects.equals(this.visitable, other.visitable)) { - return false; - } - if (!Objects.equals(this.dsFilteringObjId, other.dsFilteringObjId)) { - return false; - } return true; } - } private static class TypeArtifactKey implements ArtifactKey { @@ -346,9 +353,8 @@ public class ExtractedContent implements AutopsyVisitableItem { @Override public int hashCode() { int hash = 7; - hash = 83 * hash + Objects.hashCode(this.type); - hash = 83 * hash + Objects.hashCode(this.typeMapping); - hash = 83 * hash + Objects.hashCode(this.dsFilteringObjId); + hash = 53 * hash + Objects.hashCode(this.type); + hash = 53 * hash + (int) (this.dsFilteringObjId ^ (this.dsFilteringObjId >>> 32)); return hash; } @@ -364,18 +370,14 @@ public class ExtractedContent implements AutopsyVisitableItem { return false; } final TypeArtifactKey other = (TypeArtifactKey) obj; + if (this.dsFilteringObjId != other.dsFilteringObjId) { + return false; + } if (!Objects.equals(this.type, other.type)) { return false; } - if (!Objects.equals(this.typeMapping, other.typeMapping)) { - return false; - } - if (!Objects.equals(this.dsFilteringObjId, other.dsFilteringObjId)) { - return false; - } return true; } - } /** @@ -397,12 +399,12 @@ public class ExtractedContent implements AutopsyVisitableItem { * received. */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); - private final Map visitableItems; + private final Map visitableItems; private final Category category; private final Set excludeTypes; @SuppressWarnings("deprecation") - TypeFactory(Map visitableItems, Set excludeTypes, + TypeFactory(Map visitableItems, Set excludeTypes, Category category, long filteringDSObjId) { super(); this.filteringDSObjId = filteringDSObjId; @@ -464,14 +466,20 @@ public class ExtractedContent implements AutopsyVisitableItem { .map(tp -> new TypeArtifactKey(tp, this.typeNodeMap, this.filteringDSObjId)); Stream visitableKeys = visitableItems.entrySet().stream() - .map(entry -> new VisitableArtifactKey(entry.getKey(), entry.getValue(), filteringDSObjId)); + .map(entry -> new VisitableArtifactKey(entry.getValue(), entry.getKey(), filteringDSObjId)); - Stream.concat(typeArtifactKeys, visitableKeys) - .sorted((a, b) -> StringUtils.compareIgnoreCase(a.getName(), b.getName())) - .forEach((artifactTypeKey -> { - artifactTypeKey.update(); - list.add(artifactTypeKey); - })); + List allKeysSorted = Stream.concat(typeArtifactKeys, visitableKeys) + .filter(item -> item != null) + .sorted((a, b) -> { + String aSafe = (a.getName() == null) ? "" : a.getName(); + String bSafe = (b.getName() == null) ? "" : b.getName(); + return aSafe.compareToIgnoreCase(bSafe); + }) + .collect(Collectors.toList()); + + allKeysSorted.forEach(ArtifactKey::update); + + list.addAll(allKeysSorted); } 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/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index 48193fde3c..192a966490 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -87,7 +87,7 @@ public class RootContentChildren extends Children.Keys { @Override public ExtractedContent.RootNode visit(ExtractedContent ec) { - return new ExtractedContent.RootNode(ec.getCategory(), ec.getFilteringDSObjId()); + return new ExtractedContent.DataArtifactsNode(0); } @Override @@ -169,7 +169,7 @@ public class RootContentChildren extends Children.Keys { public AbstractNode visit(Accounts accountsItem) { return accountsItem.new AccountsRootNode(); } - + @Override public AbstractNode visit(OsAccounts osAccountsItem) { return osAccountsItem.new OsAccountListNode(); @@ -209,15 +209,13 @@ public class RootContentChildren extends Children.Keys { @Override public AbstractNode visit(AnalysisResults analysisResults) { - return new ExtractedContent.RootNode( - Category.ANALYSIS_RESULT, + return new ExtractedContent.AnalysisResultsNode( analysisResults.getFilteringDataSourceObjId()); } @Override public AbstractNode visit(DataArtifacts dataArtifacts) { - return new ExtractedContent.RootNode( - Category.ANALYSIS_RESULT, + return new ExtractedContent.DataArtifactsNode( dataArtifacts.getFilteringDataSourceObjId()); } } diff --git a/Core/src/org/sleuthkit/autopsy/images/analysis_result.png b/Core/src/org/sleuthkit/autopsy/images/analysis_result.png new file mode 100644 index 0000000000000000000000000000000000000000..0ff446770a14779b07fb8e55f547327489006fe3 GIT binary patch literal 443 zcmV;s0Yv_ZP)* zfC5ufQwb|;>uFXtwvU1A|K=7J-z+UHcbb@(=)lzA1m@=E7FJf)9}6q%zpmSR`v2*B z@BSaV@#6o4*-O4!S=)RvHa0dw*8>M2n=LJ^KFnXUd^Iq0Wc8zGYiTdqH9FPImH!ELF&-;f&nNNfZljBd->*9=o&$I;@lPQf%4yh z>fQpeJ-U7{0Hp&nGqcx8Y1tQ7?KpZL6eg>79(|aUk$V}a=?^e5y?1nU{AFQb@d2kH zAeR8~M4&;pK`9YRgZQC91AYKg<$ot9r@wd&!3BUCoClvFpfCaQU!toa2w;W)>90UM l6J4Gt05Sv^xDP-94*;r!O$*M}Fj4>j002ovPDHLkV1f_j%)0;p literal 0 HcmV?d00001 From e2f83a897a01d4fddfc035e5a5f286b36e9620e7 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 30 Apr 2021 09:20:25 -0400 Subject: [PATCH 05/16] changes to hide nodes with no results --- .../autopsy/datamodel/ExtractedContent.java | 307 ++++++------------ 1 file changed, 106 insertions(+), 201 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 4c2caa54d8..2204fcf64c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -24,8 +24,6 @@ import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; @@ -40,27 +38,26 @@ import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.RootContentChildren.CreateAutopsyNodeVisitor; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.autopsy.datamodel.utils.IconsUtil; 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_ACCOUNT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_TL_EVENT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.guiutils.RefreshThrottler; import org.sleuthkit.datamodel.BlackboardArtifact.Category; +import org.python.google.common.collect.Sets; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; /** * Parent of the "extracted content" artifacts to be displayed in the tree. @@ -147,6 +144,7 @@ public class ExtractedContent implements AutopsyVisitableItem { } static class RootNode extends DisplayableItemNode { + RootNode(Children children, String icon, String name, String displayName) { super(children, Lookups.singleton(name)); super.setName(name); @@ -187,197 +185,51 @@ public class ExtractedContent implements AutopsyVisitableItem { } private static class AnalysisResultsTypeFactory extends TypeFactory { - - private static final Logger logger = Logger.getLogger(AnalysisResultsTypeFactory.class.getName()); - - private static final Set EXCLUDED_ANALYSIS_RESULTS = Stream.of( - // these are shown in other parts of the UI (and different node types) - new BlackboardArtifact.Type(TSK_HASHSET_HIT), - new BlackboardArtifact.Type(TSK_KEYWORD_HIT), - new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT), - new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), - new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE) - ).collect(Collectors.toSet()); - - private static Map getVisitableItems(long filteringDSObjId) { - try { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return new HashMap() { - { - put(KeywordHits.getDisplayName(), new KeywordHits(skCase, filteringDSObjId)); - put(HashsetHits.getDisplayName(), new HashsetHits(skCase, filteringDSObjId)); - put(InterestingHits.getDisplayName(), new InterestingHits(skCase, filteringDSObjId)); - } - }; - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Trying to create AnalysisResultsTypeFactory with no open case.", ex); - return Collections.emptyMap(); - } - } - AnalysisResultsTypeFactory(long filteringDSObjId) { - super(getVisitableItems(filteringDSObjId), EXCLUDED_ANALYSIS_RESULTS, Category.ANALYSIS_RESULT, filteringDSObjId); + super(Category.ANALYSIS_RESULT, filteringDSObjId); } } private static class DataArtifactsTypeFactory extends TypeFactory { - - private static final Logger logger = Logger.getLogger(DataArtifactsTypeFactory.class.getName()); - - @SuppressWarnings("deprecation") - private static final Set EXCLUDED_DATA_ARTIFACTS = Stream.of( - // these are shown in other parts of the UI (and different node types) - new BlackboardArtifact.Type(TSK_GEN_INFO), - new BlackboardArtifact.Type(TSK_EMAIL_MSG), - new BlackboardArtifact.Type(TSK_ACCOUNT), - new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE), - new BlackboardArtifact.Type(TSK_TL_EVENT), - //This is not meant to be shown in the UI at all. It is more of a meta artifact. - new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) - ).collect(Collectors.toSet()); - - private static Map getVisitableItems(long filteringDSObjId) { - try { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return new HashMap() { - { - put(EmailExtracted.getDisplayName(), new EmailExtracted(skCase, filteringDSObjId)); - put(Accounts.getDisplayName(), new Accounts(skCase, filteringDSObjId)); - } - }; - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Trying to create DataArtifactsTypeFactory with no open case.", ex); - return Collections.emptyMap(); - } - } - DataArtifactsTypeFactory(long filteringDSObjId) { - super(getVisitableItems(filteringDSObjId), EXCLUDED_DATA_ARTIFACTS, Category.DATA_ARTIFACT, filteringDSObjId); + super(Category.DATA_ARTIFACT, filteringDSObjId); } } - interface ArtifactKey { + private static class TypeNodeRecord { - Node getNode(); + private final Node node; + private final Runnable onUpdate; + private final Set applicableTypes; - String getName(); - - void update(); - } - - private static class VisitableArtifactKey implements ArtifactKey { - - private static final CreateAutopsyNodeVisitor visitor = new CreateAutopsyNodeVisitor(); - private final AutopsyVisitableItem visitable; - private final String name; - private final long dsFilteringObjId; - - VisitableArtifactKey(AutopsyVisitableItem visitable, String name, long dsFilteringObjId) { - this.visitable = visitable; - this.name = name; - this.dsFilteringObjId = dsFilteringObjId; + TypeNodeRecord(BlackboardArtifact.Type type, long dsObjId) { + this(new TypeNode(type, dsObjId), type); } - @Override - public Node getNode() { - return visitable.accept(visitor); + private TypeNodeRecord(TypeNode typeNode, BlackboardArtifact.Type type) { + this(typeNode, typeNode::updateDisplayName, Stream.of(type).collect(Collectors.toSet())); } - @Override - public String getName() { - return this.name; + TypeNodeRecord(Node node, Runnable onUpdate, Set applicableTypes) { + this.node = node; + this.onUpdate = onUpdate; + this.applicableTypes = applicableTypes; } - @Override - public void update() { - // no need to handle updates for a visitable item + Node getNode() { + return node; } - @Override - public int hashCode() { - int hash = 7; - hash = 53 * hash + Objects.hashCode(this.name); - hash = 53 * hash + (int) (this.dsFilteringObjId ^ (this.dsFilteringObjId >>> 32)); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; + void update() { + if (onUpdate != null) { + onUpdate.run(); } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final VisitableArtifactKey other = (VisitableArtifactKey) obj; - if (this.dsFilteringObjId != other.dsFilteringObjId) { - return false; - } - if (!Objects.equals(this.name, other.name)) { - return false; - } - return true; - } - } - - private static class TypeArtifactKey implements ArtifactKey { - - private final BlackboardArtifact.Type type; - private final Map typeMapping; - private final long dsFilteringObjId; - - TypeArtifactKey(BlackboardArtifact.Type type, Map typeMapping, long dsFilteringObjId) { - this.type = type; - this.typeMapping = typeMapping; - this.dsFilteringObjId = dsFilteringObjId; } - @Override - public TypeNode getNode() { - return typeMapping.computeIfAbsent(type, (tp) -> new TypeNode(type, dsFilteringObjId)); + Set getApplicableTypes() { + return applicableTypes; } - @Override - public String getName() { - return this.type.getDisplayName(); - } - - @Override - public void update() { - getNode().updateDisplayName(); - } - - @Override - public int hashCode() { - int hash = 7; - hash = 53 * hash + Objects.hashCode(this.type); - hash = 53 * hash + (int) (this.dsFilteringObjId ^ (this.dsFilteringObjId >>> 32)); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final TypeArtifactKey other = (TypeArtifactKey) obj; - if (this.dsFilteringObjId != other.dsFilteringObjId) { - return false; - } - if (!Objects.equals(this.type, other.type)) { - return false; - } - return true; - } } /** @@ -385,12 +237,59 @@ public class ExtractedContent implements AutopsyVisitableItem { * This area has all of the blackboard artifacts that are not displayed in a * more specific form elsewhere in the tree. */ - private static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { + private static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); + private static final Set IGNORED_TYPES = Sets.newHashSet( + // these are shown in other parts of the UI (and different node types) + new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE), + new BlackboardArtifact.Type(TSK_GEN_INFO), + new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE), + new BlackboardArtifact.Type(TSK_TL_EVENT), + //This is not meant to be shown in the UI at all. It is more of a meta artifact. + new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) + ); + + private static TypeNodeRecord getRecord(BlackboardArtifact.Type type, SleuthkitCase skCase, long dsObjId) { + int typeId = type.getTypeID(); + if (TSK_EMAIL_MSG.getTypeID() == typeId) { + EmailExtracted.RootNode emailNode = new EmailExtracted(skCase, dsObjId).new RootNode(); + return new TypeNodeRecord( + emailNode, + null, + Sets.newHashSet(new BlackboardArtifact.Type(TSK_EMAIL_MSG))); + + } else if (TSK_ACCOUNT.getTypeID() == typeId) { + Accounts.AccountsRootNode accountsNode = new Accounts(skCase, dsObjId).new AccountsRootNode(); + return new TypeNodeRecord( + accountsNode, + null, + Sets.newHashSet(new BlackboardArtifact.Type(TSK_ACCOUNT))); + + } else if (TSK_KEYWORD_HIT.getTypeID() == typeId) { + KeywordHits.RootNode keywordsNode = new KeywordHits(skCase, dsObjId).new RootNode(); + return new TypeNodeRecord( + keywordsNode, + null, + Sets.newHashSet(new BlackboardArtifact.Type(TSK_KEYWORD_HIT))); + + } else if (TSK_EMAIL_MSG.getTypeID() == typeId) { + InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, dsObjId).new RootNode(); + return new TypeNodeRecord( + interestingHitsNode, + null, + Sets.newHashSet( + new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), + new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT))); + + } else { + return new TypeNodeRecord(type, dsObjId); + } + } + // maps the artifact type to its child node - private final HashMap typeNodeMap = new HashMap<>(); + private final HashMap typeNodeMap = new HashMap<>(); private final long filteringDSObjId; /** @@ -399,17 +298,12 @@ public class ExtractedContent implements AutopsyVisitableItem { * received. */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); - private final Map visitableItems; private final Category category; - private final Set excludeTypes; @SuppressWarnings("deprecation") - TypeFactory(Map visitableItems, Set excludeTypes, - Category category, long filteringDSObjId) { + TypeFactory(Category category, long filteringDSObjId) { super(); this.filteringDSObjId = filteringDSObjId; - this.excludeTypes = excludeTypes; - this.visitableItems = visitableItems; this.category = category; } @@ -454,31 +348,42 @@ public class ExtractedContent implements AutopsyVisitableItem { } @Override - protected boolean createKeys(List list) { + protected boolean createKeys(List list) { try { + // Potentially can reuse List types = (this.filteringDSObjId > 0) ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactTypesInUse(this.filteringDSObjId) : Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse(); - Stream typeArtifactKeys = types.stream() - .filter(tp -> category.equals(tp.getCategory()) && !excludeTypes.contains(tp)) - .map(tp -> new TypeArtifactKey(tp, this.typeNodeMap, this.filteringDSObjId)); - - Stream visitableKeys = visitableItems.entrySet().stream() - .map(entry -> new VisitableArtifactKey(entry.getValue(), entry.getKey(), filteringDSObjId)); - - List allKeysSorted = Stream.concat(typeArtifactKeys, visitableKeys) - .filter(item -> item != null) + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + + List allKeysSorted = types.stream() + .filter(tp -> category.equals(tp.getCategory()) && !IGNORED_TYPES.contains(tp)) + .map(tp -> { + if (typeNodeMap.containsKey(tp)) { + TypeNodeRecord record = typeNodeMap.get(tp); + record.update(); + return record; + } else { + TypeNodeRecord newRecord = getRecord(tp, skCase, filteringDSObjId); + for (BlackboardArtifact.Type recordType : newRecord.getApplicableTypes()) { + typeNodeMap.put(recordType, newRecord); + } + return newRecord; + } + }) + .filter(record -> record != null) + .distinct() .sorted((a, b) -> { - String aSafe = (a.getName() == null) ? "" : a.getName(); - String bSafe = (b.getName() == null) ? "" : b.getName(); + String aSafe = (a.getNode() == null || a.getNode().getDisplayName() == null) ? "" : a.getNode().getDisplayName(); + String bSafe = (b.getNode() == null || b.getNode().getDisplayName() == null) ? "" : b.getNode().getDisplayName(); return aSafe.compareToIgnoreCase(bSafe); }) .collect(Collectors.toList()); - - allKeysSorted.forEach(ArtifactKey::update); - + + allKeysSorted.forEach(record -> record.update()); + list.addAll(allKeysSorted); } catch (NoCurrentCaseException ex) { @@ -490,7 +395,7 @@ public class ExtractedContent implements AutopsyVisitableItem { } @Override - protected Node createNodeForKey(ArtifactKey key) { + protected Node createNodeForKey(TypeNodeRecord key) { return key.getNode(); } @@ -517,7 +422,7 @@ public class ExtractedContent implements AutopsyVisitableItem { */ final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); if (null != event && category.equals(event.getBlackboardArtifactType().getCategory()) - && !(excludeTypes.contains(event.getBlackboardArtifactType()))) { + && !(IGNORED_TYPES.contains(event.getBlackboardArtifactType()))) { return true; } } catch (NoCurrentCaseException notUsed) { From eadb3a8c6bd5259efcbd249ae7231eaa69995d96 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 30 Apr 2021 11:01:09 -0400 Subject: [PATCH 06/16] counts in special artifact nodes --- .../autopsy/datamodel/EmailExtracted.java | 22 ++-- .../autopsy/datamodel/ExtractedContent.java | 102 +++++++++++++----- .../autopsy/datamodel/HashsetHits.java | 20 ++-- .../autopsy/datamodel/InterestingHits.java | 21 ++-- .../autopsy/datamodel/KeywordHits.java | 21 ++-- .../autopsy/datamodel/accounts/Accounts.java | 23 ++-- 6 files changed, 125 insertions(+), 84 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 6495e9d7fe..9e3555d438 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -32,7 +32,6 @@ import java.util.Observable; import java.util.Observer; import java.util.Set; import java.util.logging.Level; -import org.apache.commons.lang3.tuple.Pair; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; @@ -45,10 +44,12 @@ 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_EMAIL_MSG; 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.ExtractedContent.UpdatableTypeCountNode; /** * Support for TSK_EMAIL_MSG nodes and displaying emails in the directory tree. @@ -59,7 +60,6 @@ import org.sleuthkit.datamodel.TskCoreException; public class EmailExtracted implements AutopsyVisitableItem { private static final String LABEL_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getLabel(); - private static final String DISPLAY_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getDisplayName(); private static final Logger logger = Logger.getLogger(EmailExtracted.class.getName()); private static final String MAIL_ACCOUNT = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailAccount.text"); private static final String MAIL_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text"); @@ -91,14 +91,6 @@ public class EmailExtracted implements AutopsyVisitableItem { private SleuthkitCase skCase; private final EmailResults emailResults; private final long filteringDSObjId; // 0 if not filtering/grouping by data source - - /** - * Returns the display name for this module. - * @return The display name for this module. - */ - static String getDisplayName() { - return DISPLAY_NAME; - } /** * Constructor @@ -213,12 +205,16 @@ public class EmailExtracted implements AutopsyVisitableItem { * Mail root node grouping all mail accounts, supports account-> folder * structure */ - public class RootNode extends DisplayableItemNode { + public class RootNode extends UpdatableTypeCountNode { public RootNode() { - super(Children.create(new AccountFactory(), true), Lookups.singleton(DISPLAY_NAME)); + super(Children.create(new AccountFactory(), true), + Lookups.singleton(TSK_EMAIL_MSG.getDisplayName()), + TSK_EMAIL_MSG.getDisplayName(), + filteringDSObjId, + new BlackboardArtifact.Type(TSK_EMAIL_MSG)); + //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 emailResults.update(); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 2204fcf64c..6893c546db 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -20,9 +20,11 @@ package org.sleuthkit.autopsy.datamodel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; @@ -32,6 +34,7 @@ import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; +import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.Lookups; @@ -185,12 +188,14 @@ public class ExtractedContent implements AutopsyVisitableItem { } private static class AnalysisResultsTypeFactory extends TypeFactory { + AnalysisResultsTypeFactory(long filteringDSObjId) { super(Category.ANALYSIS_RESULT, filteringDSObjId); } } private static class DataArtifactsTypeFactory extends TypeFactory { + DataArtifactsTypeFactory(long filteringDSObjId) { super(Category.DATA_ARTIFACT, filteringDSObjId); } @@ -274,7 +279,9 @@ public class ExtractedContent implements AutopsyVisitableItem { null, Sets.newHashSet(new BlackboardArtifact.Type(TSK_KEYWORD_HIT))); - } else if (TSK_EMAIL_MSG.getTypeID() == typeId) { + } 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 TypeNodeRecord( interestingHitsNode, @@ -351,13 +358,11 @@ public class ExtractedContent implements AutopsyVisitableItem { protected boolean createKeys(List list) { try { - // Potentially can reuse - List types = (this.filteringDSObjId > 0) - ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactTypesInUse(this.filteringDSObjId) - : Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse(); - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - + List types = (this.filteringDSObjId > 0) + ? skCase.getBlackboard().getArtifactTypesInUse(this.filteringDSObjId) + : skCase.getArtifactTypesInUse(); + List allKeysSorted = types.stream() .filter(tp -> category.equals(tp.getCategory()) && !IGNORED_TYPES.contains(tp)) .map(tp -> { @@ -435,41 +440,84 @@ public class ExtractedContent implements AutopsyVisitableItem { } } + public static abstract class UpdatableTypeCountNode extends DisplayableItemNode { + + private static final Logger logger = Logger.getLogger(UpdatableTypeCountNode.class.getName()); + + private final Set types; + private final long filteringDSObjId; + private long childCount = 0; + private final String baseName; + + /** + * Constructs a node that is eligible for display in the tree view or + * results view. Capabilitites include accepting a + * DisplayableItemNodeVisitor, indicating whether or not the node is a + * leaf node, providing an item type string suitable for use as a key, + * and storing information about a child node that is to be selected if + * the node is selected in the tree view. + * + * @param children The Children object for the node. + * @param lookup The Lookup object for the node. + */ + public UpdatableTypeCountNode(Children children, Lookup lookup, String baseName, long filteringDSObjId, BlackboardArtifact.Type... types) { + super(children, lookup); + this.types = Stream.of(types).collect(Collectors.toSet()); + this.filteringDSObjId = filteringDSObjId; + this.baseName = baseName; + updateDisplayName(); + } + + protected long getChildCount() { + return this.childCount; + } + + void updateDisplayName() { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + + int count = 0; + for (BlackboardArtifact.Type type : this.types) { + if (filteringDSObjId > 0) { + count += skCase.getBlackboard().getArtifactsCount(type.getTypeID(), filteringDSObjId); + } else { + count += skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); + } + } + + this.childCount = count; + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Error fetching data when case closed.", ex); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Error getting child count", ex); //NON-NLS + } + super.setDisplayName(this.baseName + " \u200E(\u200E" + this.childCount + ")\u200E"); + } + } + /** * 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 static class TypeNode extends DisplayableItemNode { + public static class TypeNode extends UpdatableTypeCountNode { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); private final BlackboardArtifact.Type type; - private long childCount = 0; - private final long filteringDSObjId; TypeNode(BlackboardArtifact.Type type, long filteringDSObjId) { - super(Children.create(new ArtifactFactory(type, filteringDSObjId), true), Lookups.singleton(type.getDisplayName())); + super(Children.create(new ArtifactFactory(type, filteringDSObjId), true), + Lookups.singleton(type.getDisplayName()), + type.getDisplayName(), + filteringDSObjId, + type); + super.setName(type.getTypeName()); this.type = type; - this.filteringDSObjId = filteringDSObjId; String iconPath = IconsUtil.getIconFilePath(type.getTypeID()); setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath); - updateDisplayName(); - } - - final void updateDisplayName() { - try { - this.childCount = (filteringDSObjId > 0) - ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactsCount(type.getTypeID(), filteringDSObjId) - : Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifactsTypeCount(type.getTypeID()); - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Error fetching data when case closed.", ex); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error getting child count", ex); //NON-NLS - } - super.setDisplayName(type.getDisplayName() + " \u200E(\u200E" + childCount + ")\u200E"); } @Override @@ -489,7 +537,7 @@ public class ExtractedContent implements AutopsyVisitableItem { sheetSet.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)); + getChildCount())); return sheet; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index e9eeb392d0..c063081699 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -47,10 +47,14 @@ import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; + /** * Hash set hits node support. Inner classes have all of the nodes in the tree. @@ -66,13 +70,6 @@ public class HashsetHits implements AutopsyVisitableItem { private final HashsetResults hashsetResults; private final long filteringDSObjId; // 0 if not filtering/grouping by data source - /** - * Returns the display name for this module. - * @return The display name for this module. - */ - static String getDisplayName() { - return DISPLAY_NAME; - } /** * Constructor @@ -176,10 +173,15 @@ public class HashsetHits implements AutopsyVisitableItem { /** * Top-level node for all hash sets */ - public class RootNode extends DisplayableItemNode { + public class RootNode extends UpdatableTypeCountNode { public RootNode() { - super(Children.create(new HashsetNameFactory(), true), Lookups.singleton(DISPLAY_NAME)); + super(Children.create(new HashsetNameFactory(), true), + Lookups.singleton(DISPLAY_NAME), + DISPLAY_NAME, + filteringDSObjId, + new BlackboardArtifact.Type(TSK_HASHSET_HIT)); + super.setName(HASHSET_HITS); super.setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 8db8588338..93b6480c26 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -50,6 +50,9 @@ 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.ExtractedContent.UpdatableTypeCountNode; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; + public class InterestingHits implements AutopsyVisitableItem { @@ -63,14 +66,6 @@ public class InterestingHits implements AutopsyVisitableItem { private final InterestingResults interestingResults = new InterestingResults(); private final long filteringDSObjId; // 0 if not filtering/grouping by data source - /** - * Returns the display name for this module. - * @return The display name for this module. - */ - static String getDisplayName() { - return DISPLAY_NAME; - } - /** * Constructor * @@ -173,12 +168,16 @@ public class InterestingHits implements AutopsyVisitableItem { /** * Node for the interesting items */ - public class RootNode extends DisplayableItemNode { + public class RootNode extends UpdatableTypeCountNode { public RootNode() { - super(Children.create(new SetNameFactory(), true), Lookups.singleton(DISPLAY_NAME)); + super(Children.create(new SetNameFactory(), true), + Lookups.singleton(DISPLAY_NAME), + DISPLAY_NAME, + filteringDSObjId, + new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT), + new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT)); super.setName(INTERESTING_ITEMS); - super.setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 230e35ff65..82ea4263b1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -55,6 +55,8 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; +import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; /** * Keyword hits node support @@ -104,15 +106,6 @@ public class KeywordHits implements AutopsyVisitableItem { return (instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME)); } - - /** - * Returns the display name for KeywordHits. - * @return The display name for KeywordHits. - */ - static String getDisplayName() { - return KEYWORD_HITS; - } - /** * Constructor * @@ -384,12 +377,16 @@ public class KeywordHits implements AutopsyVisitableItem { } // Created by CreateAutopsyNodeVisitor - public class RootNode extends DisplayableItemNode { + public class RootNode extends UpdatableTypeCountNode { public RootNode() { - super(Children.create(new ListFactory(), true), Lookups.singleton(KEYWORD_HITS)); + super(Children.create(new ListFactory(), true), + Lookups.singleton(KEYWORD_HITS), + KEYWORD_HITS, + filteringDSObjId, + new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); + super.setName(NAME); - super.setDisplayName(KEYWORD_HITS); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index 5ca9ba08c5..2eb2c6e021 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -69,6 +69,8 @@ import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; +import org.sleuthkit.autopsy.datamodel.ExtractedContent; +import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -77,6 +79,7 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; @@ -115,14 +118,6 @@ final public class Accounts implements AutopsyVisitableItem { private final AccountTypeResults accountTypeResults; - /** - * Returns the display name for this module. - * @return The display name for this module. - */ - public static String getDisplayName() { - return DISPLAY_NAME; - } - /** * Constructor * @@ -241,12 +236,16 @@ final public class Accounts implements AutopsyVisitableItem { * Top-level node for the accounts tree */ @NbBundle.Messages({"Accounts.RootNode.displayName=Accounts"}) - final public class AccountsRootNode extends DisplayableItemNode { + final public class AccountsRootNode extends UpdatableTypeCountNode { public AccountsRootNode() { - super(Children.create(new AccountTypeFactory(), true), Lookups.singleton(Accounts.this)); + super(Children.create(new AccountTypeFactory(), true), + Lookups.singleton(Accounts.this), + DISPLAY_NAME, + filteringDSObjId, + new BlackboardArtifact.Type(TSK_ACCOUNT)); + setName(Accounts.NAME); - setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/accounts.png"); //NON-NLS } @@ -303,7 +302,7 @@ final public class Accounts implements AutopsyVisitableItem { = "SELECT blackboard_attributes.value_text as account_type, COUNT(*) as count " + " 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.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + getFilterByDataSourceClause() + " GROUP BY blackboard_attributes.value_text "; From 758b5fcc36037f571a1d541480f9cbd2a71ce27f Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 30 Apr 2021 11:06:11 -0400 Subject: [PATCH 07/16] refactor --- .../autopsy/datamodel/ExtractedContent.java | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 6893c546db..48519061d0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -211,14 +211,16 @@ public class ExtractedContent implements AutopsyVisitableItem { this(new TypeNode(type, dsObjId), type); } - private TypeNodeRecord(TypeNode typeNode, BlackboardArtifact.Type type) { - this(typeNode, typeNode::updateDisplayName, Stream.of(type).collect(Collectors.toSet())); + private TypeNodeRecord(UpdatableTypeCountNode typeNode, BlackboardArtifact.Type...types) { + this(typeNode, typeNode::updateDisplayName, types); } - TypeNodeRecord(Node node, Runnable onUpdate, Set applicableTypes) { + TypeNodeRecord(Node node, Runnable onUpdate, BlackboardArtifact.Type...types) { this.node = node; this.onUpdate = onUpdate; - this.applicableTypes = applicableTypes; + this.applicableTypes = Stream.of(types) + .filter(t -> t != null) + .collect(Collectors.toSet()); } Node getNode() { @@ -246,6 +248,7 @@ public class ExtractedContent implements AutopsyVisitableItem { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); + @SuppressWarnings("deprecation") private static final Set IGNORED_TYPES = Sets.newHashSet( // these are shown in other parts of the UI (and different node types) new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE), @@ -260,35 +263,23 @@ public class ExtractedContent implements AutopsyVisitableItem { int typeId = type.getTypeID(); if (TSK_EMAIL_MSG.getTypeID() == typeId) { EmailExtracted.RootNode emailNode = new EmailExtracted(skCase, dsObjId).new RootNode(); - return new TypeNodeRecord( - emailNode, - null, - Sets.newHashSet(new BlackboardArtifact.Type(TSK_EMAIL_MSG))); + return new TypeNodeRecord(emailNode, new BlackboardArtifact.Type(TSK_EMAIL_MSG)); } else if (TSK_ACCOUNT.getTypeID() == typeId) { Accounts.AccountsRootNode accountsNode = new Accounts(skCase, dsObjId).new AccountsRootNode(); - return new TypeNodeRecord( - accountsNode, - null, - Sets.newHashSet(new BlackboardArtifact.Type(TSK_ACCOUNT))); + return new TypeNodeRecord(accountsNode, new BlackboardArtifact.Type(TSK_ACCOUNT)); } else if (TSK_KEYWORD_HIT.getTypeID() == typeId) { KeywordHits.RootNode keywordsNode = new KeywordHits(skCase, dsObjId).new RootNode(); - return new TypeNodeRecord( - keywordsNode, - null, - Sets.newHashSet(new BlackboardArtifact.Type(TSK_KEYWORD_HIT))); + return new TypeNodeRecord(keywordsNode, new BlackboardArtifact.Type(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 TypeNodeRecord( - interestingHitsNode, - null, - Sets.newHashSet( + return new TypeNodeRecord(interestingHitsNode, new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), - new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT))); + new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT)); } else { return new TypeNodeRecord(type, dsObjId); From ff946979a1bf7de7714deef0c1f87659ed2f3754 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 30 Apr 2021 12:49:16 -0400 Subject: [PATCH 08/16] cleanup --- .../autopsy/datamodel/AnalysisResults.java | 4 +- .../autopsy/datamodel/AutopsyItemVisitor.java | 14 --- .../datamodel/AutopsyTreeChildFactory.java | 7 +- .../autopsy/datamodel/DataArtifacts.java | 4 +- .../datamodel/DisplayableItemNodeVisitor.java | 10 -- .../autopsy/datamodel/EmailExtracted.java | 36 ++++--- .../autopsy/datamodel/ExtractedContent.java | 74 ++------------ .../autopsy/datamodel/HashsetHits.java | 7 +- .../autopsy/datamodel/InterestingHits.java | 14 ++- .../autopsy/datamodel/KeywordHits.java | 4 +- .../sleuthkit/autopsy/datamodel/Results.java | 52 ---------- .../autopsy/datamodel/ResultsNode.java | 97 ------------------- .../datamodel/RootContentChildren.java | 13 --- .../autopsy/datamodel/accounts/Accounts.java | 1 - 14 files changed, 44 insertions(+), 293 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/Results.java delete mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java index ed6bd37319..b0f038ba4a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,7 @@ package org.sleuthkit.autopsy.datamodel; /** - * Analysis Results node support + * Analysis Results node support. */ public class AnalysisResults implements AutopsyVisitableItem { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java index ed719a341e..9791d0d5fd 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java @@ -53,8 +53,6 @@ public interface AutopsyItemVisitor { T visit(FileSize.FileSizeFilter fsf); - T visit(ExtractedContent ec); - T visit(KeywordHits kh); T visit(HashsetHits hh); @@ -63,8 +61,6 @@ public interface AutopsyItemVisitor { T visit(InterestingHits ih); - T visit(Results r); - T visit(Tags tagsNodeKey); T visit(Reports reportsItem); @@ -94,11 +90,6 @@ public interface AutopsyItemVisitor { protected abstract T defaultVisit(AutopsyVisitableItem ec); - @Override - public T visit(ExtractedContent ec) { - return defaultVisit(ec); - } - @Override public T visit(FileTypesByExtension sf) { return defaultVisit(sf); @@ -204,11 +195,6 @@ public interface AutopsyItemVisitor { return defaultVisit(personGrouping); } - @Override - public T visit(Results r) { - return defaultVisit(r); - } - @Override public T visit(FileTypes ft) { return defaultVisit(ft); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java index 9ebb44cb40..845591e261 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java @@ -92,7 +92,6 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable keys = new ArrayList<>(Arrays.asList( diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java index e273d8cf12..2c52278459 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,7 @@ package org.sleuthkit.autopsy.datamodel; /** - * Analysis Results node support + * Analysis Results node support. */ public class DataArtifacts implements AutopsyVisitableItem { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 61bc401ee5..4cdb32ff2c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -88,11 +88,6 @@ public interface DisplayableItemNodeVisitor { T visit(RecentFilesFilterNode rffn); - /* - * Extracted Results Area - */ - T visit(ResultsNode rn); - T visit(BlackboardArtifactNode ban); T visit(ExtractedContent.TypeNode atn); @@ -405,11 +400,6 @@ public interface DisplayableItemNodeVisitor { return defaultVisit(dataSourceGroupingNode); } - @Override - public T visit(ResultsNode rn) { - return defaultVisit(rn); - } - @Override public T visit(FileTypesNode ft) { return defaultVisit(ft); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 9e3555d438..d042573e53 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -91,7 +91,7 @@ public class EmailExtracted implements AutopsyVisitableItem { private SleuthkitCase skCase; private final EmailResults emailResults; private final long filteringDSObjId; // 0 if not filtering/grouping by data source - + /** * Constructor * @@ -147,7 +147,7 @@ public class EmailExtracted implements AutopsyVisitableItem { } @SuppressWarnings("deprecation") - public void update() { + public void update() { // clear cache if no case if (skCase == null) { synchronized (accounts) { @@ -159,20 +159,20 @@ public class EmailExtracted implements AutopsyVisitableItem { // get artifact id and path (if present) of all email artifacts int emailArtifactId = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(); int pathAttrId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID(); - - String query = "SELECT \n" + - " art.artifact_id AS artifact_id,\n" + - " (SELECT value_text FROM blackboard_attributes attr\n" + - " WHERE attr.artifact_id = art.artifact_id AND attr.attribute_type_id = " + pathAttrId + "\n" + - " LIMIT 1) AS value_text\n" + - "FROM \n" + - " blackboard_artifacts art\n" + - " WHERE art.artifact_type_id = " + emailArtifactId + "\n" + - ((filteringDSObjId > 0) ? " AND art.data_source_obj_id = " + filteringDSObjId : ""); - + + String query = "SELECT \n" + + " art.artifact_id AS artifact_id,\n" + + " (SELECT value_text FROM blackboard_attributes attr\n" + + " WHERE attr.artifact_id = art.artifact_id AND attr.attribute_type_id = " + pathAttrId + "\n" + + " LIMIT 1) AS value_text\n" + + "FROM \n" + + " blackboard_artifacts art\n" + + " WHERE art.artifact_type_id = " + emailArtifactId + "\n" + + ((filteringDSObjId > 0) ? " AND art.data_source_obj_id = " + filteringDSObjId : ""); + // form hierarchy of account -> folder -> account id Map>> newMapping = new HashMap<>(); - + try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { ResultSet resultSet = dbQuery.getResultSet(); while (resultSet.next()) { @@ -180,7 +180,7 @@ public class EmailExtracted implements AutopsyVisitableItem { Map accountFolderMap = parsePath(resultSet.getString("value_text")); String account = accountFolderMap.get(MAIL_ACCOUNT); String folder = accountFolderMap.get(MAIL_FOLDER); - + Map> folders = newMapping.computeIfAbsent(account, (str) -> new LinkedHashMap<>()); List messages = folders.computeIfAbsent(folder, (str) -> new ArrayList<>()); messages.add(artifactId); @@ -188,18 +188,16 @@ public class EmailExtracted implements AutopsyVisitableItem { } catch (TskCoreException | SQLException ex) { logger.log(Level.WARNING, "Cannot initialize email extraction: ", ex); //NON-NLS } - - + synchronized (accounts) { accounts.clear(); accounts.putAll(newMapping); } - + setChanged(); notifyObservers(); } } - /** * Mail root node grouping all mail accounts, supports account-> folder diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 48519061d0..ac9435cea0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -20,11 +20,9 @@ package org.sleuthkit.autopsy.datamodel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; @@ -66,61 +64,9 @@ import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWO * Parent of the "extracted content" artifacts to be displayed in the tree. * Other artifacts are displayed under other more specific parents. */ -public class ExtractedContent implements AutopsyVisitableItem { +public class ExtractedContent { private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); - public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text"); - private static final Category DEFAULT_CATEGORY = Category.DATA_ARTIFACT; - - private final long filteringDSObjId; // 0 if not filtering/grouping by data source - private SleuthkitCase skCase; // set to null after case has been closed - private final Category category; - - /** - * Constructs extracted content object - * - * @param skCase Case DB - */ - public ExtractedContent(SleuthkitCase skCase) { - this(skCase, 0, DEFAULT_CATEGORY); - } - - public ExtractedContent(SleuthkitCase skCase, Category category) { - this(skCase, 0, DEFAULT_CATEGORY); - } - - /** - * Constructs extracted content object - * - * @param skCase Case DB - * @param objId Object id of the parent datasource - */ - public ExtractedContent(SleuthkitCase skCase, long objId) { - this(skCase, objId, DEFAULT_CATEGORY); - } - - public ExtractedContent(SleuthkitCase skCase, long dataSourceObjId, Category category) { - this.skCase = skCase; - this.filteringDSObjId = dataSourceObjId; - this.category = category; - } - - @Override - public T accept(AutopsyItemVisitor visitor) { - return visitor.visit(this); - } - - public SleuthkitCase getSleuthkitCase() { - return skCase; - } - - long getFilteringDSObjId() { - return filteringDSObjId; - } - - Category getCategory() { - return category; - } @Messages({ "AnalysisResultsNode_name=Analysis Results",}) @@ -177,7 +123,7 @@ public class ExtractedContent implements AutopsyVisitableItem { sheetSet.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)); + super.getDisplayName())); return sheet; } @@ -211,11 +157,11 @@ public class ExtractedContent implements AutopsyVisitableItem { this(new TypeNode(type, dsObjId), type); } - private TypeNodeRecord(UpdatableTypeCountNode typeNode, BlackboardArtifact.Type...types) { + private TypeNodeRecord(UpdatableTypeCountNode typeNode, BlackboardArtifact.Type... types) { this(typeNode, typeNode::updateDisplayName, types); } - TypeNodeRecord(Node node, Runnable onUpdate, BlackboardArtifact.Type...types) { + TypeNodeRecord(Node node, Runnable onUpdate, BlackboardArtifact.Type... types) { this.node = node; this.onUpdate = onUpdate; this.applicableTypes = Stream.of(types) @@ -273,13 +219,13 @@ public class ExtractedContent implements AutopsyVisitableItem { KeywordHits.RootNode keywordsNode = new KeywordHits(skCase, dsObjId).new RootNode(); return new TypeNodeRecord(keywordsNode, new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); - } else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId || - TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) { - + } 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 TypeNodeRecord(interestingHitsNode, - new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), - new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT)); + return new TypeNodeRecord(interestingHitsNode, + new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), + new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT)); } else { return new TypeNodeRecord(type, dsObjId); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index c063081699..7a04d3cf33 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -48,14 +48,12 @@ import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; - /** * Hash set hits node support. Inner classes have all of the nodes in the tree. */ @@ -70,7 +68,6 @@ public class HashsetHits implements AutopsyVisitableItem { private final HashsetResults hashsetResults; private final long filteringDSObjId; // 0 if not filtering/grouping by data source - /** * Constructor * @@ -176,12 +173,12 @@ public class HashsetHits implements AutopsyVisitableItem { public class RootNode extends UpdatableTypeCountNode { public RootNode() { - super(Children.create(new HashsetNameFactory(), true), + super(Children.create(new HashsetNameFactory(), true), Lookups.singleton(DISPLAY_NAME), DISPLAY_NAME, filteringDSObjId, new BlackboardArtifact.Type(TSK_HASHSET_HIT)); - + super.setName(HASHSET_HITS); super.setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 93b6480c26..27d08f3781 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -51,8 +51,6 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; - public class InterestingHits implements AutopsyVisitableItem { @@ -171,7 +169,7 @@ public class InterestingHits implements AutopsyVisitableItem { public class RootNode extends UpdatableTypeCountNode { public RootNode() { - super(Children.create(new SetNameFactory(), true), + super(Children.create(new SetNameFactory(), true), Lookups.singleton(DISPLAY_NAME), DISPLAY_NAME, filteringDSObjId, @@ -407,8 +405,8 @@ public class InterestingHits implements AutopsyVisitableItem { 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 + * 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); @@ -469,9 +467,9 @@ public class InterestingHits implements AutopsyVisitableItem { private HitFactory(String setName, String typeName) { /** - * 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 + * 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); this.setName = setName; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 82ea4263b1..6713a6722b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -105,7 +105,7 @@ public class KeywordHits implements AutopsyVisitableItem { static private boolean isOnlyDefaultInstance(List instances) { return (instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME)); } - + /** * Constructor * @@ -380,7 +380,7 @@ public class KeywordHits implements AutopsyVisitableItem { public class RootNode extends UpdatableTypeCountNode { public RootNode() { - super(Children.create(new ListFactory(), true), + super(Children.create(new ListFactory(), true), Lookups.singleton(KEYWORD_HITS), KEYWORD_HITS, filteringDSObjId, diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Results.java b/Core/src/org/sleuthkit/autopsy/datamodel/Results.java deleted file mode 100644 index b2d9f4799b..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Results.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.datamodel; - -import org.sleuthkit.datamodel.SleuthkitCase; - -/** - * Results node support - */ -public class Results implements AutopsyVisitableItem { - - private SleuthkitCase skCase; - private final long datasourceObjId; - - public Results(SleuthkitCase skCase) { - this(skCase, 0); - } - - public Results(SleuthkitCase skCase, long dsObjId) { - this.skCase = skCase; - this.datasourceObjId = dsObjId; - } - - @Override - public T accept(AutopsyItemVisitor visitor) { - return visitor.visit(this); - } - - public SleuthkitCase getSleuthkitCase() { - return skCase; - } - - long filteringDataSourceObjId() { - return datasourceObjId; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java deleted file mode 100644 index e9b2eba696..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2018 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.datamodel; - -import org.sleuthkit.autopsy.datamodel.accounts.Accounts; -import java.util.Arrays; -import org.openide.nodes.Sheet; -import org.openide.util.NbBundle; -import org.openide.util.lookup.Lookups; -import org.sleuthkit.datamodel.SleuthkitCase; - -/** - * Node for the results section of the tree. - */ -public class ResultsNode extends DisplayableItemNode { - - @NbBundle.Messages("ResultsNode.name.text=Results") - private static final String NAME = Bundle.ResultsNode_name_text(); - - public static String getNameIdentifier() { - return NAME; - } - - public ResultsNode(SleuthkitCase sleuthkitCase) { - this(sleuthkitCase, 0); - } - - public ResultsNode(SleuthkitCase sleuthkitCase, long dsObjId) { - super( - - new RootContentChildren(Arrays.asList( - new ExtractedContent(sleuthkitCase, dsObjId ), - new KeywordHits(sleuthkitCase, dsObjId), - new HashsetHits(sleuthkitCase, dsObjId), - new EmailExtracted(sleuthkitCase, dsObjId), - new InterestingHits(sleuthkitCase, dsObjId ), - new Accounts(sleuthkitCase, dsObjId), - new OsAccounts(sleuthkitCase, dsObjId)) - ), - Lookups.singleton(NAME)); - setName(NAME); - setDisplayName(NAME); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png"); //NON-NLS - } - - @Override - public boolean isLeafTypeNode() { - return false; - } - - @Override - public T accept(DisplayableItemNodeVisitor visitor) { - return visitor.visit(this); - } - - @Override - @NbBundle.Messages({ - "ResultsNode.createSheet.name.name=Name", - "ResultsNode.createSheet.name.displayName=Name", - "ResultsNode.createSheet.name.desc=no description"}) - 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<>(Bundle.ResultsNode_createSheet_name_name(), - Bundle.ResultsNode_createSheet_name_displayName(), - Bundle.ResultsNode_createSheet_name_desc(), - NAME - )); - return sheet; - } - - @Override - public String getItemType() { - return getClass().getName(); - } -} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index 192a966490..ed1af75078 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -25,8 +25,6 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardArtifact.Category; import org.sleuthkit.datamodel.SleuthkitVisitableItem; /** @@ -84,12 +82,6 @@ public class RootContentChildren extends Children.Keys { * Set Hits, etc.). */ static class CreateAutopsyNodeVisitor extends AutopsyItemVisitor.Default { - - @Override - public ExtractedContent.RootNode visit(ExtractedContent ec) { - return new ExtractedContent.DataArtifactsNode(0); - } - @Override public AbstractNode visit(FileTypesByExtension sf) { return sf.new FileTypesByExtNode(sf.getSleuthkitCase(), null); @@ -150,11 +142,6 @@ public class RootContentChildren extends Children.Keys { return new ViewsNode(v.getSleuthkitCase(), v.filteringDataSourceObjId()); } - @Override - public AbstractNode visit(Results results) { - return new ResultsNode(results.getSleuthkitCase(), results.filteringDataSourceObjId()); - } - @Override public AbstractNode visit(FileTypes ft) { return ft.new FileTypesNode(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index 2eb2c6e021..e8ec4f42bc 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -69,7 +69,6 @@ import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; -import org.sleuthkit.autopsy.datamodel.ExtractedContent; import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; From 55abf89064fbc2ca3d26dab93fcc45fd7e93c09d Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 30 Apr 2021 14:54:32 -0400 Subject: [PATCH 09/16] cleanup, refactoring, and commenting --- .../{ExtractedContent.java => Artifacts.java} | 184 +++++++++++------- .../datamodel/DisplayableItemNodeVisitor.java | 8 +- .../autopsy/datamodel/EmailExtracted.java | 4 +- .../autopsy/datamodel/HashsetHits.java | 4 +- .../autopsy/datamodel/InterestingHits.java | 4 +- .../autopsy/datamodel/KeywordHits.java | 4 +- .../datamodel/RootContentChildren.java | 4 +- .../autopsy/datamodel/accounts/Accounts.java | 4 +- .../DirectoryTreeTopComponent.java | 4 +- 9 files changed, 137 insertions(+), 83 deletions(-) rename Core/src/org/sleuthkit/autopsy/datamodel/{ExtractedContent.java => Artifacts.java} (81%) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java similarity index 81% rename from Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java rename to Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index ac9435cea0..0becc89c10 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; @@ -61,40 +62,71 @@ import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTER import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; /** - * Parent of the "extracted content" artifacts to be displayed in the tree. - * Other artifacts are displayed under other more specific parents. + * Classes for creating nodes for BlackboardArtifacts. */ -public class ExtractedContent { +public class Artifacts { - private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); + private static final Set INGEST_JOB_EVENTS_OF_INTEREST + = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); + /** + * Parent node of all analysis results. + */ @Messages({ "AnalysisResultsNode_name=Analysis Results",}) - static class AnalysisResultsNode extends RootNode { + static class AnalysisResultsNode extends BaseArtifactNode { + /** + * Main constructor. + * + * @param filteringDSObjId The data source object id for which results + * should be filtered. If no filtering should + * occur, this number should be <= 0. + */ AnalysisResultsNode(long filteringDSObjId) { - super(Children.create(new AnalysisResultsTypeFactory(filteringDSObjId), true), + super(Children.create(new TypeFactory(Category.ANALYSIS_RESULT, filteringDSObjId), true), "org/sleuthkit/autopsy/images/analysis_result.png", Bundle.AnalysisResultsNode_name(), Bundle.AnalysisResultsNode_name()); } } + /** + * Parent node of all data artifacts. + */ @Messages({ "DataArtifactsNode_name=Data Artifacts",}) - static class DataArtifactsNode extends RootNode { + static class DataArtifactsNode extends BaseArtifactNode { + /** + * Main constructor. + * + * @param filteringDSObjId The data source object id for which results + * should be filtered. If no filtering should + * occur, this number should be <= 0. + */ DataArtifactsNode(long filteringDSObjId) { - super(Children.create(new DataArtifactsTypeFactory(filteringDSObjId), true), + super(Children.create(new TypeFactory(Category.DATA_ARTIFACT, filteringDSObjId), true), "org/sleuthkit/autopsy/images/extracted_content.png", Bundle.DataArtifactsNode_name(), Bundle.DataArtifactsNode_name()); } } - static class RootNode extends DisplayableItemNode { + /** + * Base class for a parent node of artifacts. + */ + private static class BaseArtifactNode extends DisplayableItemNode { - RootNode(Children children, String icon, String name, String displayName) { + /** + * Main constructor. + * + * @param children The children of the node. + * @param icon The icon for the node. + * @param name The name identifier of the node. + * @param displayName The display name for the node. + */ + BaseArtifactNode(Children children, String icon, String name, String displayName) { super(children, Lookups.singleton(name)); super.setName(name); super.setDisplayName(displayName); @@ -133,64 +165,87 @@ public class ExtractedContent { } } - private static class AnalysisResultsTypeFactory extends TypeFactory { + /** + * A key to be used with the type factory. + */ + private static class TypeNodeKey { - AnalysisResultsTypeFactory(long filteringDSObjId) { - super(Category.ANALYSIS_RESULT, filteringDSObjId); - } - } - - private static class DataArtifactsTypeFactory extends TypeFactory { - - DataArtifactsTypeFactory(long filteringDSObjId) { - super(Category.DATA_ARTIFACT, filteringDSObjId); - } - } - - private static class TypeNodeRecord { - - private final Node node; - private final Runnable onUpdate; + private final UpdatableCountTypeNode node; private final Set applicableTypes; - TypeNodeRecord(BlackboardArtifact.Type type, long dsObjId) { + /** + * Constructor generating a generic TypeNode for a given artifact type. + * + * @param type The type for the key. + * @param dsObjId The data source object id if filtering should occur. + * If no filtering should occur, this number should be <= + * 0. + */ + TypeNodeKey(BlackboardArtifact.Type type, long dsObjId) { this(new TypeNode(type, dsObjId), type); } - private TypeNodeRecord(UpdatableTypeCountNode typeNode, BlackboardArtifact.Type... types) { - this(typeNode, typeNode::updateDisplayName, types); - } - - TypeNodeRecord(Node node, Runnable onUpdate, BlackboardArtifact.Type... types) { - this.node = node; - this.onUpdate = onUpdate; + /** + * Constructor for any UpdatableCountTypeNode. + * + * @param typeNode The UpdatableCountTypeNode. + * @param types The blackboard artifact types corresponding to this + * node. + */ + TypeNodeKey(UpdatableCountTypeNode typeNode, BlackboardArtifact.Type... types) { + this.node = typeNode; this.applicableTypes = Stream.of(types) .filter(t -> t != null) .collect(Collectors.toSet()); } - Node getNode() { + /** + * Returns the node associated with this key. + * @return The node associated with this key. + */ + UpdatableCountTypeNode getNode() { return node; } - void update() { - if (onUpdate != null) { - onUpdate.run(); - } - } - + /** + * Returns the blackboard artifact types associated with this key. + * @return The blackboard artifact types associated with this key. + */ Set getApplicableTypes() { return applicableTypes; } + @Override + public int hashCode() { + int hash = 3; + hash = 61 * hash + Objects.hashCode(this.applicableTypes); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final TypeNodeKey other = (TypeNodeKey) obj; + if (!Objects.equals(this.applicableTypes, other.applicableTypes)) { + return false; + } + return true; + } + } /** - * 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 static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { + private static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); @@ -205,35 +260,36 @@ public class ExtractedContent { new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) ); - private static TypeNodeRecord getRecord(BlackboardArtifact.Type type, SleuthkitCase skCase, long dsObjId) { + + private static TypeNodeKey getRecord(BlackboardArtifact.Type type, SleuthkitCase skCase, long dsObjId) { int typeId = type.getTypeID(); if (TSK_EMAIL_MSG.getTypeID() == typeId) { EmailExtracted.RootNode emailNode = new EmailExtracted(skCase, dsObjId).new RootNode(); - return new TypeNodeRecord(emailNode, new BlackboardArtifact.Type(TSK_EMAIL_MSG)); + return new TypeNodeKey(emailNode, new BlackboardArtifact.Type(TSK_EMAIL_MSG)); } else if (TSK_ACCOUNT.getTypeID() == typeId) { Accounts.AccountsRootNode accountsNode = new Accounts(skCase, dsObjId).new AccountsRootNode(); - return new TypeNodeRecord(accountsNode, new BlackboardArtifact.Type(TSK_ACCOUNT)); + return new TypeNodeKey(accountsNode, new BlackboardArtifact.Type(TSK_ACCOUNT)); } else if (TSK_KEYWORD_HIT.getTypeID() == typeId) { KeywordHits.RootNode keywordsNode = new KeywordHits(skCase, dsObjId).new RootNode(); - return new TypeNodeRecord(keywordsNode, new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); + return new TypeNodeKey(keywordsNode, new BlackboardArtifact.Type(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 TypeNodeRecord(interestingHitsNode, + return new TypeNodeKey(interestingHitsNode, new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT)); } else { - return new TypeNodeRecord(type, dsObjId); + return new TypeNodeKey(type, dsObjId); } } // maps the artifact type to its child node - private final HashMap typeNodeMap = new HashMap<>(); + private final HashMap typeNodeMap = new HashMap<>(); private final long filteringDSObjId; /** @@ -292,7 +348,7 @@ public class ExtractedContent { } @Override - protected boolean createKeys(List list) { + protected boolean createKeys(List list) { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); @@ -300,15 +356,15 @@ public class ExtractedContent { ? skCase.getBlackboard().getArtifactTypesInUse(this.filteringDSObjId) : skCase.getArtifactTypesInUse(); - List allKeysSorted = types.stream() + List allKeysSorted = types.stream() .filter(tp -> category.equals(tp.getCategory()) && !IGNORED_TYPES.contains(tp)) .map(tp -> { if (typeNodeMap.containsKey(tp)) { - TypeNodeRecord record = typeNodeMap.get(tp); - record.update(); + TypeNodeKey record = typeNodeMap.get(tp); + record.getNode().updateDisplayName(); return record; } else { - TypeNodeRecord newRecord = getRecord(tp, skCase, filteringDSObjId); + TypeNodeKey newRecord = getRecord(tp, skCase, filteringDSObjId); for (BlackboardArtifact.Type recordType : newRecord.getApplicableTypes()) { typeNodeMap.put(recordType, newRecord); } @@ -324,8 +380,6 @@ public class ExtractedContent { }) .collect(Collectors.toList()); - allKeysSorted.forEach(record -> record.update()); - list.addAll(allKeysSorted); } catch (NoCurrentCaseException ex) { @@ -337,7 +391,7 @@ public class ExtractedContent { } @Override - protected Node createNodeForKey(TypeNodeRecord key) { + protected Node createNodeForKey(TypeNodeKey key) { return key.getNode(); } @@ -377,9 +431,9 @@ public class ExtractedContent { } } - public static abstract class UpdatableTypeCountNode extends DisplayableItemNode { + public static abstract class UpdatableCountTypeNode extends DisplayableItemNode { - private static final Logger logger = Logger.getLogger(UpdatableTypeCountNode.class.getName()); + private static final Logger logger = Logger.getLogger(UpdatableCountTypeNode.class.getName()); private final Set types; private final long filteringDSObjId; @@ -397,7 +451,7 @@ public class ExtractedContent { * @param children The Children object for the node. * @param lookup The Lookup object for the node. */ - public UpdatableTypeCountNode(Children children, Lookup lookup, String baseName, long filteringDSObjId, BlackboardArtifact.Type... types) { + public UpdatableCountTypeNode(Children children, Lookup lookup, String baseName, long filteringDSObjId, BlackboardArtifact.Type... types) { super(children, lookup); this.types = Stream.of(types).collect(Collectors.toSet()); this.filteringDSObjId = filteringDSObjId; @@ -438,7 +492,7 @@ public class ExtractedContent { * the artifacts of a given type. Its children will be * BlackboardArtifactNode objects. */ - public static class TypeNode extends UpdatableTypeCountNode { + public static class TypeNode extends UpdatableCountTypeNode { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 4cdb32ff2c..715f9aecd9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -90,9 +90,9 @@ public interface DisplayableItemNodeVisitor { T visit(BlackboardArtifactNode ban); - T visit(ExtractedContent.TypeNode atn); + T visit(Artifacts.TypeNode atn); - T visit(ExtractedContent.RootNode ecn); + T visit(Artifacts.BaseArtifactNode ecn); T visit(KeywordHits.RootNode khrn); @@ -296,12 +296,12 @@ public interface DisplayableItemNodeVisitor { } @Override - public T visit(ExtractedContent.TypeNode atn) { + public T visit(Artifacts.TypeNode atn) { return defaultVisit(atn); } @Override - public T visit(ExtractedContent.RootNode ecn) { + public T visit(Artifacts.BaseArtifactNode ecn) { return defaultVisit(ecn); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index d042573e53..06ed408976 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -49,7 +49,7 @@ 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.ExtractedContent.UpdatableTypeCountNode; +import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; /** * Support for TSK_EMAIL_MSG nodes and displaying emails in the directory tree. @@ -203,7 +203,7 @@ public class EmailExtracted implements AutopsyVisitableItem { * Mail root node grouping all mail accounts, supports account-> folder * structure */ - public class RootNode extends UpdatableTypeCountNode { + public class RootNode extends UpdatableCountTypeNode { public RootNode() { super(Children.create(new AccountFactory(), true), diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index 7a04d3cf33..150a52e3da 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -52,7 +52,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; +import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; /** * Hash set hits node support. Inner classes have all of the nodes in the tree. @@ -170,7 +170,7 @@ public class HashsetHits implements AutopsyVisitableItem { /** * Top-level node for all hash sets */ - public class RootNode extends UpdatableTypeCountNode { + public class RootNode extends UpdatableCountTypeNode { public RootNode() { super(Children.create(new HashsetNameFactory(), true), diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 27d08f3781..28bfb3e8dc 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -50,7 +50,7 @@ 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.ExtractedContent.UpdatableTypeCountNode; +import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; public class InterestingHits implements AutopsyVisitableItem { @@ -166,7 +166,7 @@ public class InterestingHits implements AutopsyVisitableItem { /** * Node for the interesting items */ - public class RootNode extends UpdatableTypeCountNode { + public class RootNode extends UpdatableCountTypeNode { public RootNode() { super(Children.create(new SetNameFactory(), true), diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 6713a6722b..845c87d5ea 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -56,7 +56,7 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; -import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; +import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; /** * Keyword hits node support @@ -377,7 +377,7 @@ public class KeywordHits implements AutopsyVisitableItem { } // Created by CreateAutopsyNodeVisitor - public class RootNode extends UpdatableTypeCountNode { + public class RootNode extends UpdatableCountTypeNode { public RootNode() { super(Children.create(new ListFactory(), true), diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index ed1af75078..acb33129dd 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -196,13 +196,13 @@ public class RootContentChildren extends Children.Keys { @Override public AbstractNode visit(AnalysisResults analysisResults) { - return new ExtractedContent.AnalysisResultsNode( + return new Artifacts.AnalysisResultsNode( analysisResults.getFilteringDataSourceObjId()); } @Override public AbstractNode visit(DataArtifacts dataArtifacts) { - return new ExtractedContent.DataArtifactsNode( + return new Artifacts.DataArtifactsNode( dataArtifacts.getFilteringDataSourceObjId()); } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index e8ec4f42bc..aa6a53f8ec 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -69,7 +69,7 @@ import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; -import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; +import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -235,7 +235,7 @@ final public class Accounts implements AutopsyVisitableItem { * Top-level node for the accounts tree */ @NbBundle.Messages({"Accounts.RootNode.displayName=Accounts"}) - final public class AccountsRootNode extends UpdatableTypeCountNode { + final public class AccountsRootNode extends UpdatableCountTypeNode { public AccountsRootNode() { super(Children.create(new AccountTypeFactory(), true), diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index d2cd291de0..90245dfe4e 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -78,7 +78,7 @@ import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.EmailExtracted; import org.sleuthkit.autopsy.datamodel.EmptyNode; -import org.sleuthkit.autopsy.datamodel.ExtractedContent; +import org.sleuthkit.autopsy.datamodel.Artifacts; import org.sleuthkit.autopsy.datamodel.FileTypesByMimeType; import org.sleuthkit.autopsy.datamodel.InterestingHits; import org.sleuthkit.autopsy.datamodel.KeywordHits; @@ -1391,7 +1391,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS } } else { - Node extractedContent = resultsChilds.findChild(ExtractedContent.NAME); + Node extractedContent = resultsChilds.findChild(Artifacts.NAME); Children extractedChilds = extractedContent.getChildren(); if (extractedChilds == null) { return; From b566201f9123d3effcd9311acb6c3f16fa60d290 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 3 May 2021 08:37:10 -0400 Subject: [PATCH 10/16] commenting --- .../autopsy/datamodel/Artifacts.java | 103 +++++++++++++----- 1 file changed, 75 insertions(+), 28 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index 0becc89c10..fcea81513d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.logging.Level; @@ -81,7 +82,8 @@ public class Artifacts { * * @param filteringDSObjId The data source object id for which results * should be filtered. If no filtering should - * occur, this number should be <= 0. + * occur, this number should be less than or + * equal to 0. */ AnalysisResultsNode(long filteringDSObjId) { super(Children.create(new TypeFactory(Category.ANALYSIS_RESULT, filteringDSObjId), true), @@ -103,7 +105,8 @@ public class Artifacts { * * @param filteringDSObjId The data source object id for which results * should be filtered. If no filtering should - * occur, this number should be <= 0. + * occur, this number should be less than or + * equal to 0. */ DataArtifactsNode(long filteringDSObjId) { super(Children.create(new TypeFactory(Category.DATA_ARTIFACT, filteringDSObjId), true), @@ -178,8 +181,8 @@ public class Artifacts { * * @param type The type for the key. * @param dsObjId The data source object id if filtering should occur. - * If no filtering should occur, this number should be <= - * 0. + * If no filtering should occur, this number should be + * less than or equal to 0. */ TypeNodeKey(BlackboardArtifact.Type type, long dsObjId) { this(new TypeNode(type, dsObjId), type); @@ -201,6 +204,7 @@ public class Artifacts { /** * Returns the node associated with this key. + * * @return The node associated with this key. */ UpdatableCountTypeNode getNode() { @@ -209,6 +213,7 @@ public class Artifacts { /** * Returns the blackboard artifact types associated with this key. + * * @return The blackboard artifact types associated with this key. */ Set getApplicableTypes() { @@ -243,12 +248,16 @@ public class Artifacts { } /** - * + * Factory for showing a list of artifact types (i.e. all the data artifact + * types). */ private static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); + /** + * Types that should not be shown in the tree. + */ @SuppressWarnings("deprecation") private static final Set IGNORED_TYPES = Sets.newHashSet( // these are shown in other parts of the UI (and different node types) @@ -260,8 +269,18 @@ public class Artifacts { new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) ); - - private static TypeNodeKey getRecord(BlackboardArtifact.Type type, SleuthkitCase skCase, long dsObjId) { + /** + * Returns a Children key to be use for a particular artifact type. + * + * @param type The artifact type. + * @param skCase The relevant Sleuthkit case in order to create the + * node. + * @param dsObjId The data source object id to use for filtering. If id + * is less than or equal to 0, no filtering will occur. + * + * @return The generated key. + */ + private static TypeNodeKey getTypeKey(BlackboardArtifact.Type type, SleuthkitCase skCase, long dsObjId) { int typeId = type.getTypeID(); if (TSK_EMAIL_MSG.getTypeID() == typeId) { EmailExtracted.RootNode emailNode = new EmailExtracted(skCase, dsObjId).new RootNode(); @@ -289,7 +308,7 @@ public class Artifacts { } // maps the artifact type to its child node - private final HashMap typeNodeMap = new HashMap<>(); + private final Map typeNodeMap = new HashMap<>(); private final long filteringDSObjId; /** @@ -300,7 +319,14 @@ public class Artifacts { private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); private final Category category; - @SuppressWarnings("deprecation") + /** + * Main constructor. + * + * @param category The category of types to be displayed. + * @param filteringDSObjId The data source object id to use for + * filtering. If id is less than or equal to 0, + * no filtering will occur. + */ TypeFactory(Category category, long filteringDSObjId) { super(); this.filteringDSObjId = filteringDSObjId; @@ -350,29 +376,36 @@ public class Artifacts { @Override protected boolean createKeys(List list) { try { - + // Get all types in use SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); List types = (this.filteringDSObjId > 0) ? skCase.getBlackboard().getArtifactTypesInUse(this.filteringDSObjId) : skCase.getArtifactTypesInUse(); List allKeysSorted = types.stream() + // filter types by category and ensure they are not in the list of ignored types .filter(tp -> category.equals(tp.getCategory()) && !IGNORED_TYPES.contains(tp)) .map(tp -> { + // if typeNodeMap already contains key, update the relevant node and return the node if (typeNodeMap.containsKey(tp)) { - TypeNodeKey record = typeNodeMap.get(tp); - record.getNode().updateDisplayName(); - return record; + TypeNodeKey typeKey = typeNodeMap.get(tp); + typeKey.getNode().updateDisplayName(); + return typeKey; } else { - TypeNodeKey newRecord = getRecord(tp, skCase, filteringDSObjId); - for (BlackboardArtifact.Type recordType : newRecord.getApplicableTypes()) { - typeNodeMap.put(recordType, newRecord); + // if key is not in map, create the type key and add to map + TypeNodeKey newTypeKey = getTypeKey(tp, skCase, filteringDSObjId); + for (BlackboardArtifact.Type recordType : newTypeKey.getApplicableTypes()) { + typeNodeMap.put(recordType, newTypeKey); } - return newRecord; + return newTypeKey; } }) + // ensure record is returned .filter(record -> record != null) + // there are potentially multiple types that apply to the same node (i.e. Interesting Files / Artifacts) + // ensure the keys are distinct .distinct() + // sort by display name .sorted((a, b) -> { String aSafe = (a.getNode() == null || a.getNode().getDisplayName() == null) ? "" : a.getNode().getDisplayName(); String bSafe = (b.getNode() == null || b.getNode().getDisplayName() == null) ? "" : b.getNode().getDisplayName(); @@ -431,6 +464,10 @@ public class Artifacts { } } + /** + * Abstract class for type(s) nodes. This class allows for displaying a + * count artifacts with the type(s) associated with this node. + */ public static abstract class UpdatableCountTypeNode extends DisplayableItemNode { private static final Logger logger = Logger.getLogger(UpdatableCountTypeNode.class.getName()); @@ -441,17 +478,20 @@ public class Artifacts { private final String baseName; /** - * Constructs a node that is eligible for display in the tree view or - * results view. Capabilitites include accepting a - * DisplayableItemNodeVisitor, indicating whether or not the node is a - * leaf node, providing an item type string suitable for use as a key, - * and storing information about a child node that is to be selected if - * the node is selected in the tree view. + * Main constructor. * - * @param children The Children object for the node. - * @param lookup The Lookup object for the node. + * @param children The Children to associated with this node. + * @param lookup The Lookup to use with this name. + * @param baseName The display name. The Node.displayName will + * be of format "[baseName] ([count])". + * @param filteringDSObjId The data source object id to use for + * filtering. If id is less than or equal to 0, + * no filtering will occur. + * @param types The types associated with this type node. */ - public UpdatableCountTypeNode(Children children, Lookup lookup, String baseName, long filteringDSObjId, BlackboardArtifact.Type... types) { + public UpdatableCountTypeNode(Children children, Lookup lookup, String baseName, + long filteringDSObjId, BlackboardArtifact.Type... types) { + super(children, lookup); this.types = Stream.of(types).collect(Collectors.toSet()); this.filteringDSObjId = filteringDSObjId; @@ -459,10 +499,19 @@ public class Artifacts { updateDisplayName(); } + /** + * Returns the count of artifacts associated with these type(s). + * + * @return The count of artifacts associated with these type(s). + */ protected long getChildCount() { return this.childCount; } + /** + * When this method is called, the count to be displayed will be + * updated. + */ void updateDisplayName() { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); @@ -494,8 +543,6 @@ public class Artifacts { */ public static class TypeNode extends UpdatableCountTypeNode { - private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); - private final BlackboardArtifact.Type type; TypeNode(BlackboardArtifact.Type type, long filteringDSObjId) { From 8cd287e3ddfc8b4cf0d363cf7725fdd8b500815c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 3 May 2021 09:07:05 -0400 Subject: [PATCH 11/16] commenting --- .../autopsy/datamodel/Artifacts.java | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index fcea81513d..bdb88dfbf2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -536,15 +536,23 @@ public class Artifacts { } /** - * 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 + * Default node encapsulating a 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 static class TypeNode extends UpdatableCountTypeNode { private final BlackboardArtifact.Type type; + /** + * Main constructor. + * + * @param type The blackboard artifact type for this node. + * @param filteringDSObjId The data source object id to use for + * filtering. If id is less than or equal to 0, + * no filtering will occur. + */ TypeNode(BlackboardArtifact.Type type, long filteringDSObjId) { super(Children.create(new ArtifactFactory(type, filteringDSObjId), true), Lookups.singleton(type.getDisplayName()), @@ -612,6 +620,14 @@ public class Artifacts { private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); private final long filteringDSObjId; + /** + * Main constructor. + * + * @param type The blackboard artifact type for this node. + * @param filteringDSObjId The data source object id to use for + * filtering. If id is less than or equal to 0, + * no filtering will occur. + */ ArtifactFactory(BlackboardArtifact.Type type, long filteringDSObjId) { super(type.getTypeName()); this.type = type; From 2c2a731341f0755515d2a04fa415d6496e142811 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 3 May 2021 13:01:21 -0400 Subject: [PATCH 12/16] worked through changes in tree for DirectoryTreeTopComponent --- .../autopsy/datamodel/AnalysisResults.java | 36 + .../autopsy/datamodel/Artifacts.java | 53 +- .../autopsy/datamodel/DataArtifacts.java | 36 + .../datamodel/RootContentChildren.java | 5 +- .../DirectoryTreeTopComponent.java | 642 +++++++++++------- 5 files changed, 470 insertions(+), 302 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java index b0f038ba4a..fc51d97cc9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java @@ -18,11 +18,47 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.openide.nodes.Children; +import org.openide.util.NbBundle; +import org.sleuthkit.datamodel.BlackboardArtifact; + /** * Analysis Results node support. */ +@NbBundle.Messages({ + "AnalysisResults_name=Analysis Results",}) public class AnalysisResults implements AutopsyVisitableItem { + /** + * Returns the name of this node that is the key in the children object. + * + * @return The name of this node that is the key in the children object. + */ + public static String getName() { + return Bundle.AnalysisResults_name(); + } + + /** + * Parent node of all analysis results. + */ + static class RootNode extends Artifacts.BaseArtifactNode { + + /** + * Main constructor. + * + * @param filteringDSObjId The data source object id for which results + * should be filtered. If no filtering should + * occur, this number should be less than or + * equal to 0. + */ + RootNode(long filteringDSObjId) { + super(Children.create(new Artifacts.TypeFactory(BlackboardArtifact.Category.ANALYSIS_RESULT, filteringDSObjId), true), + "org/sleuthkit/autopsy/images/analysis_result.png", + AnalysisResults.getName(), + AnalysisResults.getName()); + } + } + private final long datasourceObjId; /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index bdb88dfbf2..2bce9cdc95 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -70,56 +70,11 @@ public class Artifacts { private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); - /** - * Parent node of all analysis results. - */ - @Messages({ - "AnalysisResultsNode_name=Analysis Results",}) - static class AnalysisResultsNode extends BaseArtifactNode { - - /** - * Main constructor. - * - * @param filteringDSObjId The data source object id for which results - * should be filtered. If no filtering should - * occur, this number should be less than or - * equal to 0. - */ - AnalysisResultsNode(long filteringDSObjId) { - super(Children.create(new TypeFactory(Category.ANALYSIS_RESULT, filteringDSObjId), true), - "org/sleuthkit/autopsy/images/analysis_result.png", - Bundle.AnalysisResultsNode_name(), - Bundle.AnalysisResultsNode_name()); - } - } - - /** - * Parent node of all data artifacts. - */ - @Messages({ - "DataArtifactsNode_name=Data Artifacts",}) - static class DataArtifactsNode extends BaseArtifactNode { - - /** - * Main constructor. - * - * @param filteringDSObjId The data source object id for which results - * should be filtered. If no filtering should - * occur, this number should be less than or - * equal to 0. - */ - DataArtifactsNode(long filteringDSObjId) { - super(Children.create(new TypeFactory(Category.DATA_ARTIFACT, filteringDSObjId), true), - "org/sleuthkit/autopsy/images/extracted_content.png", - Bundle.DataArtifactsNode_name(), - Bundle.DataArtifactsNode_name()); - } - } - + /** * Base class for a parent node of artifacts. */ - private static class BaseArtifactNode extends DisplayableItemNode { + static class BaseArtifactNode extends DisplayableItemNode { /** * Main constructor. @@ -251,7 +206,7 @@ public class Artifacts { * Factory for showing a list of artifact types (i.e. all the data artifact * types). */ - private static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { + static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); @@ -541,7 +496,7 @@ public class Artifacts { * all of the artifacts of a given type. Its children will be * BlackboardArtifactNode objects. */ - public static class TypeNode extends UpdatableCountTypeNode { + static class TypeNode extends UpdatableCountTypeNode { private final BlackboardArtifact.Type type; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java index 2c52278459..54e9e5da0a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java @@ -18,11 +18,47 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.openide.nodes.Children; +import org.openide.util.NbBundle; +import org.sleuthkit.datamodel.BlackboardArtifact; + /** * Analysis Results node support. */ +@NbBundle.Messages({ + "DataArtifacts_name=Data Artifacts",}) public class DataArtifacts implements AutopsyVisitableItem { + /** + * Returns the name of this node that is the key in the children object. + * + * @return The name of this node that is the key in the children object. + */ + public static String getName() { + return Bundle.DataArtifacts_name(); + } + + /** + * Parent node of all data artifacts. + */ + static class RootNode extends Artifacts.BaseArtifactNode { + + /** + * Main constructor. + * + * @param filteringDSObjId The data source object id for which results + * should be filtered. If no filtering should + * occur, this number should be less than or + * equal to 0. + */ + RootNode(long filteringDSObjId) { + super(Children.create(new Artifacts.TypeFactory(BlackboardArtifact.Category.DATA_ARTIFACT, filteringDSObjId), true), + "org/sleuthkit/autopsy/images/extracted_content.png", + DataArtifacts.getName(), + DataArtifacts.getName()); + } + } + private final long datasourceObjId; /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index acb33129dd..24d077b5fa 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -82,6 +82,7 @@ public class RootContentChildren extends Children.Keys { * Set Hits, etc.). */ static class CreateAutopsyNodeVisitor extends AutopsyItemVisitor.Default { + @Override public AbstractNode visit(FileTypesByExtension sf) { return sf.new FileTypesByExtNode(sf.getSleuthkitCase(), null); @@ -196,13 +197,13 @@ public class RootContentChildren extends Children.Keys { @Override public AbstractNode visit(AnalysisResults analysisResults) { - return new Artifacts.AnalysisResultsNode( + return new AnalysisResults.RootNode( analysisResults.getFilteringDataSourceObjId()); } @Override public AbstractNode visit(DataArtifacts dataArtifacts) { - return new Artifacts.DataArtifactsNode( + return new DataArtifacts.RootNode( dataArtifacts.getFilteringDataSourceObjId()); } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 90245dfe4e..6d90e9b821 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -32,6 +32,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.prefs.PreferenceChangeEvent; @@ -72,18 +73,18 @@ import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.corecomponents.ViewPreferencesPanel; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.datamodel.AnalysisResults; import org.sleuthkit.autopsy.datamodel.ArtifactNodeSelectionInfo; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.EmailExtracted; import org.sleuthkit.autopsy.datamodel.EmptyNode; -import org.sleuthkit.autopsy.datamodel.Artifacts; import org.sleuthkit.autopsy.datamodel.FileTypesByMimeType; import org.sleuthkit.autopsy.datamodel.InterestingHits; import org.sleuthkit.autopsy.datamodel.KeywordHits; -import org.sleuthkit.autopsy.datamodel.ResultsNode; import org.sleuthkit.autopsy.datamodel.AutopsyTreeChildFactory; +import org.sleuthkit.autopsy.datamodel.DataArtifacts; import org.sleuthkit.autopsy.datamodel.PersonGroupingNode; import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.autopsy.datamodel.ViewsNode; @@ -91,6 +92,7 @@ import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.autopsy.datamodel.accounts.BINRange; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardArtifact.Category; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DataSource; @@ -199,19 +201,21 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat */ private void preExpandNodes(Children rootChildren) { BeanTreeView tree = getTree(); + for (String categoryKey : new String[]{AnalysisResults.getName(), DataArtifacts.getName()}) { + Node categoryNode = rootChildren.findChild(categoryKey); - Node results = rootChildren.findChild(ResultsNode.getNameIdentifier()); - if (!Objects.isNull(results)) { - tree.expandNode(results); - Children resultsChildren = results.getChildren(); - Arrays.stream(resultsChildren.getNodes()).forEach(tree::expandNode); + if (!Objects.isNull(categoryNode)) { + tree.expandNode(categoryNode); + Children resultsChildren = categoryNode.getChildren(); + Arrays.stream(resultsChildren.getNodes()).forEach(tree::expandNode); + } } Node views = rootChildren.findChild(ViewsNode.NAME); if (!Objects.isNull(views)) { tree.expandNode(views); } - + // expand all nodes parents of and including hosts if group by host/person if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { Node[] rootNodes = rootChildren.getNodes(); @@ -223,11 +227,13 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } } } - - + /** - * Returns all nodes including provided node that are parents of or are hosts. + * Returns all nodes including provided node that are parents of or are + * hosts. + * * @param node The parent or possible host node. + * * @return The descendant host nodes. */ private List getHostNodesAndParents(Node node) { @@ -307,7 +313,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * Setter to determine if rejected results should be shown or not. * * @param showRejectedResults True if showing rejected results; otherwise - * false. + * false. */ public void setShowRejectedResults(boolean showRejectedResults) { this.showRejectedResults = showRejectedResults; @@ -1054,7 +1060,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * Set the selected node using a path to a previously selected node. * * @param previouslySelectedNodePath Path to a previously selected node. - * @param rootNodeName Name of the root node to match, may be null. + * @param rootNodeName Name of the root node to match, may be + * null. */ private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) { if (previouslySelectedNodePath == null) { @@ -1112,53 +1119,82 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } /** - * Does dfs search of node while nodes are Host, Person, or - * DataSourcesByType looking for the Results Node. + * Returns the node matching the given category that is an immediate child + * of the provided Children object or empty if no immediate child matches + * the given category. * - * @param node The node. - * @param dataSourceId The data source id. - * @return The child nodes that are at the data source level. + * @param children The children to search. + * @param category The category to find. + * + * @return The node matching the given category */ - private Node getResultsNodeSearch(Node node, long dataSourceId) { - if (node == null) { - return null; - } else if (node.getLookup().lookup(Host.class) != null - || node.getLookup().lookup(Person.class) != null - || PersonGroupingNode.getUnknownPersonId().equals(node.getLookup().lookup(String.class))) { - Children children = node.getChildren(); - Node[] childNodes = children == null ? null : children.getNodes(); - if (childNodes != null) { - for (Node child : childNodes) { - Node foundExtracted = getResultsNodeSearch(child, dataSourceId); - if (foundExtracted != null) { - return foundExtracted; - } - } - } - } else { - DataSource dataSource = node.getLookup().lookup(DataSource.class); - if (dataSource != null && dataSource.getId() == dataSourceId) { - Children dsChildren = node.getChildren(); - if (dsChildren != null) { - return dsChildren.findChild(ResultsNode.getNameIdentifier()); - } - } + private Optional getCategoryNodeChild(Children children, Category category) { + switch (category) { + case DATA_ARTIFACT: + return Optional.ofNullable(children.findChild(DataArtifacts.getName())); + case ANALYSIS_RESULT: + return Optional.ofNullable(children.findChild(AnalysisResults.getName())); + default: + LOGGER.log(Level.WARNING, "Unbale to find category of type: " + category.name()); + return Optional.empty(); } - return null; } /** - * Finds the results node for the specific artifact. + * Does depth first search of node while nodes are Host, Person, or + * DataSourcesByType looking for the appropriate category Node (i.e. the + * Data Artifacts or Analysis Results nodes). * - * @param art The artifact to find the relevant Results Node. - * @return THe Results Node or null. + * @param node The node. + * @param dataSourceId The data source id. + * @param category The artifact type category. + * + * @return The child nodes that are at the data source level. */ - private Node getResultsNode(final BlackboardArtifact art) { - Children rootChilds = em.getRootContext().getChildren(); + private Optional searchForCategoryNode(Node node, long dataSourceId, Category category) { + if (node == null) { + // if no node, no result + return Optional.empty(); + } else if (node.getLookup().lookup(Host.class) != null + || node.getLookup().lookup(Person.class) != null + || PersonGroupingNode.getUnknownPersonId().equals(node.getLookup().lookup(String.class))) { + // if host or person node, recurse until we find correct data source node. + Children children = node.getChildren(); - Node resultsNode = rootChilds.findChild(ResultsNode.getNameIdentifier()); - if (resultsNode != null) { - return resultsNode; + Stream childNodeStream = children == null ? Stream.empty() : Stream.of(children.getNodes()); + return childNodeStream + .map(childNode -> searchForCategoryNode(childNode, dataSourceId, category)) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst(); + } else { + DataSource dataSource = node.getLookup().lookup(DataSource.class); + // if data source node and the one we want, find the right category node. + if (dataSource != null && dataSource.getId() == dataSourceId) { + Children dsChildren = node.getChildren(); + if (dsChildren != null) { + return getCategoryNodeChild(dsChildren, category); + } + } + + return Optional.empty(); + } + } + + /** + * Finds the category node (i.e. Data Artifacts / Analysis Results) for the + * specific artifact and category. + * + * @param category The category of the artifact. + * @param art The artifact to find the relevant Results Node. + * + * @return The category node or empty. + */ + private Optional getCategoryNode(Category category, BlackboardArtifact art) { + Children rootChildren = em.getRootContext().getChildren(); + Optional categoryNode = getCategoryNodeChild(rootChildren, category); + if (categoryNode.isPresent()) { + return categoryNode; } long dataSourceId; @@ -1169,17 +1205,31 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat return null; } - Node[] rootNodes = rootChilds.getNodes(); - if (rootNodes != null) { - for (Node rootNode : rootNodes) { - resultsNode = getResultsNodeSearch(rootNode, dataSourceId); - if (resultsNode != null) { - return resultsNode; - } - } - } + Node[] rootNodes = rootChildren.getNodes(); + Stream rootNodesStream = rootNodes == null ? Stream.empty() : Stream.of(rootNodes); + return rootNodesStream + .map((rootNode) -> searchForCategoryNode(rootNode, dataSourceId, category)) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst(); + } - return null; + /** + * Attempts to retrieve the artifact type for the given artifact type id. + * + * @param artifactTypeId The artifact type id. + * + * @return The artifact type if present or empty if not found. + */ + private Optional getType(long artifactTypeId) { + try { + return Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse().stream() + .filter(type -> type.getTypeID() == artifactTypeId) + .findFirst(); + } catch (NoCurrentCaseException | TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error occurred while looking up blackboard artifact type for: " + artifactTypeId, ex); + return Optional.empty(); + } } /** @@ -1196,207 +1246,34 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat public void viewArtifact(final BlackboardArtifact art) { int typeID = art.getArtifactTypeID(); String typeName = art.getArtifactTypeName(); - Node treeNode = null; - Node resultsNode = getResultsNode(art); - if (resultsNode == null) { + Optional typeOpt = getType(typeID); + Optional categoryChildrenOpt = typeOpt + .flatMap(type -> getCategoryNode(type.getCategory(), art)) + .flatMap(categoryNode -> Optional.ofNullable(categoryNode.getChildren())); + + if (!categoryChildrenOpt.isPresent()) { + LOGGER.log(Level.WARNING, String.format("Category node children for artifact of typeID: %d and artifactID: %d not found.", + typeID, art.getArtifactID())); return; } - Children resultsChilds = resultsNode.getChildren(); + Children typesChildren = categoryChildrenOpt.get(); + + Node treeNode = null; if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { - Node hashsetRootNode = resultsChilds.findChild(typeName); - Children hashsetRootChilds = hashsetRootNode.getChildren(); - 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(); - } - } - treeNode = hashsetRootChilds.findChild(setName); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS - } + treeNode = getHashsetNode(typesChildren, art); } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - Node keywordRootNode = resultsChilds.findChild(typeName); - Children keywordRootChilds = keywordRootNode.getChildren(); - try { - String listName = null; - String keywordName = null; - String regex = null; - List attributes = art.getAttributes(); - for (BlackboardAttribute att : attributes) { - int typeId = att.getAttributeType().getTypeID(); - if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { - listName = att.getValueString(); - } else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) { - keywordName = att.getValueString(); - } else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()) { - regex = att.getValueString(); - } - } - if (listName == null) { - if (regex == null) { //using same labels used for creation - listName = NbBundle.getMessage(KeywordHits.class, "KeywordHits.simpleLiteralSearch.text"); - } else { - listName = NbBundle.getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text"); - } - } - Node listNode = keywordRootChilds.findChild(listName); - if (listNode == null) { - return; - } - Children listChildren = listNode.getChildren(); - if (listChildren == null) { - return; - } - if (regex != null) { //For support of regex nodes such as URLs, IPs, Phone Numbers, and Email Addrs as they are down another level - Node regexNode = listChildren.findChild(regex); - if (regexNode == null) { - return; - } - listChildren = regexNode.getChildren(); - if (listChildren == null) { - return; - } - } - - treeNode = listChildren.findChild(keywordName); - - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS - } + treeNode = getKeywordHitNode(typesChildren, art); } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() || typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { - Node interestingItemsRootNode = resultsChilds.findChild(NbBundle - .getMessage(InterestingHits.class, "InterestingHits.interestingItems.text")); - Children interestingItemsRootChildren = interestingItemsRootNode.getChildren(); - 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; - } - - Children fileArtifactChildren = setNode.getChildren(); - Node[] fileArtifactNodes = fileArtifactChildren == null ? null : fileArtifactChildren.getNodes(); - if (fileArtifactNodes == null || fileArtifactNodes.length != 2) { - return; - } - - treeNode = (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()) - ? fileArtifactNodes[0] - : fileArtifactNodes[1]; - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS - } + treeNode = getInterestingItemNode(typesChildren, art); } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) { - Node emailMsgRootNode = resultsChilds.findChild(typeName); - Children emailMsgRootChilds = emailMsgRootNode.getChildren(); - Map parsedPath = null; - try { - List attributes = art.getAttributes(); - for (BlackboardAttribute att : attributes) { - int typeId = att.getAttributeType().getTypeID(); - if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID()) { - parsedPath = EmailExtracted.parsePath(att.getValueString()); - break; - } - } - if (parsedPath == null) { - return; - } - Node defaultNode = emailMsgRootChilds.findChild(parsedPath.get(NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text"))); - Children defaultChildren = defaultNode.getChildren(); - treeNode = defaultChildren.findChild(parsedPath.get(NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text"))); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS - } - + treeNode = getEmailNode(typesChildren, art); } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { - Node accountRootNode = resultsChilds.findChild(art.getDisplayName()); - Children accountRootChilds = accountRootNode.getChildren(); - List attributes; - String accountType = null; - String ccNumberName = null; - try { - attributes = art.getAttributes(); - for (BlackboardAttribute att : attributes) { - int typeId = att.getAttributeType().getTypeID(); - if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()) { - accountType = att.getValueString(); - } - if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID()) { - ccNumberName = att.getValueString(); - } - } - if (accountType == null) { - return; - } - - if (accountType.equals(Account.Type.CREDIT_CARD.getTypeName())) { - Node accountNode = accountRootChilds.findChild(Account.Type.CREDIT_CARD.getDisplayName()); - if (accountNode == null) { - return; - } - Children accountChildren = accountNode.getChildren(); - if (accountChildren == null) { - return; - } - Node binNode = accountChildren.findChild(NbBundle.getMessage(Accounts.class, "Accounts.ByBINNode.name")); - if (binNode == null) { - return; - } - Children binChildren = binNode.getChildren(); - if (ccNumberName == null) { - return; - } - //right padded with 0s to 8 digits when single number - //when a range of numbers, the first 6 digits are rightpadded with 0s to 8 digits then a dash then 3 digits, the 6,7,8, digits of the end number right padded with 9s - String binName = StringUtils.rightPad(ccNumberName, 8, "0"); - binName = binName.substring(0, 8); - int bin; - try { - bin = Integer.parseInt(binName); - } catch (NumberFormatException ex) { - LOGGER.log(Level.WARNING, "Unable to parseInt a BIN for node selection from string binName=" + binName, ex); //NON-NLS - return; - } - CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin); - if (binInfo != null) { - int startBin = ((BINRange) binInfo).getBINstart(); - int endBin = ((BINRange) binInfo).getBINend(); - if (startBin != endBin) { - binName = Integer.toString(startBin) + "-" + Integer.toString(endBin).substring(5); //if there is a range re-construct the name it appears as - } - } - if (binName == null) { - return; - } - treeNode = binChildren.findChild(binName); - } else { //default account type - treeNode = accountRootChilds.findChild(accountType); - } - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS - } + treeNode = getAccountNode(typesChildren, art); } else { - Node extractedContent = resultsChilds.findChild(Artifacts.NAME); - Children extractedChilds = extractedContent.getChildren(); - if (extractedChilds == null) { - return; - } - treeNode = extractedChilds.findChild(typeName); + treeNode = typesChildren.findChild(typeName); } if (treeNode == null) { @@ -1419,6 +1296,269 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // Another thread is needed because we have to wait for dataResult to populate } + /** + * Returns the hashset hit artifact's parent node or null if cannot be + * found. + * + * @param typesChildren The children object of the same category as hashset + * hits. + * @param art The artifact. + * + * @return The hashset hit artifact's parent node or null if cannot be + * found. + */ + private Node getHashsetNode(Children typesChildren, final BlackboardArtifact art) { + Node hashsetRootNode = typesChildren.findChild(art.getArtifactTypeName()); + Children hashsetRootChilds = hashsetRootNode.getChildren(); + 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(); + } + } + return hashsetRootChilds.findChild(setName); + } catch (TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS + return null; + } + } + + /** + * Returns the keyword hit artifact's parent node or null if cannot be + * found. + * + * @param typesChildren The children object of the same category as keyword + * hits. + * @param art The artifact. + * + * @return The keyword hit artifact's parent node or null if cannot be + * found. + */ + private Node getKeywordHitNode(Children typesChildren, BlackboardArtifact art) { + Node keywordRootNode = typesChildren.findChild(art.getArtifactTypeName()); + Children keywordRootChilds = keywordRootNode.getChildren(); + try { + String listName = null; + String keywordName = null; + String regex = null; + List attributes = art.getAttributes(); + for (BlackboardAttribute att : attributes) { + int typeId = att.getAttributeType().getTypeID(); + if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { + listName = att.getValueString(); + } else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) { + keywordName = att.getValueString(); + } else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()) { + regex = att.getValueString(); + } + } + if (listName == null) { + if (regex == null) { //using same labels used for creation + listName = NbBundle.getMessage(KeywordHits.class, "KeywordHits.simpleLiteralSearch.text"); + } else { + listName = NbBundle.getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text"); + } + } + Node listNode = keywordRootChilds.findChild(listName); + if (listNode == null) { + return null; + } + Children listChildren = listNode.getChildren(); + if (listChildren == null) { + return null; + } + if (regex != null) { //For support of regex nodes such as URLs, IPs, Phone Numbers, and Email Addrs as they are down another level + Node regexNode = listChildren.findChild(regex); + if (regexNode == null) { + return null; + } + listChildren = regexNode.getChildren(); + if (listChildren == null) { + return null; + } + } + + return listChildren.findChild(keywordName); + } catch (TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS + return null; + } + } + + /** + * Returns the interesting item artifact's parent node or null if cannot be + * found. + * + * @param typesChildren The children object of the same category as + * interesting item. + * @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(); + 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.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()) + ? fileArtifactNodes[0] + : fileArtifactNodes[1]; + } catch (TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS + return null; + } + } + + /** + * Returns the email artifact's parent node or null if cannot be found. + * + * @param typesChildren The children object of the same category as email. + * @param art The artifact. + * + * @return The email artifact's parent node or null if cannot be found. + */ + private Node getEmailNode(Children typesChildren, BlackboardArtifact art) { + Node emailMsgRootNode = typesChildren.findChild(art.getArtifactTypeName()); + Children emailMsgRootChilds = emailMsgRootNode.getChildren(); + Map parsedPath = null; + try { + List attributes = art.getAttributes(); + for (BlackboardAttribute att : attributes) { + int typeId = att.getAttributeType().getTypeID(); + if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID()) { + parsedPath = EmailExtracted.parsePath(att.getValueString()); + break; + } + } + if (parsedPath == null) { + return null; + } + Node defaultNode = emailMsgRootChilds.findChild(parsedPath.get(NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text"))); + Children defaultChildren = defaultNode.getChildren(); + return defaultChildren.findChild(parsedPath.get(NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text"))); + } catch (TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS + return null; + } + } + + /** + * Returns the account artifact's parent node or null if cannot be found. + * + * @param typesChildren The children object of the same category as the + * account. + * @param art The artifact. + * + * @return The account artifact's parent node or null if cannot be found. + */ + private Node getAccountNode(Children typesChildren, BlackboardArtifact art) { + Node accountRootNode = typesChildren.findChild(art.getDisplayName()); + Children accountRootChilds = accountRootNode.getChildren(); + List attributes; + String accountType = null; + String ccNumberName = null; + try { + attributes = art.getAttributes(); + for (BlackboardAttribute att : attributes) { + int typeId = att.getAttributeType().getTypeID(); + if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()) { + accountType = att.getValueString(); + } + if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID()) { + ccNumberName = att.getValueString(); + } + } + if (accountType == null) { + return null; + } + + if (accountType.equals(Account.Type.CREDIT_CARD.getTypeName())) { + return getCreditCardAccountNode(accountRootChilds, ccNumberName); + } else { //default account type + return accountRootChilds.findChild(accountType); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS + return null; + } + } + + /** + * Returns the credit card artifact's parent node or null if cannot be + * found. + * + * @param typesChildren The children object of the same category as credit + * card. + * @param art The artifact. + * + * @return The credit card artifact's parent node or null if cannot be + * found. + */ + private Node getCreditCardAccountNode(Children accountRootChildren, String ccNumberName) { + Node accountNode = accountRootChildren.findChild(Account.Type.CREDIT_CARD.getDisplayName()); + if (accountNode == null) { + return null; + } + Children accountChildren = accountNode.getChildren(); + if (accountChildren == null) { + return null; + } + Node binNode = accountChildren.findChild(NbBundle.getMessage(Accounts.class, "Accounts.ByBINNode.name")); + if (binNode == null) { + return null; + } + Children binChildren = binNode.getChildren(); + if (ccNumberName == null) { + return null; + } + //right padded with 0s to 8 digits when single number + //when a range of numbers, the first 6 digits are rightpadded with 0s to 8 digits then a dash then 3 digits, the 6,7,8, digits of the end number right padded with 9s + String binName = StringUtils.rightPad(ccNumberName, 8, "0"); + binName = binName.substring(0, 8); + int bin; + try { + bin = Integer.parseInt(binName); + } catch (NumberFormatException ex) { + LOGGER.log(Level.WARNING, "Unable to parseInt a BIN for node selection from string binName=" + binName, ex); //NON-NLS + return null; + } + CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin); + if (binInfo != null) { + int startBin = ((BINRange) binInfo).getBINstart(); + int endBin = ((BINRange) binInfo).getBINend(); + if (startBin != endBin) { + binName = Integer.toString(startBin) + "-" + Integer.toString(endBin).substring(5); //if there is a range re-construct the name it appears as + } + } + if (binName == null) { + return null; + } + return binChildren.findChild(binName); + } + public void viewArtifactContent(BlackboardArtifact art) { new ViewContextAction( NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.action.viewArtContent.text"), From 61ede44e7e1b54f839a7327fb4a4cb79a22c3317 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 3 May 2021 14:38:16 -0400 Subject: [PATCH 13/16] bug fixes --- .../autopsy/datamodel/Artifacts.java | 34 ++++--- .../datamodel/Bundle.properties-MERGED | 8 +- .../autopsy/datamodel/accounts/Accounts.java | 99 +++++++++++++------ 3 files changed, 92 insertions(+), 49 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index 2bce9cdc95..cc78991c95 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -70,7 +70,6 @@ public class Artifacts { private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); - /** * Base class for a parent node of artifacts. */ @@ -463,6 +462,27 @@ public class Artifacts { return this.childCount; } + /** + * Fetches the count to be displayed from the case. + * + * @param skCase The relevant SleuthkitCase. + * + * @return The count to be displayed. + * + * @throws TskCoreException + */ + protected long fetchChildCount(SleuthkitCase skCase) throws TskCoreException { + int count = 0; + for (BlackboardArtifact.Type type : this.types) { + if (filteringDSObjId > 0) { + count += skCase.getBlackboard().getArtifactsCount(type.getTypeID(), filteringDSObjId); + } else { + count += skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); + } + } + return count; + } + /** * When this method is called, the count to be displayed will be * updated. @@ -470,17 +490,7 @@ public class Artifacts { void updateDisplayName() { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - - int count = 0; - for (BlackboardArtifact.Type type : this.types) { - if (filteringDSObjId > 0) { - count += skCase.getBlackboard().getArtifactsCount(type.getTypeID(), filteringDSObjId); - } else { - count += skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); - } - } - - this.childCount = count; + this.childCount = fetchChildCount(skCase); } catch (NoCurrentCaseException ex) { logger.log(Level.WARNING, "Error fetching data when case closed.", ex); } catch (TskCoreException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED index aa955c23e8..2feefb56c7 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED @@ -39,7 +39,7 @@ AbstractAbstractFileNode.useridColLbl=UserID AbstractContentNode.nodescription=no description AbstractContentNode.valueLoading=value loading AbstractFsContentNode.noDesc.text=no description -AnalysisResultsNode_name=Analysis Results +AnalysisResults_name=Analysis Results ArtifactStringContent.attrsTableHeader.sources=Source(s) ArtifactStringContent.attrsTableHeader.type=Type ArtifactStringContent.attrsTableHeader.value=Value @@ -94,7 +94,7 @@ ContentTagNode.createSheet.artifactMD5.displayName=MD5 Hash ContentTagNode.createSheet.artifactMD5.name=MD5 Hash ContentTagNode.createSheet.origFileName=Original Name ContentTagNode.createSheet.userName.text=User Name -DataArtifactsNode_name=Data Artifacts +DataArtifacts_name=Data Artifacts DataSourcesHostsNode_name=Data Sources DeletedContent.allDelFilter.text=All DeletedContent.createSheet.filterType.desc=no description @@ -360,10 +360,6 @@ ReportNode.reportNameProperty.name=Report Name ReportNode.reportNameProperty.displayName=Report Name ReportNode.reportNameProperty.desc=Name of the report ReportsListNode.displayName=Reports -ResultsNode.createSheet.name.desc=no description -ResultsNode.createSheet.name.displayName=Name -ResultsNode.createSheet.name.name=Name -ResultsNode.name.text=Results SlackFileNode.getActions.viewInNewWin.text=View in New Window SlackFileNode.getActions.viewFileInDir.text=View File in Directory SpecialDirectoryNode.getActions.viewInNewWin.text=View in New Window diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index aa6a53f8ec..c453603874 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -96,7 +96,7 @@ final public class Accounts implements AutopsyVisitableItem { 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 String DISPLAY_NAME = Bundle.Accounts_RootNode_displayName(); - + @NbBundle.Messages("AccountsRootNode.name=Accounts") final public static String NAME = Bundle.AccountsRootNode_name(); @@ -112,11 +112,10 @@ final public class Accounts implements AutopsyVisitableItem { private final RejectAccounts rejectActionInstance; private final ApproveAccounts approveActionInstance; - + // tracks the number of each account type found private final AccountTypeResults accountTypeResults; - /** * Constructor * @@ -135,7 +134,7 @@ final public class Accounts implements AutopsyVisitableItem { public Accounts(SleuthkitCase skCase, long objId) { this.skCase = skCase; this.filteringDSObjId = objId; - + this.rejectActionInstance = new RejectAccounts(); this.approveActionInstance = new ApproveAccounts(); this.accountTypeResults = new AccountTypeResults(); @@ -238,12 +237,12 @@ final public class Accounts implements AutopsyVisitableItem { final public class AccountsRootNode extends UpdatableCountTypeNode { public AccountsRootNode() { - super(Children.create(new AccountTypeFactory(), true), + super(Children.create(new AccountTypeFactory(), true), Lookups.singleton(Accounts.this), DISPLAY_NAME, filteringDSObjId, new BlackboardArtifact.Type(TSK_ACCOUNT)); - + setName(Accounts.NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/accounts.png"); //NON-NLS } @@ -262,37 +261,71 @@ final public class Accounts implements AutopsyVisitableItem { public String getItemType() { return getClass().getName(); } + + @Override + protected long fetchChildCount(SleuthkitCase skCase) throws TskCoreException { + long count = 0; + String dataSourceFilterClause = (filteringDSObjId > 0) + ? " AND " + filteringDSObjId + " IN (SELECT art.data_source_obj_id FROM blackboard_artifacts art WHERE art.artifact_id = attr.artifact_id)" + : ""; + + String accountTypesInUseQuery + = "SELECT COUNT(attr.value_text) AS count" + + " FROM blackboard_attributes attr" + + " WHERE attr.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() + + " AND attr.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() + + dataSourceFilterClause + + " GROUP BY attr.value_text"; + + try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery); + ResultSet resultSet = executeQuery.getResultSet()) { + + if (resultSet.next()) { + count = resultSet.getLong("count"); + } + + } catch (TskCoreException | SQLException ex) { + LOGGER.log(Level.SEVERE, "Error querying for count of all account types", ex); + } + return count; + } + } - + /** * Tracks the account types and the number of account types found. */ private class AccountTypeResults { + private final Map counts = new HashMap<>(); - + AccountTypeResults() { update(); } - + /** - * Given the type name of the Account.Type, provides the count of those type. - * @param accountType The type name of the Account.Type. - * @return The number of results found for the given account type. + * Given the type name of the Account.Type, provides the count of those + * type. + * + * @param accountType The type name of the Account.Type. + * + * @return The number of results found for the given account type. */ Long getCount(String accountType) { return counts.get(accountType); } - + /** * Retrieves an alphabetically organized list of all the account types. - * @return An alphabetically organized list of all the account types. + * + * @return An alphabetically organized list of all the account types. */ List getTypes() { List types = new ArrayList<>(counts.keySet()); Collections.sort(types); return types; } - + /** * Queries the database and updates the counts for each account type. */ @@ -308,7 +341,7 @@ final public class Accounts implements AutopsyVisitableItem { try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery); ResultSet resultSet = executeQuery.getResultSet()) { - + counts.clear(); while (resultSet.next()) { String accountType = resultSet.getString("account_type"); @@ -325,7 +358,7 @@ final public class Accounts implements AutopsyVisitableItem { * Creates child nodes for each account type in the db. */ private class AccountTypeFactory extends ObservingChildren { - + /* * The pcl is in this class because it has the easiest mechanisms to add * and remove itself during its life cycles. @@ -399,12 +432,14 @@ final public class Accounts implements AutopsyVisitableItem { list.addAll(accountTypeResults.getTypes()); return true; } - + /** - * Registers the given node with the reviewStatusBus and returns - * the node wrapped in an array. - * @param node The node to be wrapped. - * @return The array containing this node. + * Registers the given node with the reviewStatusBus and returns the + * node wrapped in an array. + * + * @param node The node to be wrapped. + * + * @return The array containing this node. */ private Node[] getNodeArr(Node node) { reviewStatusBus.register(node); @@ -584,8 +619,9 @@ final public class Accounts implements AutopsyVisitableItem { * no special behavior. */ final public class DefaultAccountTypeNode extends DisplayableItemNode { + private final Account.Type accountType; - + private DefaultAccountTypeNode(Account.Type accountType) { super(Children.create(new DefaultAccountFactory(accountType), true), Lookups.singleton(accountType)); this.accountType = accountType; @@ -608,8 +644,7 @@ final public class Accounts implements AutopsyVisitableItem { public String getItemType() { return getClass().getName(); } - - + @Subscribe void handleReviewStatusChange(ReviewStatusChangeEvent event) { updateName(); @@ -619,12 +654,13 @@ final public class Accounts implements AutopsyVisitableItem { void handleDataAdded(ModuleDataEvent event) { updateName(); } - + /** - * Gets the latest counts for the account type and then updates the name. + * Gets the latest counts for the account type and then updates the + * name. */ public void updateName() { - setName(String.format("%s (%d)", accountType.getDisplayName(), accountTypeResults.getCount(accountType.getTypeName()))); + setDisplayName(String.format("%s (%d)", accountType.getDisplayName(), accountTypeResults.getCount(accountType.getTypeName()))); } } @@ -755,14 +791,15 @@ final public class Accounts implements AutopsyVisitableItem { setName(Account.Type.CREDIT_CARD.getDisplayName()); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS } - + /** - * Gets the latest counts for the account type and then updates the name. + * Gets the latest counts for the account type and then updates the + * name. */ public void updateName() { setName(String.format("%s (%d)", Account.Type.CREDIT_CARD.getDisplayName(), accountTypeResults.getCount(Account.Type.CREDIT_CARD.getTypeName()))); } - + @Subscribe void handleReviewStatusChange(ReviewStatusChangeEvent event) { updateName(); From 188d02809c5a97bc343393094862817fbc084f98 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 3 May 2021 14:55:07 -0400 Subject: [PATCH 14/16] bug fix --- Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index c453603874..8559d45d51 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -627,6 +627,7 @@ final public class Accounts implements AutopsyVisitableItem { this.accountType = accountType; String iconPath = getIconFilePath(accountType); this.setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath); //NON-NLS + setName(accountType.getTypeName()); updateName(); } From e9f9dd87d9d8c72e69dfbedda12815fc4985e8e2 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 3 May 2021 15:38:52 -0400 Subject: [PATCH 15/16] migration to blackboard artifact types --- .../autopsy/datamodel/Artifacts.java | 44 ++++++++++--------- .../autopsy/datamodel/EmailExtracted.java | 8 ++-- .../autopsy/datamodel/HashsetHits.java | 13 +++--- .../autopsy/datamodel/InterestingHits.java | 26 +++++------ .../autopsy/datamodel/KeywordHits.java | 10 ++--- .../autopsy/datamodel/accounts/Accounts.java | 30 ++++++------- .../DirectoryTreeTopComponent.java | 17 +++---- 7 files changed, 76 insertions(+), 72 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index cc78991c95..d39bef3ee9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -36,7 +36,6 @@ import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.Lookup; import org.openide.util.NbBundle; -import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -46,21 +45,22 @@ import org.sleuthkit.autopsy.datamodel.utils.IconsUtil; 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_ASSOCIATED_OBJECT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_TL_EVENT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.guiutils.RefreshThrottler; import org.sleuthkit.datamodel.BlackboardArtifact.Category; import org.python.google.common.collect.Sets; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_ACCOUNT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_DATA_SOURCE_USAGE; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_EMAIL_MSG; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_HASHSET_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_GEN_INFO; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_TL_EVENT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_ASSOCIATED_OBJECT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_KEYWORD_HIT; /** * Classes for creating nodes for BlackboardArtifacts. @@ -215,12 +215,12 @@ public class Artifacts { @SuppressWarnings("deprecation") private static final Set IGNORED_TYPES = Sets.newHashSet( // these are shown in other parts of the UI (and different node types) - new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE), - new BlackboardArtifact.Type(TSK_GEN_INFO), + TSK_DATA_SOURCE_USAGE, + TSK_GEN_INFO, new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE), - new BlackboardArtifact.Type(TSK_TL_EVENT), + TSK_TL_EVENT, //This is not meant to be shown in the UI at all. It is more of a meta artifact. - new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) + TSK_ASSOCIATED_OBJECT ); /** @@ -238,24 +238,28 @@ public class Artifacts { int typeId = type.getTypeID(); if (TSK_EMAIL_MSG.getTypeID() == typeId) { EmailExtracted.RootNode emailNode = new EmailExtracted(skCase, dsObjId).new RootNode(); - return new TypeNodeKey(emailNode, new BlackboardArtifact.Type(TSK_EMAIL_MSG)); + return new TypeNodeKey(emailNode, TSK_EMAIL_MSG); } else if (TSK_ACCOUNT.getTypeID() == typeId) { Accounts.AccountsRootNode accountsNode = new Accounts(skCase, dsObjId).new AccountsRootNode(); - return new TypeNodeKey(accountsNode, new BlackboardArtifact.Type(TSK_ACCOUNT)); + return new TypeNodeKey(accountsNode, TSK_ACCOUNT); } else if (TSK_KEYWORD_HIT.getTypeID() == typeId) { KeywordHits.RootNode keywordsNode = new KeywordHits(skCase, dsObjId).new RootNode(); - return new TypeNodeKey(keywordsNode, new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); + 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, - new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), - new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT)); + TSK_INTERESTING_ARTIFACT_HIT, + 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); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 06ed408976..845fdf8798 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -44,7 +44,7 @@ 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_EMAIL_MSG; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_EMAIL_MSG; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; @@ -59,7 +59,7 @@ import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; */ public class EmailExtracted implements AutopsyVisitableItem { - private static final String LABEL_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getLabel(); + private static final String LABEL_NAME = BlackboardArtifact.Type.TSK_EMAIL_MSG.getLabel(); private static final Logger logger = Logger.getLogger(EmailExtracted.class.getName()); private static final String MAIL_ACCOUNT = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailAccount.text"); private static final String MAIL_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text"); @@ -157,7 +157,7 @@ public class EmailExtracted implements AutopsyVisitableItem { } // get artifact id and path (if present) of all email artifacts - int emailArtifactId = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(); + int emailArtifactId = BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeID(); int pathAttrId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID(); String query = "SELECT \n" @@ -279,7 +279,7 @@ public class EmailExtracted implements AutopsyVisitableItem { * for the event to have a null oldValue. */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); - if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) { + if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeID()) { emailResults.update(); } } catch (NoCurrentCaseException notUsed) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index 150a52e3da..5318a99a00 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -46,8 +46,7 @@ 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.BlackboardArtifact.ARTIFACT_TYPE; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_HASHSET_HIT; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; @@ -59,8 +58,8 @@ import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; */ public class HashsetHits implements AutopsyVisitableItem { - private static final String HASHSET_HITS = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getLabel(); - private static final String DISPLAY_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(); + private static final String HASHSET_HITS = BlackboardArtifact.Type.TSK_HASHSET_HIT.getTypeName(); + private static final String DISPLAY_NAME = BlackboardArtifact.Type.TSK_HASHSET_HIT.getDisplayName(); private static final Logger logger = Logger.getLogger(HashsetHits.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); @@ -136,7 +135,7 @@ public class HashsetHits implements AutopsyVisitableItem { } int setNameId = ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(); - int artId = ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(); + int artId = 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 @@ -177,7 +176,7 @@ public class HashsetHits implements AutopsyVisitableItem { Lookups.singleton(DISPLAY_NAME), DISPLAY_NAME, filteringDSObjId, - new BlackboardArtifact.Type(TSK_HASHSET_HIT)); + TSK_HASHSET_HIT); super.setName(HASHSET_HITS); super.setDisplayName(DISPLAY_NAME); @@ -246,7 +245,7 @@ public class HashsetHits implements AutopsyVisitableItem { * oldValue if the event is a remote event. */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); - if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { + if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == TSK_HASHSET_HIT.getTypeID()) { hashsetResults.update(); } } catch (NoCurrentCaseException notUsed) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 28bfb3e8dc..22525854ca 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -111,8 +111,8 @@ public class InterestingHits implements AutopsyVisitableItem { synchronized (interestingItemsMap) { interestingItemsMap.clear(); } - loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); - loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); + loadArtifacts(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT); + loadArtifacts(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT); setChanged(); notifyObservers(); } @@ -122,7 +122,7 @@ public class InterestingHits implements AutopsyVisitableItem { * the interestingItemsMap */ @SuppressWarnings("deprecation") - private void loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE artType) { + private void loadArtifacts(BlackboardArtifact.Type artType) { if (skCase == null) { return; } @@ -146,8 +146,8 @@ public class InterestingHits implements AutopsyVisitableItem { long artifactId = resultSet.getLong("artifact_id"); //NON-NLS if (!interestingItemsMap.containsKey(value)) { interestingItemsMap.put(value, new LinkedHashMap<>()); - interestingItemsMap.get(value).put(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getDisplayName(), new HashSet<>()); - interestingItemsMap.get(value).put(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName(), new HashSet<>()); + 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(artifactId); } @@ -173,8 +173,8 @@ public class InterestingHits implements AutopsyVisitableItem { Lookups.singleton(DISPLAY_NAME), DISPLAY_NAME, filteringDSObjId, - new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT), - new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT)); + 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 } @@ -237,8 +237,8 @@ public class InterestingHits implements AutopsyVisitableItem { * event to have a null oldValue. */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); - if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() - || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID())) { + 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) { @@ -319,8 +319,8 @@ public class InterestingHits implements AutopsyVisitableItem { } private void updateDisplayName() { - int sizeOfSet = interestingResults.getArtifactIds(setName, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()).size() - + interestingResults.getArtifactIds(setName, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getDisplayName()).size(); + 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 + ")"); } @@ -379,8 +379,8 @@ public class InterestingHits implements AutopsyVisitableItem { @Override protected boolean createKeys(List list) { - list.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getDisplayName()); - list.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()); + list.add(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName()); + list.add(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()); return true; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 845c87d5ea..396cbea57e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -55,7 +55,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_KEYWORD_HIT; import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; /** @@ -73,7 +73,7 @@ public class KeywordHits implements AutopsyVisitableItem { @NbBundle.Messages("KeywordHits.singleRegexSearch.text=Single Regular Expression Search") private static final String SIMPLE_REGEX_SEARCH = KeywordHits_singleRegexSearch_text(); - public static final String NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getLabel(); + public static final String NAME = BlackboardArtifact.Type.TSK_KEYWORD_HIT.getLabel(); private SleuthkitCase skCase; private final KeywordResults keywordResults; @@ -95,7 +95,7 @@ public class KeywordHits implements AutopsyVisitableItem { + "blackboard_attributes.attribute_type_id "//NON-NLS + "FROM blackboard_attributes, blackboard_artifacts "//NON-NLS + "WHERE blackboard_attributes.artifact_id = blackboard_artifacts.artifact_id "//NON-NLS - + " AND blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() //NON-NLS + + " AND blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeID() //NON-NLS + " AND (attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()//NON-NLS + " OR attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()//NON-NLS + " OR attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()//NON-NLS @@ -384,7 +384,7 @@ public class KeywordHits implements AutopsyVisitableItem { Lookups.singleton(KEYWORD_HITS), KEYWORD_HITS, filteringDSObjId, - new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); + TSK_KEYWORD_HIT); super.setName(NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS @@ -470,7 +470,7 @@ public class KeywordHits implements AutopsyVisitableItem { * for the event to have a null oldValue. */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); - if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { + if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeID()) { keywordResults.update(); } } catch (NoCurrentCaseException notUsed) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index 8559d45d51..18136db99e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -77,8 +77,8 @@ import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT; +import org.sleuthkit.datamodel.BlackboardArtifact.Type; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_ACCOUNT; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; @@ -241,7 +241,7 @@ final public class Accounts implements AutopsyVisitableItem { Lookups.singleton(Accounts.this), DISPLAY_NAME, filteringDSObjId, - new BlackboardArtifact.Type(TSK_ACCOUNT)); + TSK_ACCOUNT); setName(Accounts.NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/accounts.png"); //NON-NLS @@ -384,7 +384,7 @@ final public class Accounts implements AutopsyVisitableItem { */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); if (null != eventData - && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + && eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) { accountTypeResults.update(); reviewStatusBus.post(eventData); } @@ -519,7 +519,7 @@ final public class Accounts implements AutopsyVisitableItem { */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); if (null != eventData - && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + && eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) { reviewStatusBus.post(eventData); } } catch (NoCurrentCaseException notUsed) { @@ -572,7 +572,7 @@ final public class Accounts implements AutopsyVisitableItem { = "SELECT blackboard_artifacts.artifact_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.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + " AND blackboard_attributes.value_text = '" + accountType.getTypeName() + "'" //NON-NLS + getFilterByDataSourceClause() @@ -696,7 +696,7 @@ final public class Accounts implements AutopsyVisitableItem { */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); if (null != eventData - && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + && eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) { reviewStatusBus.post(eventData); } } catch (NoCurrentCaseException notUsed) { @@ -850,7 +850,7 @@ final public class Accounts implements AutopsyVisitableItem { */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); if (null != eventData - && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + && eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) { reviewStatusBus.post(eventData); } } catch (NoCurrentCaseException notUsed) { @@ -928,7 +928,7 @@ final public class Accounts implements AutopsyVisitableItem { + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS + getFilterByDataSourceClause() + getRejectedArtifactFilterClause() + " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS @@ -997,7 +997,7 @@ final public class Accounts implements AutopsyVisitableItem { + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS + getFilterByDataSourceClause() + getRejectedArtifactFilterClause() + " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo"; @@ -1065,7 +1065,7 @@ final public class Accounts implements AutopsyVisitableItem { */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); if (null != eventData - && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + && eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) { reviewStatusBus.post(eventData); } } catch (NoCurrentCaseException notUsed) { //NOPMD empy catch clause @@ -1133,7 +1133,7 @@ final public class Accounts implements AutopsyVisitableItem { + " COUNT(blackboard_artifacts.artifact_id) AS count " //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.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + getFilterByDataSourceClause() + getRejectedArtifactFilterClause() @@ -1200,7 +1200,7 @@ final public class Accounts implements AutopsyVisitableItem { = "SELECT count(distinct SUBSTR(blackboard_attributes.value_text,1,8)) AS BINs " //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.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + getFilterByDataSourceClause() + getRejectedArtifactFilterClause(); //NON-NLS @@ -1495,7 +1495,7 @@ final public class Accounts implements AutopsyVisitableItem { = "SELECT blackboard_artifacts.artifact_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.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS + getFilterByDataSourceClause() @@ -1569,7 +1569,7 @@ final public class Accounts implements AutopsyVisitableItem { = "SELECT count(blackboard_artifacts.artifact_id ) AS count" //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.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS + getFilterByDataSourceClause() diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 6d90e9b821..d5fe55d358 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -1261,16 +1261,16 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat Children typesChildren = categoryChildrenOpt.get(); Node treeNode = null; - if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { + if (typeID == BlackboardArtifact.Type.TSK_HASHSET_HIT.getTypeID()) { treeNode = getHashsetNode(typesChildren, art); - } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { + } else if (typeID == BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeID()) { treeNode = getKeywordHitNode(typesChildren, art); - } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() - || typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { + } 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.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) { + } else if (typeID == BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeID()) { treeNode = getEmailNode(typesChildren, art); - } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + } else if (typeID == BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID()) { treeNode = getAccountNode(typesChildren, art); } else { treeNode = typesChildren.findChild(typeName); @@ -1371,7 +1371,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat return null; } if (regex != null) { //For support of regex nodes such as URLs, IPs, Phone Numbers, and Email Addrs as they are down another level - Node regexNode = listChildren.findChild(regex); + Node regexNode = listChildren.findChild(listName); + regexNode = (regexNode == null) ? listChildren.findChild(listName + "_" + regex) : regexNode; if (regexNode == null) { return null; } @@ -1423,7 +1424,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat return null; } - return (art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()) + return (art.getArtifactTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID()) ? fileArtifactNodes[0] : fileArtifactNodes[1]; } catch (TskCoreException ex) { From dae6b773b1c872721aabbd03baeac5364a99b1c0 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 3 May 2021 20:00:00 -0400 Subject: [PATCH 16/16] fixes --- Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java | 4 ++-- Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 845fdf8798..357f6ec153 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -59,7 +59,7 @@ import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; */ public class EmailExtracted implements AutopsyVisitableItem { - private static final String LABEL_NAME = BlackboardArtifact.Type.TSK_EMAIL_MSG.getLabel(); + private static final String LABEL_NAME = BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeName(); private static final Logger logger = Logger.getLogger(EmailExtracted.class.getName()); private static final String MAIL_ACCOUNT = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailAccount.text"); private static final String MAIL_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text"); @@ -210,7 +210,7 @@ public class EmailExtracted implements AutopsyVisitableItem { Lookups.singleton(TSK_EMAIL_MSG.getDisplayName()), TSK_EMAIL_MSG.getDisplayName(), filteringDSObjId, - new BlackboardArtifact.Type(TSK_EMAIL_MSG)); + TSK_EMAIL_MSG); //super(Children.create(new AccountFactory(), true), Lookups.singleton(DISPLAY_NAME)); super.setName(LABEL_NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/mail-icon-16.png"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 396cbea57e..eab8a07d3a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -73,7 +73,7 @@ public class KeywordHits implements AutopsyVisitableItem { @NbBundle.Messages("KeywordHits.singleRegexSearch.text=Single Regular Expression Search") private static final String SIMPLE_REGEX_SEARCH = KeywordHits_singleRegexSearch_text(); - public static final String NAME = BlackboardArtifact.Type.TSK_KEYWORD_HIT.getLabel(); + public static final String NAME = BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeName(); private SleuthkitCase skCase; private final KeywordResults keywordResults;