From c05e92aec20db4fa420541247bcc03abb7642185 Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 27 Apr 2018 11:08:46 -0400 Subject: [PATCH 01/29] 3757: Group views in the case tree by data source --- .../autopsy/core/UserPreferences.java | 9 ++ .../datamodel/AbstractContentChildren.java | 6 +- .../datamodel/DataSourceLayerNode.java | 114 +++++++++++++++ .../datamodel/DataSourcesLayerChildren.java | 134 ++++++++++++++++++ .../autopsy/datamodel/DeletedContent.java | 51 +++++-- .../datamodel/DisplayableItemNodeVisitor.java | 7 + .../sleuthkit/autopsy/datamodel/FileSize.java | 53 +++++-- .../autopsy/datamodel/FileTypes.java | 14 +- .../datamodel/FileTypesByExtension.java | 9 +- .../datamodel/FileTypesByMimeType.java | 10 +- .../autopsy/datamodel/ViewsNode.java | 25 ++-- .../autopsy/directorytree/Bundle.properties | 1 + .../DirectoryTreeTopComponent.form | 46 ++++-- .../DirectoryTreeTopComponent.java | 58 ++++++-- 14 files changed, 467 insertions(+), 70 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/DataSourceLayerNode.java create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesLayerChildren.java diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index 904ab285c8..22fa2b7135 100644 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -69,6 +69,7 @@ public final class UserPreferences { private static final String MODE = "AutopsyMode"; // NON-NLS private static final String MAX_NUM_OF_LOG_FILE = "MaximumNumberOfLogFiles"; private static final int LOG_FILE_NUM_INT = 10; + public static final String GROUP_ITEMS_IN_TREE_BY_DATASOURCE = "GroupItemsInTreeByDataSource"; //NON-NLS // Prevent instantiation. private UserPreferences() { @@ -187,6 +188,14 @@ public final class UserPreferences { preferences.putInt(NUMBER_OF_FILE_INGEST_THREADS, value); } + public static boolean groupItemsInTreeByDatasource() { + return preferences.getBoolean(GROUP_ITEMS_IN_TREE_BY_DATASOURCE, false); + } + + public static void setGroupItemsInTreeByDatasource(boolean value) { + preferences.putBoolean(GROUP_ITEMS_IN_TREE_BY_DATASOURCE, value); + } + /** * Reads persisted case database connection info. * diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index bf139f9a47..25da96db78 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -162,12 +162,12 @@ abstract class AbstractContentChildren extends Keys { @Override public AbstractNode visit(DeletedContent dc) { - return new DeletedContent.DeletedContentsNode(dc.getSleuthkitCase()); + return new DeletedContent.DeletedContentsNode(dc.getSleuthkitCase(), dc.filteringDataSourceObjId()); } @Override public AbstractNode visit(FileSize dc) { - return new FileSize.FileSizeRootNode(dc.getSleuthkitCase()); + return new FileSize.FileSizeRootNode(dc.getSleuthkitCase(), dc.filteringDataSourceObjId()); } @Override @@ -234,7 +234,7 @@ abstract class AbstractContentChildren extends Keys { @Override public AbstractNode visit(FileTypesByMimeType ftByMimeTypeItem) { - return ftByMimeTypeItem.new ByMimeTypeNode(); + return ftByMimeTypeItem.new ByMimeTypeNode(/*ftByMimeTypeItem.filteringDataSourceObjId()*/); } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceLayerNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceLayerNode.java new file mode 100644 index 0000000000..9573597d5a --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceLayerNode.java @@ -0,0 +1,114 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 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 java.util.Arrays; +import java.util.Collections; +import java.util.Optional; +import java.util.logging.Level; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.DataSourcesLayerChildren.SubtreeEnum; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.LocalFilesDataSource; + + +/** + * Datasource layer node - an optional grouping node in the data tree view + * + */ +public class DataSourceLayerNode extends DisplayableItemNode { + + private static final Logger logger = Logger.getLogger(DataSourceLayerNode.class.getName()); + + /** + * Creates the Datasource node for the given data source, + * and initializes the children nodes under it based on the subtree specified + * + * @param dataSourceLayerInfo specifies the + */ + DataSourceLayerNode(DataSourcesLayerChildren.DataSourceLayerInfo dataSourceLayerInfo) { + + super (Optional.ofNullable(createDSLayerNodeChildren(dataSourceLayerInfo)) + .orElse(new RootContentChildren(Arrays.asList(Collections.EMPTY_LIST)))); + + DataSource dataSource = dataSourceLayerInfo.getDataSource(); + if (dataSource instanceof Image) { + Image image = (Image) dataSource; + + super.setName(image.getName()); + super.setDisplayName(image.getName()); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png"); + } else if (dataSource instanceof LocalFilesDataSource) { + LocalFilesDataSource localFilesDataSource = (LocalFilesDataSource) dataSource; + + super.setName(localFilesDataSource.getName()); + super.setDisplayName(localFilesDataSource.getName()); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); + } + + } + + @Override + public boolean isLeafTypeNode() { + return false; + } + + private static RootContentChildren createDSLayerNodeChildren(DataSourcesLayerChildren.DataSourceLayerInfo dataSourceLayerInfo) { + + SubtreeEnum subtree = dataSourceLayerInfo.getSubtree(); + long dsObjId = dataSourceLayerInfo.getDataSource().getId(); + + try { + switch (subtree) { + case VIEWS: + return new RootContentChildren(Arrays.asList( + new FileTypes(Case.getOpenCase().getSleuthkitCase(), dsObjId), + new DeletedContent(Case.getOpenCase().getSleuthkitCase(), dsObjId), + new FileSize(Case.getOpenCase().getSleuthkitCase(), dsObjId)) + ); + + case RESULTS: // TBD: + case TAGS: // TBD: + case REPORTS: // TBD: + + default: + { + logger.log(Level.SEVERE, "Unknown subtree type " + subtree.name()); //NON-NLS + return null; + } + } + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Error getting open case.", ex); //NON-NLS + return null; + } + } + + @Override + public T accept(DisplayableItemNodeVisitor visitor) { + return visitor.visit(this); + } + + @Override + public String getItemType() { + return getClass().getName(); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesLayerChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesLayerChildren.java new file mode 100644 index 0000000000..95513b3b97 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesLayerChildren.java @@ -0,0 +1,134 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 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 java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.logging.Level; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Child factory for DataSource node layer in the Results, Views Tags subtrees + * + */ +class DataSourcesLayerChildren extends Children.Keys { + + private static final Logger logger = Logger.getLogger(DataSourcesLayerChildren.class.getName()); + private final SleuthkitCase sleuthkitCase; + private final SubtreeEnum subTree; + + /** + * Subtree in which this DataSourcesLayerChildren exist + */ + public enum SubtreeEnum { + VIEWS, + RESULTS, + TAGS, + REPORTS + } + + /** + * Simple wrapper class to pass Datasource and subtree down to children nodes + * + */ + class DataSourceLayerInfo { + + private final DataSource dataSource; + private final SubtreeEnum subTree; + + DataSourceLayerInfo(DataSource dataSource, SubtreeEnum subTree) { + this.dataSource = dataSource; + this.subTree = subTree; + } + + DataSource getDataSource() { + return this.dataSource; + } + + SubtreeEnum getSubtree() { + return this.subTree; + } + } + + /** + * Constructs the factory to create optional datasource nodes + * + * @param tskCase - Case DB + * @param subTree - subtree under which data source nodes are to be created + */ + public DataSourcesLayerChildren(SleuthkitCase tskCase, SubtreeEnum subTree) { + // super(true); + super(false); + + this.sleuthkitCase = tskCase; + this.subTree = subTree; + } + + private final PropertyChangeListener pcl = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + String eventType = evt.getPropertyName(); + if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { + reloadKeys(); + } + } + }; + + private void reloadKeys() { + try { + List keys = sleuthkitCase.getDataSources(); + setKeys(keys); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get Datasources from DB", ex); + } + } + + @Override + protected void addNotify() { + super.addNotify(); + Case.addEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl); + reloadKeys(); + } + + @Override + protected void removeNotify() { + super.removeNotify(); + Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl); + setKeys(Collections.emptyList()); + } + + @Override + protected Node[] createNodes(DataSource ds) { + return new Node[]{createNodeForKey(ds)}; + } + + protected Node createNodeForKey(DataSource ds) { + return new DataSourceLayerNode(new DataSourceLayerInfo(ds, subTree)); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index 816105d080..ff0837a14a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -61,6 +61,7 @@ import org.sleuthkit.datamodel.TskData; public class DeletedContent implements AutopsyVisitableItem { private SleuthkitCase skCase; + private final long datasourceObjId; @NbBundle.Messages({"DeletedContent.fsDelFilter.text=File System", "DeletedContent.allDelFilter.text=All"}) @@ -101,9 +102,18 @@ public class DeletedContent implements AutopsyVisitableItem { } public DeletedContent(SleuthkitCase skCase) { - this.skCase = skCase; + this(skCase, 0); } + public DeletedContent(SleuthkitCase skCase, long dsObjId) { + this.skCase = skCase; + this.datasourceObjId = dsObjId; + } + + long filteringDataSourceObjId() { + return this.datasourceObjId; + } + @Override public T accept(AutopsyItemVisitor v) { return v.visit(this); @@ -118,8 +128,8 @@ public class DeletedContent implements AutopsyVisitableItem { @NbBundle.Messages("DeletedContent.deletedContentsNode.name=Deleted Files") private static final String NAME = Bundle.DeletedContent_deletedContentsNode_name(); - DeletedContentsNode(SleuthkitCase skCase) { - super(Children.create(new DeletedContentsChildren(skCase), true), Lookups.singleton(NAME)); + DeletedContentsNode(SleuthkitCase skCase, long datasourceObjId) { + super(Children.create(new DeletedContentsChildren(skCase, datasourceObjId), true), Lookups.singleton(NAME)); super.setName(NAME); super.setDisplayName(NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS @@ -164,11 +174,13 @@ public class DeletedContent implements AutopsyVisitableItem { private SleuthkitCase skCase; private Observable notifier; + private final long datasourceObjId; // true if we have already told user that not all files will be shown private static volatile boolean maxFilesDialogShown = false; - public DeletedContentsChildren(SleuthkitCase skCase) { + public DeletedContentsChildren(SleuthkitCase skCase, long dsObjId) { this.skCase = skCase; + this.datasourceObjId = dsObjId; this.notifier = new DeletedContentsChildrenObservable(); } @@ -257,24 +269,27 @@ public class DeletedContent implements AutopsyVisitableItem { @Override protected Node createNodeForKey(DeletedContent.DeletedContentFilter key) { - return new DeletedContentNode(skCase, key, notifier); + return new DeletedContentNode(skCase, key, notifier, datasourceObjId); } public class DeletedContentNode extends DisplayableItemNode { private final DeletedContent.DeletedContentFilter filter; + private final long datasourceObjId; // Use version that has observer for updates @Deprecated - DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter) { - super(Children.create(new DeletedContentChildren(filter, skCase, null), true), Lookups.singleton(filter.getDisplayName())); + DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, long dsObjId) { + super(Children.create(new DeletedContentChildren(filter, skCase, null, dsObjId ), true), Lookups.singleton(filter.getDisplayName())); this.filter = filter; + this.datasourceObjId = dsObjId; init(); } - DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, Observable o) { - super(Children.create(new DeletedContentChildren(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName())); + DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, Observable o, long dsObjId) { + super(Children.create(new DeletedContentChildren(filter, skCase, o, dsObjId), true), Lookups.singleton(filter.getDisplayName())); this.filter = filter; + this.datasourceObjId = dsObjId; init(); o.addObserver(new DeletedContentNodeObserver()); } @@ -299,7 +314,7 @@ public class DeletedContent implements AutopsyVisitableItem { private void updateDisplayName() { //get count of children without preloading all children nodes - final long count = DeletedContentChildren.calculateItems(skCase, filter); + final long count = DeletedContentChildren.calculateItems(skCase, filter, datasourceObjId); //final long count = getChildren().getNodesCount(true); super.setDisplayName(filter.getDisplayName() + " (" + count + ")"); } @@ -351,11 +366,13 @@ public class DeletedContent implements AutopsyVisitableItem { private static final Logger logger = Logger.getLogger(DeletedContentChildren.class.getName()); private static final int MAX_OBJECTS = 10001; private final Observable notifier; + private final long datasourceObjId; - DeletedContentChildren(DeletedContent.DeletedContentFilter filter, SleuthkitCase skCase, Observable o) { + DeletedContentChildren(DeletedContent.DeletedContentFilter filter, SleuthkitCase skCase, Observable o, long datasourceObjId) { this.skCase = skCase; this.filter = filter; this.notifier = o; + this.datasourceObjId = datasourceObjId; } private final Observer observer = new DeletedContentChildrenObserver(); @@ -405,7 +422,7 @@ public class DeletedContent implements AutopsyVisitableItem { return true; } - static private String makeQuery(DeletedContent.DeletedContentFilter filter) { + static private String makeQuery(DeletedContent.DeletedContentFilter filter, long filteringDSObjId) { String query = ""; switch (filter) { case FS_DELETED_FILTER: @@ -443,6 +460,10 @@ public class DeletedContent implements AutopsyVisitableItem { + " OR known IS NULL)"; //NON-NLS } + if (UserPreferences.groupItemsInTreeByDatasource()) { + query += " AND data_source_obj_id = " + filteringDSObjId; + } + query += " LIMIT " + MAX_OBJECTS; //NON-NLS return query; } @@ -450,7 +471,7 @@ public class DeletedContent implements AutopsyVisitableItem { private List runFsQuery() { List ret = new ArrayList<>(); - String query = makeQuery(filter); + String query = makeQuery(filter, datasourceObjId); try { ret = skCase.findAllFilesWhere(query); } catch (TskCoreException e) { @@ -469,9 +490,9 @@ public class DeletedContent implements AutopsyVisitableItem { * * @return */ - static long calculateItems(SleuthkitCase sleuthkitCase, DeletedContent.DeletedContentFilter filter) { + static long calculateItems(SleuthkitCase sleuthkitCase, DeletedContent.DeletedContentFilter filter, long datasourceObjId) { try { - return sleuthkitCase.countFilesWhere(makeQuery(filter)); + return sleuthkitCase.countFilesWhere(makeQuery(filter, datasourceObjId)); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error getting deleted files search view count", ex); //NON-NLS return 0; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 2713992139..de41409c42 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -60,6 +60,8 @@ public interface DisplayableItemNodeVisitor { */ T visit(ViewsNode vn); + T visit(DataSourceLayerNode vn); + T visit(org.sleuthkit.autopsy.datamodel.FileTypesByExtension.FileExtensionNode fsfn); T visit(DeletedContentNode dcn); @@ -307,6 +309,11 @@ public interface DisplayableItemNodeVisitor { return defaultVisit(vn); } + @Override + public T visit(DataSourceLayerNode vn) { + return defaultVisit(vn); + } + @Override public T visit(ResultsNode rn) { return defaultVisit(rn); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java index 0a9321e4d5..a4c27b69f9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java @@ -61,6 +61,7 @@ import org.sleuthkit.datamodel.VirtualDirectory; public class FileSize implements AutopsyVisitableItem { private SleuthkitCase skCase; + private final long datasourceObjId; public enum FileSizeFilter implements AutopsyVisitableItem { @@ -97,9 +98,14 @@ public class FileSize implements AutopsyVisitableItem { } public FileSize(SleuthkitCase skCase) { - this.skCase = skCase; + this(skCase, 0); } + public FileSize(SleuthkitCase skCase, long dsObjId) { + this.skCase = skCase; + this.datasourceObjId = dsObjId; + } + @Override public T accept(AutopsyItemVisitor v) { return v.visit(this); @@ -109,6 +115,9 @@ public class FileSize implements AutopsyVisitableItem { return this.skCase; } + long filteringDataSourceObjId() { + return this.datasourceObjId; + } /* * Root node. Children are nodes for specific sizes. */ @@ -116,8 +125,8 @@ public class FileSize implements AutopsyVisitableItem { private static final String NAME = NbBundle.getMessage(FileSize.class, "FileSize.fileSizeRootNode.name"); - FileSizeRootNode(SleuthkitCase skCase) { - super(Children.create(new FileSizeRootChildren(skCase), true), Lookups.singleton(NAME)); + FileSizeRootNode(SleuthkitCase skCase, long datasourceObjId) { + super(Children.create(new FileSizeRootChildren(skCase, datasourceObjId), true), Lookups.singleton(NAME)); super.setName(NAME); super.setDisplayName(NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-size-16.png"); //NON-NLS @@ -161,10 +170,12 @@ public class FileSize implements AutopsyVisitableItem { public static class FileSizeRootChildren extends ChildFactory { private SleuthkitCase skCase; + private long datasourceObjId; private Observable notifier; - public FileSizeRootChildren(SleuthkitCase skCase) { + public FileSizeRootChildren(SleuthkitCase skCase, long datasourceObjId) { this.skCase = skCase; + this.datasourceObjId = datasourceObjId; notifier = new FileSizeRootChildrenObservable(); } @@ -248,7 +259,7 @@ public class FileSize implements AutopsyVisitableItem { @Override protected Node createNodeForKey(FileSizeFilter key) { - return new FileSizeNode(skCase, key, notifier); + return new FileSizeNode(skCase, key, notifier, datasourceObjId); } /* @@ -257,12 +268,14 @@ public class FileSize implements AutopsyVisitableItem { public class FileSizeNode extends DisplayableItemNode { private FileSizeFilter filter; + private final long datasourceObjId; // use version with observer instead so that it updates @Deprecated - FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter) { - super(Children.create(new FileSizeChildren(filter, skCase, null), true), Lookups.singleton(filter.getDisplayName())); + FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, long datasourceObjId) { + super(Children.create(new FileSizeChildren(filter, skCase, null, datasourceObjId), true), Lookups.singleton(filter.getDisplayName())); this.filter = filter; + this.datasourceObjId = datasourceObjId; init(); } @@ -272,10 +285,12 @@ public class FileSize implements AutopsyVisitableItem { * @param filter * @param o Observable that provides updates when events are * fired + * @param datasourceObjId filter by data source, if configured in user preferences */ - FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, Observable o) { - super(Children.create(new FileSizeChildren(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName())); + FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, Observable o, long datasourceObjId) { + super(Children.create(new FileSizeChildren(filter, skCase, o, datasourceObjId), true), Lookups.singleton(filter.getDisplayName())); this.filter = filter; + this.datasourceObjId = datasourceObjId; init(); o.addObserver(new FileSizeNodeObserver()); } @@ -309,7 +324,7 @@ public class FileSize implements AutopsyVisitableItem { } private void updateDisplayName() { - final long numVisibleChildren = FileSizeChildren.calculateItems(skCase, filter); + final long numVisibleChildren = FileSizeChildren.calculateItems(skCase, filter, datasourceObjId); super.setDisplayName(filter.getDisplayName() + " (" + numVisibleChildren + ")"); } @@ -349,6 +364,7 @@ public class FileSize implements AutopsyVisitableItem { private final SleuthkitCase skCase; private final FileSizeFilter filter; private final Observable notifier; + private final long datasourceObjId; private static final Logger logger = Logger.getLogger(FileSizeChildren.class.getName()); /** @@ -358,10 +374,12 @@ public class FileSize implements AutopsyVisitableItem { * @param o Observable that provides updates when new files are * added to case */ - FileSizeChildren(FileSizeFilter filter, SleuthkitCase skCase, Observable o) { + FileSizeChildren(FileSizeFilter filter, SleuthkitCase skCase, Observable o, long dsObjId) { this.skCase = skCase; this.filter = filter; this.notifier = o; + this.datasourceObjId = dsObjId; + } @Override @@ -395,7 +413,7 @@ public class FileSize implements AutopsyVisitableItem { return true; } - private static String makeQuery(FileSizeFilter filter) { + private static String makeQuery(FileSizeFilter filter, long filteringDSObjId) { String query; switch (filter) { case SIZE_50_200: @@ -427,6 +445,11 @@ public class FileSize implements AutopsyVisitableItem { query += " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType() + ")"; //NON-NLS } + // filter by datasource if indicated in user preferences + if (UserPreferences.groupItemsInTreeByDatasource()) { + query += " AND data_source_obj_id = " + filteringDSObjId; + } + return query; } @@ -434,7 +457,7 @@ public class FileSize implements AutopsyVisitableItem { List ret = new ArrayList<>(); try { - String query = makeQuery(filter); + String query = makeQuery(filter, datasourceObjId); ret = skCase.findAllFilesWhere(query); } catch (Exception e) { @@ -449,9 +472,9 @@ public class FileSize implements AutopsyVisitableItem { * * @return */ - static long calculateItems(SleuthkitCase sleuthkitCase, FileSizeFilter filter) { + static long calculateItems(SleuthkitCase sleuthkitCase, FileSizeFilter filter, long datasourceObjId) { try { - return sleuthkitCase.countFilesWhere(makeQuery(filter)); + return sleuthkitCase.countFilesWhere(makeQuery(filter, datasourceObjId)); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error getting files by size search view count", ex); //NON-NLS return 0; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java index 53822532bb..49f63749d1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java @@ -72,11 +72,18 @@ public final class FileTypes implements AutopsyVisitableItem { private final SleuthkitCase skCase; + private final long datasourceObjId; + FileTypes(SleuthkitCase skCase) { - this.skCase = skCase; - updateShowCounts(); + this(skCase, 0); } + FileTypes(SleuthkitCase skCase, long dsObjId) { + this.skCase = skCase; + this.datasourceObjId = dsObjId; + updateShowCounts(); + } + @Override public T accept(AutopsyItemVisitor v) { return v.visit(this); @@ -86,6 +93,9 @@ public final class FileTypes implements AutopsyVisitableItem { return skCase; } + long filteringDataSourceObjId() { + return this.datasourceObjId; + } /** * Check the db to determine if the nodes should show child counts. */ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index 2d8cc564d2..342763a57b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -69,6 +69,10 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { return v.visit(this); } + long filteringDataSourceObjId() { + return typesRoot.filteringDataSourceObjId(); + } + /** * Listens for case and ingest invest. Updates observers when events are * fired. FileType and FileTypes nodes are all listening to this. @@ -153,7 +157,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { * @param o Observable that was created by a higher-level node that * provides updates on events */ - private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o) { + private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o /*, long datasourceObjId */) { super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, o), true), Lookups.singleton(filter == null ? FNAME : filter.getDisplayName())); @@ -359,6 +363,9 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { + (UserPreferences.hideKnownFilesInViewsTree() ? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")" : " ") + + (UserPreferences.groupItemsInTreeByDatasource() + ? " AND data_source_obj_id = " + FileTypesByExtension.this.filteringDataSourceObjId() + : " ") + " AND (extension IN (" + filter.getFilter().stream() .map(String::toLowerCase) .map(s -> "'"+StringUtils.substringAfter(s, ".")+"'") diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java index e7af90fab7..379b790cd6 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java @@ -42,6 +42,7 @@ import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.core.UserPreferences; import static org.sleuthkit.autopsy.core.UserPreferences.hideKnownFilesInViewsTree; import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTree; import org.sleuthkit.autopsy.coreutils.Logger; @@ -91,15 +92,16 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi * @return The base expression to be used in the where clause of queries for * files by mime type. */ - static private String createBaseWhereExpr() { + private String createBaseWhereExpr() { return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")" + " AND (type IN (" + TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + "," + TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + "," + TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + "," + TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal() - + (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal())) + + (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal())) + "))" + + ( UserPreferences.groupItemsInTreeByDatasource() ? " AND data_source_obj_id = " + this.filteringDataSourceObjId() : " ") + (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : ""); } @@ -188,6 +190,10 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi return v.visit(this); } + long filteringDataSourceObjId() { + return typesRoot.filteringDataSourceObjId(); + } + /** * Method to check if the node in question is a ByMimeTypeNode which is * empty. diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java index 9d1f0e0d63..da907c37b8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2014 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +22,8 @@ import java.util.Arrays; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.datamodel.DataSourcesLayerChildren.SubtreeEnum; import org.sleuthkit.datamodel.SleuthkitCase; /** @@ -34,14 +36,19 @@ public class ViewsNode extends DisplayableItemNode { public static final String NAME = NbBundle.getMessage(ViewsNode.class, "ViewsNode.name.text"); public ViewsNode(SleuthkitCase sleuthkitCase) { - super(new RootContentChildren(Arrays.asList( - new FileTypes(sleuthkitCase), - // June '15: Recent Files was removed because it was not useful w/out filtering - // add it back in if we can filter the results to a more managable size. - // new RecentFiles(sleuthkitCase), - new DeletedContent(sleuthkitCase), - new FileSize(sleuthkitCase))), - Lookups.singleton(NAME)); + + super( UserPreferences.groupItemsInTreeByDatasource() ? + new DataSourcesLayerChildren(sleuthkitCase, SubtreeEnum.VIEWS) : + new RootContentChildren(Arrays.asList( + new FileTypes(sleuthkitCase), + // June '15: Recent Files was removed because it was not useful w/out filtering + // add it back in if we can filter the results to a more managable size. + // new RecentFiles(sleuthkitCase), + new DeletedContent(sleuthkitCase), + new FileSize(sleuthkitCase)) + ), + Lookups.singleton(NAME) + ); setName(NAME); setDisplayName(NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/views.png"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties index 647c6f70d3..0e7f3cf315 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties @@ -119,3 +119,4 @@ AddExternalViewerRulePanel.browseButton.text=Browse AddExternalViewerRulePanel.exePathTextField.text= AddExternalViewerRulePanel.exePathLabel.text=Path of the program to use for files with this type or extension AddExternalViewerRulePanel.extRadioButton.text=Extension +DirectoryTreeTopComponent.groupByDatasourceCheckBox.text=Group by Data Source diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form index 90c6ac00a6..48dfad0bb6 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.form @@ -16,14 +16,17 @@ - - - + + + - - + + + + + @@ -31,14 +34,23 @@ - - - - - + + + + + + + + + + + + + + - - + + @@ -130,5 +142,15 @@ + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 13219f863d..00f2c6a110 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -141,6 +141,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat switch (evt.getKey()) { case UserPreferences.HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE: case UserPreferences.HIDE_SLACK_FILES_IN_DATA_SRCS_TREE: + case UserPreferences.GROUP_ITEMS_IN_TREE_BY_DATASOURCE: refreshContentTreeSafe(); break; case UserPreferences.HIDE_KNOWN_FILES_IN_VIEWS_TREE: @@ -181,6 +182,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat backButton = new javax.swing.JButton(); forwardButton = new javax.swing.JButton(); showRejectedCheckBox = new javax.swing.JCheckBox(); + groupByDatasourceCheckBox = new javax.swing.JCheckBox(); treeView.setBorder(null); @@ -218,30 +220,45 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat org.openide.awt.Mnemonics.setLocalizedText(showRejectedCheckBox, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.showRejectedCheckBox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(groupByDatasourceCheckBox, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.groupByDatasourceCheckBox.text")); // NOI18N + groupByDatasourceCheckBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + groupByDatasourceCheckBoxActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE) + .addComponent(treeView) .addGroup(layout.createSequentialGroup() - .addGap(5, 5, 5) + .addContainerGap() .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0) .addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 46, Short.MAX_VALUE) - .addComponent(showRejectedCheckBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 65, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(showRejectedCheckBox) + .addComponent(groupByDatasourceCheckBox)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(5, 5, 5) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(showRejectedCheckBox)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(5, 5, 5) + .addComponent(showRejectedCheckBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(groupByDatasourceCheckBox)) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 854, Short.MAX_VALUE) + .addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 838, Short.MAX_VALUE) .addGap(0, 0, 0)) ); }// //GEN-END:initComponents @@ -295,9 +312,14 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat this.setCursor(null); }//GEN-LAST:event_forwardButtonActionPerformed + private void groupByDatasourceCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_groupByDatasourceCheckBoxActionPerformed + UserPreferences.setGroupItemsInTreeByDatasource(this.groupByDatasourceCheckBox.isSelected()); + }//GEN-LAST:event_groupByDatasourceCheckBoxActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton backButton; private javax.swing.JButton forwardButton; + private javax.swing.JCheckBox groupByDatasourceCheckBox; private javax.swing.JCheckBox showRejectedCheckBox; private javax.swing.JScrollPane treeView; // End of variables declaration//GEN-END:variables @@ -429,6 +451,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat showRejectedCheckBox.setAction(accounts.newToggleShowRejectedAction()); showRejectedCheckBox.setSelected(false); + groupByDatasourceCheckBox.setSelected(UserPreferences.groupItemsInTreeByDatasource()); + Node views = rootChildren.findChild(ViewsNode.NAME); Arrays.stream(views.getChildren().getNodes()).forEach(tree::expandNode); tree.collapseNode(views); @@ -772,7 +796,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * Refresh the content node part of the dir tree safely in the EDT thread */ public void refreshContentTreeSafe() { - SwingUtilities.invokeLater(this::refreshDataSourceTree); + SwingUtilities.invokeLater(this::refreshTree); } /** @@ -793,6 +817,18 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat setSelectedNode(selectedPath, DataSourcesNode.NAME); } + /** + * Refreshes the entire tree + */ + private void refreshTree() { + Node selectedNode = getSelectedNode(); + final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext()); + + contentChildren.refreshContentKeys(); + + setSelectedNode(selectedPath, DataSourcesNode.NAME); + } + /** * Set the selected node using a path to a previously selected node. * From 3f01e351c2b3842967239afc051621596936e0f4 Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 27 Apr 2018 11:29:13 -0400 Subject: [PATCH 02/29] 3757: Group views in the case tree by data source - Removed commented code. --- .../org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index 451c32f09b..b4dd903e83 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -157,7 +157,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { * @param o Observable that was created by a higher-level node that * provides updates on events */ - private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o /*, long datasourceObjId */) { + private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o) { super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, o), true), Lookups.singleton(filter == null ? FNAME : filter.getDisplayName())); From 97df1d2c215d66648529399eb535392511eba890 Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 27 Apr 2018 13:36:48 -0400 Subject: [PATCH 03/29] Addressed Codacy comments. --- Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java | 2 +- .../org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java index 83cbde398e..f1871c46bf 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java @@ -170,7 +170,7 @@ public class FileSize implements AutopsyVisitableItem { public static class FileSizeRootChildren extends ChildFactory { private SleuthkitCase skCase; - private long datasourceObjId; + private final long datasourceObjId; private Observable notifier; public FileSizeRootChildren(SleuthkitCase skCase, long datasourceObjId) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index b4dd903e83..4689dd515a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -364,7 +364,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { ? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")" : " ") + (UserPreferences.groupItemsInTreeByDatasource() - ? " AND data_source_obj_id = " + FileTypesByExtension.this.filteringDataSourceObjId() + ? " AND data_source_obj_id = " + filteringDataSourceObjId() : " ") + " AND (extension IN (" + filter.getFilter().stream() .map(String::toLowerCase) From 05c41132f80904101324e63f91f87eb8c1f987c3 Mon Sep 17 00:00:00 2001 From: Raman Date: Wed, 2 May 2018 08:27:07 -0400 Subject: [PATCH 04/29] Group Results tree by Datasource. Interim commit to save the partial work. Some of this will need to be fixed for Vik-3802 --- .../datamodel/DataSourceLayerNode.java | 9 ++++++ .../autopsy/datamodel/ExtractedContent.java | 30 +++++++++++++++++-- .../autopsy/datamodel/ResultsNode.java | 21 ++++++++----- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceLayerNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceLayerNode.java index 9573597d5a..95eb015c09 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceLayerNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceLayerNode.java @@ -26,6 +26,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.DataSourcesLayerChildren.SubtreeEnum; +import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.LocalFilesDataSource; @@ -87,6 +88,14 @@ public class DataSourceLayerNode extends DisplayableItemNode { ); case RESULTS: // TBD: + return new RootContentChildren(Arrays.asList( + new ExtractedContent(Case.getOpenCase().getSleuthkitCase()), + new KeywordHits(Case.getOpenCase().getSleuthkitCase()), + new HashsetHits(Case.getOpenCase().getSleuthkitCase()), + new EmailExtracted(Case.getOpenCase().getSleuthkitCase()), + new InterestingHits(Case.getOpenCase().getSleuthkitCase()), + new Accounts(Case.getOpenCase().getSleuthkitCase()) + )); case TAGS: // TBD: case REPORTS: // TBD: diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index f6b25ad2ba..054f0eea16 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -35,6 +35,7 @@ import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -58,11 +59,28 @@ public class ExtractedContent implements AutopsyVisitableItem { private SleuthkitCase skCase; // set to null after case has been closed public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text"); + private final long datasourceObjId; + /** + * Constructs extracted content object + * + * @param skCase Case DB + */ public ExtractedContent(SleuthkitCase skCase) { - this.skCase = skCase; + this(skCase, 0); } + /** + * Constructs extracted content object + * + * @param skCase Case DB + * @param objId Object id of the parent datasource + */ + public ExtractedContent(SleuthkitCase skCase, long objId) { + this.skCase = skCase; + this.datasourceObjId = objId; + } + @Override public T accept(AutopsyItemVisitor visitor) { return visitor.visit(this); @@ -270,6 +288,7 @@ public class ExtractedContent implements AutopsyVisitableItem { //TEST COMMENT if (skCase != null) { try { + // RAMAN TBD: filter on datasource obj id List types = skCase.getArtifactTypesInUse(); types.removeAll(doNotShow); Collections.sort(types, @@ -332,7 +351,9 @@ public class ExtractedContent implements AutopsyVisitableItem { // a performance increase might be had by adding a // "getBlackboardArtifactCount()" method to skCase try { - this.childCount = skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); + this.childCount = UserPreferences.groupItemsInTreeByDatasource() ? + skCase.getBlackboardArtifactsCount(type.getTypeID(), datasourceObjId) : + skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); } catch (TskException ex) { Logger.getLogger(TypeNode.class.getName()) .log(Level.WARNING, "Error getting child count", ex); //NON-NLS @@ -454,7 +475,10 @@ public class ExtractedContent implements AutopsyVisitableItem { protected boolean createKeys(List list) { if (skCase != null) { try { - List arts = skCase.getBlackboardArtifacts(type.getTypeID()); + List arts = + UserPreferences.groupItemsInTreeByDatasource() ? + skCase.getBlackboardArtifacts(TSK_ACCOUNT, datasourceObjId) : + skCase.getBlackboardArtifacts(type.getTypeID()); list.addAll(arts); } catch (TskException ex) { Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java index 87a3d5f903..cb192ced64 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java @@ -23,6 +23,8 @@ import java.util.Arrays; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.datamodel.DataSourcesLayerChildren.SubtreeEnum; import org.sleuthkit.datamodel.SleuthkitCase; /** @@ -36,14 +38,17 @@ public class ResultsNode extends DisplayableItemNode { public ResultsNode(SleuthkitCase sleuthkitCase) { - super(new RootContentChildren(Arrays.asList( - new ExtractedContent(sleuthkitCase), - new KeywordHits(sleuthkitCase), - new HashsetHits(sleuthkitCase), - new EmailExtracted(sleuthkitCase), - new InterestingHits(sleuthkitCase), - new Accounts(sleuthkitCase) - )), Lookups.singleton(NAME)); + super(UserPreferences.groupItemsInTreeByDatasource() ? + new DataSourcesLayerChildren(sleuthkitCase, SubtreeEnum.RESULTS) : + new RootContentChildren(Arrays.asList( + new ExtractedContent(sleuthkitCase), + new KeywordHits(sleuthkitCase), + new HashsetHits(sleuthkitCase), + new EmailExtracted(sleuthkitCase), + new InterestingHits(sleuthkitCase), + new Accounts(sleuthkitCase) ) + ), + Lookups.singleton(NAME)); setName(NAME); setDisplayName(NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png"); //NON-NLS From 8b92a52b1b408d2f9118eeaaa662ad79d4bcbc10 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 10 May 2018 08:45:45 -0400 Subject: [PATCH 05/29] 3802: Group by datasource Build the top level tree using new RootContentChildrenFactory --- .../datamodel/AbstractContentChildren.java | 11 +- .../autopsy/datamodel/AutopsyItemVisitor.java | 7 + .../autopsy/datamodel/Bundle.properties | 2 +- .../autopsy/datamodel/DataSourceGrouping.java | 52 ++++++ ...n.java => DataSourceGroupingChildren.java} | 59 ++----- .../datamodel/DataSourceGroupingNode.java | 99 +++++++++++ .../datamodel/DataSourceLayerNode.java | 123 -------------- .../autopsy/datamodel/DataSources.java | 11 ++ .../autopsy/datamodel/DataSourcesNode.java | 38 ++++- .../autopsy/datamodel/DeletedContent.java | 2 +- .../datamodel/DisplayableItemNodeVisitor.java | 6 +- .../autopsy/datamodel/ResultsNode.java | 12 +- .../datamodel/RootContentChildrenFactory.java | 158 ++++++++++++++++++ .../sleuthkit/autopsy/datamodel/Views.java | 12 +- .../autopsy/datamodel/ViewsNode.java | 15 +- .../autoingest/AutoIngestManager.java | 2 +- 16 files changed, 409 insertions(+), 200 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGrouping.java rename Core/src/org/sleuthkit/autopsy/datamodel/{DataSourcesLayerChildren.java => DataSourceGroupingChildren.java} (66%) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java delete mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/DataSourceLayerNode.java create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index 25da96db78..e300efdf1b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -192,21 +192,28 @@ abstract class AbstractContentChildren extends Keys { @Override public AbstractNode visit(Tags tagsNodeKey) { + // RAMAN TBD: pass dsObjID down here return tagsNodeKey.new RootNode(); } @Override public AbstractNode visit(DataSources i) { - return new DataSourcesNode(); + return new DataSourcesNode(i.filteringDataSourceObjId()); } + @Override + public AbstractNode visit(DataSourceGrouping datasourceGrouping) { + return new DataSourceGroupingNode(datasourceGrouping.getgDataSource()); + } + @Override public AbstractNode visit(Views v) { - return new ViewsNode(v.getSleuthkitCase()); + return new ViewsNode(v.getSleuthkitCase(), v.filteringDataSourceObjId()); } @Override public AbstractNode visit(Results r) { + // RAMAN TBD: pass dsObjID down here return new ResultsNode(r.getSleuthkitCase()); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java index 2dcc5942db..29843bccb7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java @@ -28,6 +28,8 @@ import org.sleuthkit.autopsy.datamodel.accounts.Accounts; public interface AutopsyItemVisitor { T visit(DataSources i); + + T visit(DataSourceGrouping datasourceGrouping); T visit(Views v); @@ -173,6 +175,11 @@ public interface AutopsyItemVisitor { return defaultVisit(v); } + @Override + public T visit(DataSourceGrouping datasourceGrouping) { + return defaultVisit(datasourceGrouping); + } + @Override public T visit(Results r) { return defaultVisit(r); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index 733c49e8b7..f392d406d3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -55,7 +55,7 @@ DataModelActionsFactory.fileInDir.text=View File in Directory DataModelActionsFactory.viewNewWin.text=View in New Window DataModelActionsFactory.openExtViewer.text=Open in External Viewer DataModelActionsFactory.srfFileSameMD5.text=Search for files with the same MD5 hash -DataSourcesNode.name=Data Sources +DataSourcesNode.name=Data Source Files DataSourcesNode.createSheet.name.name=Name DataSourcesNode.createSheet.name.displayName=Name DataSourcesNode.createSheet.name.desc=no description diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGrouping.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGrouping.java new file mode 100644 index 0000000000..360ee735ce --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGrouping.java @@ -0,0 +1,52 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 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.datamodel.DataSource; +import org.sleuthkit.datamodel.SleuthkitCase; + +/** + * A top level UI grouping of Files, Views, Results, Tags + * for 'Group by Data Source' view of the tree. + * + */ +public class DataSourceGrouping implements AutopsyVisitableItem { + + private final SleuthkitCase skCase; + private final DataSource dataSource; + + public DataSourceGrouping(SleuthkitCase skCase, DataSource dataSource) { + this.skCase = skCase; + this.dataSource = dataSource; + } + + DataSource getgDataSource() { + return this.dataSource; + } + + @Override + public T accept(AutopsyItemVisitor visitor) { + return visitor.visit(this); + } + + public SleuthkitCase getSleuthkitCase() { + return skCase; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesLayerChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingChildren.java similarity index 66% rename from Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesLayerChildren.java rename to Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingChildren.java index 95513b3b97..1b7d969100 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesLayerChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingChildren.java @@ -33,62 +33,29 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; /** - * Child factory for DataSource node layer in the Results, Views Tags subtrees + * Child factory for Data Source grouping nodes + * A node is created for each data source in the case * */ -class DataSourcesLayerChildren extends Children.Keys { +public class DataSourceGroupingChildren extends Children.Keys { - private static final Logger logger = Logger.getLogger(DataSourcesLayerChildren.class.getName()); + private static final Logger logger = Logger.getLogger(DataSourceGroupingChildren.class.getName()); private final SleuthkitCase sleuthkitCase; - private final SubtreeEnum subTree; + + /** - * Subtree in which this DataSourcesLayerChildren exist - */ - public enum SubtreeEnum { - VIEWS, - RESULTS, - TAGS, - REPORTS - } - - /** - * Simple wrapper class to pass Datasource and subtree down to children nodes + * Constructs the factory object * + * @param tskCase - Case DB */ - class DataSourceLayerInfo { - - private final DataSource dataSource; - private final SubtreeEnum subTree; - - DataSourceLayerInfo(DataSource dataSource, SubtreeEnum subTree) { - this.dataSource = dataSource; - this.subTree = subTree; - } - - DataSource getDataSource() { - return this.dataSource; - } - - SubtreeEnum getSubtree() { - return this.subTree; - } - } - - /** - * Constructs the factory to create optional datasource nodes - * - * @param tskCase - Case DB - * @param subTree - subtree under which data source nodes are to be created - */ - public DataSourcesLayerChildren(SleuthkitCase tskCase, SubtreeEnum subTree) { - // super(true); - super(false); - + public DataSourceGroupingChildren(SleuthkitCase tskCase) { this.sleuthkitCase = tskCase; - this.subTree = subTree; } + /** + * Listener for handling DATA_SOURCE_ADDED events. + */ private final PropertyChangeListener pcl = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { @@ -128,7 +95,7 @@ class DataSourcesLayerChildren extends Children.Keys { } protected Node createNodeForKey(DataSource ds) { - return new DataSourceLayerNode(new DataSourceLayerInfo(ds, subTree)); + return new DataSourceGroupingNode(ds); } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java new file mode 100644 index 0000000000..2b6f2d0e1f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java @@ -0,0 +1,99 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 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 java.util.Arrays; +import java.util.Collections; +import java.util.Optional; +import java.util.logging.Level; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.coreutils.Logger; +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 + * + */ +public class DataSourceGroupingNode extends DisplayableItemNode { + + private static final Logger logger = Logger.getLogger(DataSourceGroupingNode.class.getName()); + + /** + * Creates the 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)))); + + if (dataSource instanceof Image) { + Image image = (Image) dataSource; + + super.setName(image.getName()); + super.setDisplayName(image.getName()); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png"); + } else if (dataSource instanceof LocalFilesDataSource) { + LocalFilesDataSource localFilesDataSource = (LocalFilesDataSource) dataSource; + + super.setName(localFilesDataSource.getName()); + super.setDisplayName(localFilesDataSource.getName()); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); + } + + } + + @Override + public boolean isLeafTypeNode() { + return false; + } + + private static RootContentChildren createDSGroupingNodeChildren(DataSource dataSource) { + + long dsObjId = dataSource.getId(); + try { + return new RootContentChildren(Arrays.asList( + new DataSources(dsObjId), + new Views(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId), + new Results(Case.getCurrentCaseThrows().getSleuthkitCase()), // RAMAN TBD: pass down dsObjId + new Tags() ) // RAMAN TBD: pass down dsObjId + + ); + + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Error getting open case.", ex); //NON-NLS + return null; + } + } + + @Override + public T accept(DisplayableItemNodeVisitor visitor) { + return visitor.visit(this); + } + + @Override + public String getItemType() { + return getClass().getName(); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceLayerNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceLayerNode.java deleted file mode 100644 index 95eb015c09..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceLayerNode.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 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 java.util.Arrays; -import java.util.Collections; -import java.util.Optional; -import java.util.logging.Level; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.DataSourcesLayerChildren.SubtreeEnum; -import org.sleuthkit.autopsy.datamodel.accounts.Accounts; -import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.Image; -import org.sleuthkit.datamodel.LocalFilesDataSource; - - -/** - * Datasource layer node - an optional grouping node in the data tree view - * - */ -public class DataSourceLayerNode extends DisplayableItemNode { - - private static final Logger logger = Logger.getLogger(DataSourceLayerNode.class.getName()); - - /** - * Creates the Datasource node for the given data source, - * and initializes the children nodes under it based on the subtree specified - * - * @param dataSourceLayerInfo specifies the - */ - DataSourceLayerNode(DataSourcesLayerChildren.DataSourceLayerInfo dataSourceLayerInfo) { - - super (Optional.ofNullable(createDSLayerNodeChildren(dataSourceLayerInfo)) - .orElse(new RootContentChildren(Arrays.asList(Collections.EMPTY_LIST)))); - - DataSource dataSource = dataSourceLayerInfo.getDataSource(); - if (dataSource instanceof Image) { - Image image = (Image) dataSource; - - super.setName(image.getName()); - super.setDisplayName(image.getName()); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png"); - } else if (dataSource instanceof LocalFilesDataSource) { - LocalFilesDataSource localFilesDataSource = (LocalFilesDataSource) dataSource; - - super.setName(localFilesDataSource.getName()); - super.setDisplayName(localFilesDataSource.getName()); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); - } - - } - - @Override - public boolean isLeafTypeNode() { - return false; - } - - private static RootContentChildren createDSLayerNodeChildren(DataSourcesLayerChildren.DataSourceLayerInfo dataSourceLayerInfo) { - - SubtreeEnum subtree = dataSourceLayerInfo.getSubtree(); - long dsObjId = dataSourceLayerInfo.getDataSource().getId(); - - try { - switch (subtree) { - case VIEWS: - return new RootContentChildren(Arrays.asList( - new FileTypes(Case.getOpenCase().getSleuthkitCase(), dsObjId), - new DeletedContent(Case.getOpenCase().getSleuthkitCase(), dsObjId), - new FileSize(Case.getOpenCase().getSleuthkitCase(), dsObjId)) - ); - - case RESULTS: // TBD: - return new RootContentChildren(Arrays.asList( - new ExtractedContent(Case.getOpenCase().getSleuthkitCase()), - new KeywordHits(Case.getOpenCase().getSleuthkitCase()), - new HashsetHits(Case.getOpenCase().getSleuthkitCase()), - new EmailExtracted(Case.getOpenCase().getSleuthkitCase()), - new InterestingHits(Case.getOpenCase().getSleuthkitCase()), - new Accounts(Case.getOpenCase().getSleuthkitCase()) - )); - case TAGS: // TBD: - case REPORTS: // TBD: - - default: - { - logger.log(Level.SEVERE, "Unknown subtree type " + subtree.name()); //NON-NLS - return null; - } - } - } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Error getting open case.", ex); //NON-NLS - return null; - } - } - - @Override - public T accept(DisplayableItemNodeVisitor visitor) { - return visitor.visit(this); - } - - @Override - public String getItemType() { - return getClass().getName(); - } -} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java index 5f8cbfff54..52ca52e89f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java @@ -23,9 +23,20 @@ package org.sleuthkit.autopsy.datamodel; */ public class DataSources implements AutopsyVisitableItem { + private final long datasourceObjId; + public DataSources() { + this(0); } + public DataSources(long datasourceObjId) { + this.datasourceObjId = datasourceObjId; + } + + long filteringDataSourceObjId() { + return this.datasourceObjId; + } + @Override public T accept(AutopsyItemVisitor visitor) { return visitor.visit(this); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index 6e8374252d..68f92b8f4e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.List; @@ -33,6 +34,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskDataException; /** * Nodes for the images @@ -41,18 +43,24 @@ public class DataSourcesNode extends DisplayableItemNode { public static final String NAME = NbBundle.getMessage(DataSourcesNode.class, "DataSourcesNode.name"); + private final long datasourceObjId; + // NOTE: The images passed in via argument will be ignored. @Deprecated public DataSourcesNode(List images) { - super(new DataSourcesNodeChildren(), Lookups.singleton(NAME)); - init(); + this(0); } public DataSourcesNode() { - super(new DataSourcesNodeChildren(), Lookups.singleton(NAME)); - init(); + this(0); } + public DataSourcesNode(long dsObjId) { + super(new DataSourcesNodeChildren(dsObjId), Lookups.singleton(NAME)); + init(); + this.datasourceObjId = dsObjId; + } + private void init() { setName(NAME); setDisplayName(NAME); @@ -70,14 +78,20 @@ public class DataSourcesNode extends DisplayableItemNode { public static class DataSourcesNodeChildren extends AbstractContentChildren { private static final Logger logger = Logger.getLogger(DataSourcesNodeChildren.class.getName()); - + private final long datasourceObjId; + List currentKeys; public DataSourcesNodeChildren() { - super(); - this.currentKeys = new ArrayList<>(); + this(0); } + public DataSourcesNodeChildren(long dsObjId) { + super(); + this.currentKeys = new ArrayList<>(); + this.datasourceObjId = dsObjId; + } + private final PropertyChangeListener pcl = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { @@ -103,9 +117,15 @@ public class DataSourcesNode extends DisplayableItemNode { private void reloadKeys() { try { - currentKeys = Case.getCurrentCaseThrows().getDataSources(); + if (datasourceObjId == 0) { + currentKeys = Case.getCurrentCaseThrows().getDataSources(); + } + else { + Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getDataSource(datasourceObjId); + currentKeys = new ArrayList<>(Arrays.asList(content)); + } setKeys(currentKeys); - } catch (TskCoreException | NoCurrentCaseException ex) { + } catch (TskCoreException | NoCurrentCaseException | TskDataException ex) { logger.log(Level.SEVERE, "Error getting data sources: {0}", ex.getMessage()); // NON-NLS setKeys(Collections.emptySet()); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index ca1dc0063c..370cc5cec7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -383,7 +383,7 @@ public class DeletedContent implements AutopsyVisitableItem { @Override public void update(Observable o, Object arg) { refresh(true); - } + } } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index f633112888..0392614fe3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -61,7 +61,7 @@ public interface DisplayableItemNodeVisitor { */ T visit(ViewsNode vn); - T visit(DataSourceLayerNode vn); + T visit(DataSourceGroupingNode dataSourceGroupingNode); T visit(org.sleuthkit.autopsy.datamodel.FileTypesByExtension.FileExtensionNode fsfn); @@ -339,8 +339,8 @@ public interface DisplayableItemNodeVisitor { } @Override - public T visit(DataSourceLayerNode vn) { - return defaultVisit(vn); + public T visit(DataSourceGroupingNode dataSourceGroupingNode) { + return defaultVisit(dataSourceGroupingNode); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java index cb192ced64..6fcd9a540c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java @@ -23,8 +23,6 @@ import java.util.Arrays; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; -import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.datamodel.DataSourcesLayerChildren.SubtreeEnum; import org.sleuthkit.datamodel.SleuthkitCase; /** @@ -35,11 +33,13 @@ public class ResultsNode extends DisplayableItemNode { @NbBundle.Messages("ResultsNode.name.text=Results") public static final String NAME = Bundle.ResultsNode_name_text(); - - public ResultsNode(SleuthkitCase sleuthkitCase) { - super(UserPreferences.groupItemsInTreeByDatasource() ? - new DataSourcesLayerChildren(sleuthkitCase, SubtreeEnum.RESULTS) : + this(sleuthkitCase, 0); + } + + public ResultsNode(SleuthkitCase sleuthkitCase, long dsObjId) { + super( + // RAMAN TBD: pass down dsObjId to each of these subnodes new RootContentChildren(Arrays.asList( new ExtractedContent(sleuthkitCase), new KeywordHits(sleuthkitCase), diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java new file mode 100644 index 0000000000..5adbb8c826 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java @@ -0,0 +1,158 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 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 java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Observable; +import java.util.Observer; +import java.util.Set; +import java.util.logging.Level; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Node; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.SleuthkitVisitableItem; +import org.sleuthkit.datamodel.TskCoreException; + + +/** + * Child factory to create the top level children of the root of the directory tree + * + */ +public class RootContentChildrenFactory extends ChildFactory.Detachable implements Observer { + + private static final Logger logger = Logger.getLogger(RootContentChildrenFactory.class.getName()); + private final SleuthkitCase tskCase; + + + /** + * Constructs the child factory for root nodes + * @param tskCase + */ + public RootContentChildrenFactory(SleuthkitCase tskCase) { + this.tskCase = tskCase; + + } + + /** + * Listener for handling DATA_SOURCE_ADDED events. + */ + private final PropertyChangeListener pcl = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + String eventType = evt.getPropertyName(); + if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { + refreshChildren(); + } + } + }; + + @Override + protected void addNotify() { + super.addNotify(); + Case.addEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl); + } + + @Override + protected void removeNotify() { + super.removeNotify(); + Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl); + } + + @Override + public void update(Observable o, Object arg) { + refresh(true); + } + + + + + + /** + * Creates keys for the top level children. + * + * @param list list of keys created + */ + @Override + protected boolean createKeys(List list) { + + try { + if (UserPreferences.groupItemsInTreeByDatasource()) { + List dataSources = tskCase.getDataSources(); + List keys = new ArrayList<>(); + dataSources.forEach((ds) -> { + keys.add(new DataSourceGrouping(tskCase, ds)); + }); + + list.addAll(keys); + } else { + + List keys = new ArrayList<>(Arrays.asList( + new DataSources(), + new Views(tskCase), + new Results(tskCase), + new Tags(), + new Reports())); + + list.addAll(keys); + } + + } catch (TskCoreException tskCoreException) { + logger.log(Level.SEVERE, "Error getting datas sources list form the database.", tskCoreException); + } + return true; + } + + /** + * Creates nodes for the top level Key + * + * @param key + * + * @return Node for the key, null if key is unknown. + */ + @Override + protected Node createNodeForKey(Object key) { + + if (key instanceof SleuthkitVisitableItem) { + return ((SleuthkitVisitableItem) key).accept(new RootContentChildren.CreateSleuthkitNodeVisitor()); + } else if (key instanceof AutopsyVisitableItem) { + return ((AutopsyVisitableItem) key).accept(new RootContentChildren.CreateAutopsyNodeVisitor()); + } + else { + logger.log(Level.SEVERE, "Unknown key type ", key.getClass().getName()); + return null; + } + } + + /** + * Refresh the children + */ + public void refreshChildren() { + refresh(true); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Views.java b/Core/src/org/sleuthkit/autopsy/datamodel/Views.java index b31cfda543..d2a8671678 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Views.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Views.java @@ -26,11 +26,21 @@ import org.sleuthkit.datamodel.SleuthkitCase; public class Views implements AutopsyVisitableItem { private SleuthkitCase skCase; + private final long datasourceObjId; public Views(SleuthkitCase skCase) { - this.skCase = skCase; + this(skCase, 0); } + public Views(SleuthkitCase skCase, long dsObjId) { + this.skCase = skCase; + this.datasourceObjId = dsObjId; + } + + long filteringDataSourceObjId() { + return this.datasourceObjId; + } + @Override public T accept(AutopsyItemVisitor visitor) { return visitor.visit(this); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java index 261206efff..11b905008c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java @@ -22,8 +22,6 @@ import java.util.Arrays; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; -import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.datamodel.DataSourcesLayerChildren.SubtreeEnum; import org.sleuthkit.datamodel.SleuthkitCase; /** @@ -36,16 +34,19 @@ public class ViewsNode extends DisplayableItemNode { public static final String NAME = NbBundle.getMessage(ViewsNode.class, "ViewsNode.name.text"); public ViewsNode(SleuthkitCase sleuthkitCase) { + this(sleuthkitCase, 0); + } + + public ViewsNode(SleuthkitCase sleuthkitCase, long dsObjId) { - super( UserPreferences.groupItemsInTreeByDatasource() ? - new DataSourcesLayerChildren(sleuthkitCase, SubtreeEnum.VIEWS) : + super( new RootContentChildren(Arrays.asList( - new FileTypes(sleuthkitCase), + new FileTypes(sleuthkitCase, dsObjId), // June '15: Recent Files was removed because it was not useful w/out filtering // add it back in if we can filter the results to a more managable size. // new RecentFiles(sleuthkitCase), - new DeletedContent(sleuthkitCase), - new FileSize(sleuthkitCase)) + new DeletedContent(sleuthkitCase, dsObjId), + new FileSize(sleuthkitCase, dsObjId)) ), Lookups.singleton(NAME) ); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 46fa59daa5..866d1d2e94 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -427,7 +427,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen notifyObservers(Event.SHUTTING_DOWN); break; default: - SYS_LOGGER.log(Level.WARNING, "Received unsupported control event: {0}", event.getControlEventType()); + sysLogger.log(Level.WARNING, "Received unsupported control event: {0}", event.getControlEventType()); break; } } From 140989d9c60d1ded8437fc2cde6f77764f7ea6bd Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 10 May 2018 08:51:00 -0400 Subject: [PATCH 06/29] Resolving conflicts after stash pop --- .../autopsy/datamodel/DataSources.java | 1 + .../autopsy/datamodel/ViewsNode.java | 1 + .../DirectoryTreeTopComponent.java | 100 ++++++++++++------ 3 files changed, 68 insertions(+), 34 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java index 52ca52e89f..c5d8fadc46 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel; /** * Root node to store the data sources in a case */ +// RAMAN TBD: Rename DataSources/DataSourcesNode/ public class DataSources implements AutopsyVisitableItem { private final long datasourceObjId; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java index 11b905008c..a1114761bb 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java @@ -55,6 +55,7 @@ public class ViewsNode extends DisplayableItemNode { this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/views.png"); //NON-NLS } + @Override public boolean isLeafTypeNode() { return false; diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 977b1ccdd0..ff77fbfddb 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.directorytree; import java.awt.Cursor; import java.awt.EventQueue; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; @@ -30,6 +32,7 @@ import java.util.EnumSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.prefs.PreferenceChangeEvent; @@ -37,6 +40,7 @@ import java.util.prefs.PreferenceChangeListener; import javax.swing.Action; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; +import javax.swing.Timer; import javax.swing.tree.TreeSelectionModel; import org.apache.commons.lang3.StringUtils; import org.openide.explorer.ExplorerManager; @@ -48,6 +52,7 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.NodeNotFoundException; import org.openide.nodes.NodeOp; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.windows.TopComponent; @@ -64,7 +69,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ArtifactNodeSelectionInfo; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.CreditCards; -import org.sleuthkit.autopsy.datamodel.DataSources; import org.sleuthkit.autopsy.datamodel.DataSourcesNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.EmailExtracted; @@ -73,12 +77,8 @@ import org.sleuthkit.autopsy.datamodel.ExtractedContent; import org.sleuthkit.autopsy.datamodel.FileTypesByMimeType; import org.sleuthkit.autopsy.datamodel.InterestingHits; import org.sleuthkit.autopsy.datamodel.KeywordHits; -import org.sleuthkit.autopsy.datamodel.Reports; -import org.sleuthkit.autopsy.datamodel.Results; import org.sleuthkit.autopsy.datamodel.ResultsNode; -import org.sleuthkit.autopsy.datamodel.RootContentChildren; -import org.sleuthkit.autopsy.datamodel.Tags; -import org.sleuthkit.autopsy.datamodel.Views; +import org.sleuthkit.autopsy.datamodel.RootContentChildrenFactory; import org.sleuthkit.autopsy.datamodel.ViewsNode; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.autopsy.datamodel.accounts.BINRange; @@ -106,7 +106,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat private final LinkedList forwardList; private static final String PREFERRED_ID = "DirectoryTreeTopComponent"; //NON-NLS private static final Logger LOGGER = Logger.getLogger(DirectoryTreeTopComponent.class.getName()); - private RootContentChildren contentChildren; + private RootContentChildrenFactory rootChildrenFactory; + private Children contentChildren; /** * the constructor @@ -129,6 +130,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat this.forwardList = new LinkedList<>(); backButton.setEnabled(false); forwardButton.setEnabled(false); + + groupByDatasourceCheckBox.setSelected(UserPreferences.groupItemsInTreeByDatasource()); } /** @@ -397,12 +400,9 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } else { // if there's at least one image, load the image and open the top component final SleuthkitCase tskCase = currentCase.getSleuthkitCase(); - contentChildren = new RootContentChildren(Arrays.asList( - new DataSources(), - new Views(tskCase), - new Results(tskCase), - new Tags(), - new Reports())); + + rootChildrenFactory = new RootContentChildrenFactory(tskCase); + contentChildren = Children.create(rootChildrenFactory, true); Node root = new AbstractNode(contentChildren) { //JIRA-2807: What is the point of these overrides? /** @@ -443,19 +443,23 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat TreeView tree = getTree(); Node results = rootChildren.findChild(ResultsNode.NAME); - tree.expandNode(results); - Children resultsChildren = results.getChildren(); - Arrays.stream(resultsChildren.getNodes()).forEach(tree::expandNode); + if (!Objects.isNull(results)) { + tree.expandNode(results); + Children resultsChildren = results.getChildren(); + Arrays.stream(resultsChildren.getNodes()).forEach(tree::expandNode); - Accounts accounts = resultsChildren.findChild(Accounts.NAME).getLookup().lookup(Accounts.class); - showRejectedCheckBox.setAction(accounts.newToggleShowRejectedAction()); - showRejectedCheckBox.setSelected(false); + Accounts accounts = resultsChildren.findChild(Accounts.NAME).getLookup().lookup(Accounts.class); + if (!Objects.isNull(accounts)) { + showRejectedCheckBox.setAction(accounts.newToggleShowRejectedAction()); + showRejectedCheckBox.setSelected(false); + } + } - groupByDatasourceCheckBox.setSelected(UserPreferences.groupItemsInTreeByDatasource()); - Node views = rootChildren.findChild(ViewsNode.NAME); - Arrays.stream(views.getChildren().getNodes()).forEach(tree::expandNode); - tree.collapseNode(views); + if (!Objects.isNull(views)) { + Arrays.stream(views.getChildren().getNodes()).forEach(tree::expandNode); + tree.collapseNode(views); + } /* * JIRA-2806: What is this supposed to do? Right now it selects * the data sources node, but the comment seems to indicate @@ -487,7 +491,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // of changing the selected node fires a handler that tries to make // dataResult active) try { - em.setSelectedNodes(get()); + Node[] selections = get(); + if (selections != null && selections.length > 0){ + em.setSelectedNodes(selections); + } } catch (PropertyVetoException ex) { LOGGER.log(Level.SEVERE, "Error setting default selected node.", ex); //NON-NLS } catch (InterruptedException | ExecutionException ex) { @@ -752,7 +759,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat */ String[] currentLast = backList.peekLast(); String lastNodeName = null; - if (currentLast != null) { + if (currentLast != null && currentLast.length > 0) { lastNodeName = currentLast[currentLast.length - 1]; } @@ -796,7 +803,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * Refresh the content node part of the dir tree safely in the EDT thread */ public void refreshContentTreeSafe() { - SwingUtilities.invokeLater(this::refreshTree); + SwingUtilities.invokeLater(this::rebuildTree); } /** @@ -817,18 +824,43 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat setSelectedNode(selectedPath, DataSourcesNode.NAME); } - /** - * Refreshes the entire tree + /** + * Rebuilds the tree */ - private void refreshTree() { - Node selectedNode = getSelectedNode(); - final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext()); + private void rebuildTree() { - contentChildren.refreshContentKeys(); - - setSelectedNode(selectedPath, DataSourcesNode.NAME); + // refresh all children of the root. + rootChildrenFactory.refreshChildren(); + + // Select the first node and reset the selection history + // This should happen on the EDT once the tree has been rebuilt. + // hence the timer to schedule it + Timer timer = new Timer( 10, (ActionEvent e) -> { + selectFirstChildNode(); + resetHistory(); + }); + + timer.setRepeats( false ); + timer.start(); } + /** + * Selects the first node in the tree. + * + */ + private void selectFirstChildNode () { + Children rootChildren = em.getRootContext().getChildren(); + + if (rootChildren.getNodesCount() > 0) { + //Node[] ttt = new Node[]{rootChildren.getNodeAt(0)}; + //Node firstNode = ttt[0]; + Node firstNode = rootChildren.getNodeAt(0); + if (firstNode != null) { + final String[] selectedPath = NodeOp.createPath(firstNode, em.getRootContext()); + setSelectedNode(selectedPath, null); + } + } + } /** * Set the selected node using a path to a previously selected node. * From bcad232ee6d9e6abbd78c55ab8d090541352aebf Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 10 May 2018 11:15:17 -0400 Subject: [PATCH 07/29] Added JIRA number for a TBD --- .../autopsy/directorytree/DirectoryTreeTopComponent.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index ff77fbfddb..3036b64114 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -825,7 +825,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } /** - * Rebuilds the tree + * Rebuilds the directory tree */ private void rebuildTree() { @@ -835,6 +835,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // Select the first node and reset the selection history // This should happen on the EDT once the tree has been rebuilt. // hence the timer to schedule it + // TBD JIRA-3838: need to get rid of this delay hack. Timer timer = new Timer( 10, (ActionEvent e) -> { selectFirstChildNode(); resetHistory(); From e71624e98931328ba873bb8d767e55e82969ee3e Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 10 May 2018 13:39:01 -0400 Subject: [PATCH 08/29] Cleanup after self-review. --- .../sleuthkit/autopsy/datamodel/AbstractContentChildren.java | 5 ++--- .../sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java | 4 ++-- Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java | 1 - .../src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java | 3 --- .../org/sleuthkit/autopsy/datamodel/ExtractedContent.java | 2 +- Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java | 2 +- .../autopsy/datamodel/RootContentChildrenFactory.java | 5 ----- .../autopsy/directorytree/DirectoryTreeTopComponent.java | 2 -- 8 files changed, 6 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index e300efdf1b..bfd2f0172a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -192,7 +192,6 @@ abstract class AbstractContentChildren extends Keys { @Override public AbstractNode visit(Tags tagsNodeKey) { - // RAMAN TBD: pass dsObjID down here return tagsNodeKey.new RootNode(); } @@ -213,7 +212,7 @@ abstract class AbstractContentChildren extends Keys { @Override public AbstractNode visit(Results r) { - // RAMAN TBD: pass dsObjID down here + // RAMAN TBD JIRA-3763: pass dsObjID down here return new ResultsNode(r.getSleuthkitCase()); } @@ -241,7 +240,7 @@ abstract class AbstractContentChildren extends Keys { @Override public AbstractNode visit(FileTypesByMimeType ftByMimeTypeItem) { - return ftByMimeTypeItem.new ByMimeTypeNode(/*ftByMimeTypeItem.filteringDataSourceObjId()*/); + return ftByMimeTypeItem.new ByMimeTypeNode(); } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java index 2b6f2d0e1f..87f6d8ed7b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java @@ -76,8 +76,8 @@ public class DataSourceGroupingNode extends DisplayableItemNode { return new RootContentChildren(Arrays.asList( new DataSources(dsObjId), new Views(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId), - new Results(Case.getCurrentCaseThrows().getSleuthkitCase()), // RAMAN TBD: pass down dsObjId - new Tags() ) // RAMAN TBD: pass down dsObjId + new Results(Case.getCurrentCaseThrows().getSleuthkitCase()), // RAMAN TBD JIRA-3763: pass down dsObjId + new Tags() ) // RAMAN TBD JIRA-3762 : pass down dsObjId ); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java index c5d8fadc46..52ca52e89f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel; /** * Root node to store the data sources in a case */ -// RAMAN TBD: Rename DataSources/DataSourcesNode/ public class DataSources implements AutopsyVisitableItem { private final long datasourceObjId; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index 68f92b8f4e..8441b8aaad 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -43,8 +43,6 @@ public class DataSourcesNode extends DisplayableItemNode { public static final String NAME = NbBundle.getMessage(DataSourcesNode.class, "DataSourcesNode.name"); - private final long datasourceObjId; - // NOTE: The images passed in via argument will be ignored. @Deprecated public DataSourcesNode(List images) { @@ -58,7 +56,6 @@ public class DataSourcesNode extends DisplayableItemNode { public DataSourcesNode(long dsObjId) { super(new DataSourcesNodeChildren(dsObjId), Lookups.singleton(NAME)); init(); - this.datasourceObjId = dsObjId; } private void init() { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 79797d22a6..b9664eaf34 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -288,7 +288,7 @@ public class ExtractedContent implements AutopsyVisitableItem { //TEST COMMENT if (skCase != null) { try { - // RAMAN TBD: filter on datasource obj id + // RAMAN TBD JIRA-3763: filter on datasource obj id List types = skCase.getArtifactTypesInUse(); types.removeAll(doNotShow); Collections.sort(types, diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java index 6fcd9a540c..acb5235c96 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java @@ -39,7 +39,7 @@ public class ResultsNode extends DisplayableItemNode { public ResultsNode(SleuthkitCase sleuthkitCase, long dsObjId) { super( - // RAMAN TBD: pass down dsObjId to each of these subnodes + // RAMAN TBD JIRA-3763: pass down dsObjId to each of these subnodes new RootContentChildren(Arrays.asList( new ExtractedContent(sleuthkitCase), new KeywordHits(sleuthkitCase), diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java index 5adbb8c826..e9e72e05cf 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java @@ -49,7 +49,6 @@ public class RootContentChildrenFactory extends ChildFactory.Detachable private static final Logger logger = Logger.getLogger(RootContentChildrenFactory.class.getName()); private final SleuthkitCase tskCase; - /** * Constructs the child factory for root nodes * @param tskCase @@ -89,10 +88,6 @@ public class RootContentChildrenFactory extends ChildFactory.Detachable refresh(true); } - - - - /** * Creates keys for the top level children. * diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 3036b64114..a1002f79a8 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.directorytree; import java.awt.Cursor; import java.awt.EventQueue; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; @@ -52,7 +51,6 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.NodeNotFoundException; import org.openide.nodes.NodeOp; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.windows.TopComponent; From f5b4dbdfe43bf514103f2ae26c921936faaf71ee Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 11 May 2018 14:02:26 -0400 Subject: [PATCH 09/29] 3763: Groups Results by Data source (Interim commit) - Group the extracted content subtree by data source --- .../autopsy/datamodel/AbstractContentChildren.java | 5 ++--- .../autopsy/datamodel/DataSourceGroupingNode.java | 2 +- .../autopsy/datamodel/ExtractedContent.java | 10 ++++++---- .../org/sleuthkit/autopsy/datamodel/Results.java | 12 +++++++++++- .../sleuthkit/autopsy/datamodel/ResultsNode.java | 14 +++++++------- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index bfd2f0172a..7e2f35f0bb 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -211,9 +211,8 @@ abstract class AbstractContentChildren extends Keys { } @Override - public AbstractNode visit(Results r) { - // RAMAN TBD JIRA-3763: pass dsObjID down here - return new ResultsNode(r.getSleuthkitCase()); + public AbstractNode visit(Results results) { + return new ResultsNode(results.getSleuthkitCase(), results.filteringDataSourceObjId() ); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java index 87f6d8ed7b..314e2a78da 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java @@ -76,7 +76,7 @@ public class DataSourceGroupingNode extends DisplayableItemNode { return new RootContentChildren(Arrays.asList( new DataSources(dsObjId), new Views(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId), - new Results(Case.getCurrentCaseThrows().getSleuthkitCase()), // RAMAN TBD JIRA-3763: pass down dsObjId + new Results(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId), new Tags() ) // RAMAN TBD JIRA-3762 : pass down dsObjId ); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index b9664eaf34..3c1a2cd1d5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -288,8 +288,10 @@ public class ExtractedContent implements AutopsyVisitableItem { //TEST COMMENT if (skCase != null) { try { - // RAMAN TBD JIRA-3763: filter on datasource obj id - List types = skCase.getArtifactTypesInUse(); + List types = (UserPreferences.groupItemsInTreeByDatasource()) ? + skCase.getArtifactTypesInUseByDataSource(datasourceObjId) : + skCase.getArtifactTypesInUse() ; + types.removeAll(doNotShow); Collections.sort(types, new Comparator() { @@ -352,7 +354,7 @@ public class ExtractedContent implements AutopsyVisitableItem { // "getBlackboardArtifactCount()" method to skCase try { this.childCount = UserPreferences.groupItemsInTreeByDatasource() ? - skCase.getBlackboardArtifactsCount(type.getTypeID(), datasourceObjId) : + skCase.getBlackboardArtifactsCountByDataSource(type.getTypeID(), datasourceObjId) : skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); } catch (TskException ex) { Logger.getLogger(TypeNode.class.getName()) @@ -477,7 +479,7 @@ public class ExtractedContent implements AutopsyVisitableItem { try { List arts = UserPreferences.groupItemsInTreeByDatasource() ? - skCase.getBlackboardArtifacts(TSK_ACCOUNT, datasourceObjId) : + skCase.getBlackboardArtifactsByDataSource(type.getTypeID(), datasourceObjId) : skCase.getBlackboardArtifacts(type.getTypeID()); list.addAll(arts); } catch (TskException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Results.java b/Core/src/org/sleuthkit/autopsy/datamodel/Results.java index 7f1cd1cea7..b2d9f4799b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Results.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Results.java @@ -26,11 +26,17 @@ import org.sleuthkit.datamodel.SleuthkitCase; public class Results implements AutopsyVisitableItem { private SleuthkitCase skCase; + private final long datasourceObjId; public Results(SleuthkitCase skCase) { - this.skCase = 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); @@ -39,4 +45,8 @@ public class Results implements AutopsyVisitableItem { 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 index acb5235c96..e284780bcd 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java @@ -39,14 +39,14 @@ public class ResultsNode extends DisplayableItemNode { public ResultsNode(SleuthkitCase sleuthkitCase, long dsObjId) { super( - // RAMAN TBD JIRA-3763: pass down dsObjId to each of these subnodes + new RootContentChildren(Arrays.asList( - new ExtractedContent(sleuthkitCase), - new KeywordHits(sleuthkitCase), - new HashsetHits(sleuthkitCase), - new EmailExtracted(sleuthkitCase), - new InterestingHits(sleuthkitCase), - new Accounts(sleuthkitCase) ) + new ExtractedContent(sleuthkitCase, dsObjId ), + new KeywordHits(sleuthkitCase), // RAMAN TBD JIRA-3763: pass down dsObjId to each of these subnodes + new HashsetHits(sleuthkitCase), // RAMAN TBD JIRA-3763: pass down dsObjId to each of these subnodes + new EmailExtracted(sleuthkitCase), // RAMAN TBD JIRA-3763: pass down dsObjId to each of these subnodes + new InterestingHits(sleuthkitCase), // RAMAN TBD JIRA-3763: pass down dsObjId to each of these subnodes + new Accounts(sleuthkitCase) ) // RAMAN TBD JIRA-3763: pass down dsObjId to each of these subnodes ), Lookups.singleton(NAME)); setName(NAME); From f73dad988d1110d68eecaaee86c1e175eb53ed88 Mon Sep 17 00:00:00 2001 From: Raman Date: Wed, 16 May 2018 10:03:31 -0400 Subject: [PATCH 10/29] 3813: Fix 'View In Directory' context menu action. --- .../directorytree/ViewContextAction.java | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index 792252605a..acec3cb1bd 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -24,6 +24,7 @@ import java.beans.PropertyVetoException; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.AbstractAction; @@ -32,21 +33,29 @@ import org.openide.explorer.ExplorerManager; import org.openide.explorer.view.TreeView; import org.openide.nodes.Children; import org.openide.nodes.Node; +import org.openide.nodes.NodeOp; +import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.ContentNodeSelectionInfo; +import org.sleuthkit.autopsy.datamodel.DataSourceGroupingNode; import org.sleuthkit.autopsy.datamodel.DataSourcesNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.RootContentChildren; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; +import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.FileSystem; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.datamodel.TskDataException; import org.sleuthkit.datamodel.VolumeSystem; /** @@ -122,7 +131,9 @@ public class ViewContextAction extends AbstractAction { @Override @Messages({ "ViewContextAction.errorMessage.cannotFindDirectory=Failed to locate directory.", - "ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree.",}) + "ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree.", + "ViewContextAction.errorMessage.cannotFindNode=Failed to locate data source node in tree." + }) public void actionPerformed(ActionEvent event) { EventQueue.invokeLater(() -> { /* @@ -130,7 +141,40 @@ public class ViewContextAction extends AbstractAction { */ DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance(); ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager(); - Node parentTreeViewNode = treeViewExplorerMgr.getRootContext().getChildren().findChild(DataSourcesNode.NAME); + + Node parentTreeViewNode; + if (UserPreferences.groupItemsInTreeByDatasource()) { // 'Group by Data Source' view + + SleuthkitCase skCase; + String dsname; + try { + // get the objid/name of the datasource of the selected content. + skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + long contentDSObjid = skCase.getDataSourceObjectId(content.getId()); + DataSource datasource = skCase.getDataSource(contentDSObjid); + dsname = datasource.getName(); + + Children rootChildren = treeViewExplorerMgr.getRootContext().getChildren(); + Node datasourceGroupingNode = rootChildren.findChild(dsname); + if (! Objects.isNull(datasourceGroupingNode) ) { + Children dsChildren = datasourceGroupingNode.getChildren(); + parentTreeViewNode = dsChildren.findChild(DataSourcesNode.NAME); + } + else { + MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode()); + logger.log(Level.SEVERE, "Failed to locate data source node in tree."); //NON-NLS + return; + } + } catch (NoCurrentCaseException| TskDataException | TskCoreException ex) { + MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode()); + logger.log(Level.SEVERE, "Failed to locate data source node in tree.", ex); //NON-NLS + return; + } + } else { // Classic view + // Start the search at the DataSourcesNode + parentTreeViewNode = treeViewExplorerMgr.getRootContext().getChildren().findChild(DataSourcesNode.NAME); + } + /* * Get the parent content for the content to be selected in the * results view. If the parent content is null, then the specified From 63add9d2b78ee507594534e0f7ab0428e0292d27 Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 18 May 2018 15:36:55 -0400 Subject: [PATCH 11/29] 3763: Group Results by data source --- .../autopsy/datamodel/EmailExtracted.java | 23 +++++++++ .../autopsy/datamodel/HashsetHits.java | 28 ++++++++++- .../autopsy/datamodel/InterestingHits.java | 23 +++++++++ .../autopsy/datamodel/KeywordHits.java | 29 ++++++++++- .../autopsy/datamodel/ResultsNode.java | 12 ++--- .../autopsy/datamodel/accounts/Accounts.java | 48 +++++++++++++++++-- 6 files changed, 148 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 409c3165e8..d9df849d86 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -40,6 +40,7 @@ import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -86,10 +87,29 @@ public class EmailExtracted implements AutopsyVisitableItem { } private SleuthkitCase skCase; private final EmailResults emailResults; + private final long datasourceObjId; + + /** + * Constructor + * + * @param skCase Case DB + */ public EmailExtracted(SleuthkitCase skCase) { + this(skCase, 0); + } + + /** + * Constructor + * + * @param skCase Case DB + * @param objId Object id of the data source + * + */ + public EmailExtracted(SleuthkitCase skCase, long objId) { this.skCase = skCase; + this.datasourceObjId = objId; emailResults = new EmailResults(); } @@ -141,6 +161,9 @@ public class EmailExtracted implements AutopsyVisitableItem { + "attribute_type_id=" + pathAttrId //NON-NLS + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS + if (UserPreferences.groupItemsInTreeByDatasource()) { + query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId; + } try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { ResultSet resultSet = dbQuery.getResultSet(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index a720409489..24bae3d368 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -42,6 +42,7 @@ import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -63,9 +64,29 @@ public class HashsetHits implements AutopsyVisitableItem { private static final Logger logger = Logger.getLogger(HashsetHits.class.getName()); private SleuthkitCase skCase; private final HashsetResults hashsetResults; - + private final long datasourceObjId; + + + /** + * Constructor + * + * @param skCase Case DB + * + */ public HashsetHits(SleuthkitCase skCase) { + this(skCase, 0); + } + + /** + * Constructor + * + * @param skCase Case DB + * @param objId Object id of the data source + * + */ + public HashsetHits(SleuthkitCase skCase, long objId) { this.skCase = skCase; + this.datasourceObjId = objId; hashsetResults = new HashsetResults(); } @@ -120,7 +141,10 @@ public class HashsetHits implements AutopsyVisitableItem { + "attribute_type_id=" + setNameId //NON-NLS + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS - + if (UserPreferences.groupItemsInTreeByDatasource()) { + query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId; + } + try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { ResultSet resultSet = dbQuery.getResultSet(); synchronized (hashSetHitsMap) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 7c3249f990..67622d180c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -42,6 +42,7 @@ import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -59,9 +60,28 @@ public class InterestingHits implements AutopsyVisitableItem { private static final Logger logger = Logger.getLogger(InterestingHits.class.getName()); private SleuthkitCase skCase; private final InterestingResults interestingResults = new InterestingResults(); + private final long datasourceObjId; + /** + * Constructor + * + * @param skCase Case DB + * + */ public InterestingHits(SleuthkitCase skCase) { + this(skCase, 0); + } + + /** + * Constructor + * + * @param skCase Case DB + * @param objId Object id of the data source + * + */ + public InterestingHits(SleuthkitCase skCase, long objId) { this.skCase = skCase; + this.datasourceObjId = objId; interestingResults.update(); } @@ -112,6 +132,9 @@ public class InterestingHits implements AutopsyVisitableItem { + "attribute_type_id=" + setNameId //NON-NLS + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS + if (UserPreferences.groupItemsInTreeByDatasource()) { + query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId; + } try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { synchronized (interestingItemsMap) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index c35d9bdda0..51367297b8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -44,6 +44,7 @@ import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import static org.sleuthkit.autopsy.datamodel.Bundle.*; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -73,6 +74,7 @@ public class KeywordHits implements AutopsyVisitableItem { private SleuthkitCase skCase; private final KeywordResults keywordResults; + private final long datasourceObjId; /** * String used in the instance MAP so that exact matches and substring can @@ -81,6 +83,7 @@ public class KeywordHits implements AutopsyVisitableItem { */ private static final String DEFAULT_INSTANCE_NAME = "DEFAULT_INSTANCE_NAME"; + /** * query attributes table for the ones that we need for the tree */ @@ -101,8 +104,25 @@ public class KeywordHits implements AutopsyVisitableItem { return (instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME)); } - public KeywordHits(SleuthkitCase skCase) { + /** + * Constructor + * + * @param skCase Case DB + */ + KeywordHits(SleuthkitCase skCase) { + this(skCase, 0); + } + + /** + * Constructor + * + * @param skCase Case DB + * @param objId Object id of the data source + * + */ + public KeywordHits(SleuthkitCase skCase, long objId) { this.skCase = skCase; + this.datasourceObjId = objId; keywordResults = new KeywordResults(); } @@ -300,7 +320,12 @@ public class KeywordHits implements AutopsyVisitableItem { return; } - try (CaseDbQuery dbQuery = skCase.executeQuery(KEYWORD_HIT_ATTRIBUTES_QUERY)) { + String queryStr = KEYWORD_HIT_ATTRIBUTES_QUERY; + if (UserPreferences.groupItemsInTreeByDatasource()) { + queryStr += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId; + } + + try (CaseDbQuery dbQuery = skCase.executeQuery(queryStr)) { ResultSet resultSet = dbQuery.getResultSet(); while (resultSet.next()) { long artifactId = resultSet.getLong("artifact_id"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java index e284780bcd..91d18bbcc6 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -42,11 +42,11 @@ public class ResultsNode extends DisplayableItemNode { new RootContentChildren(Arrays.asList( new ExtractedContent(sleuthkitCase, dsObjId ), - new KeywordHits(sleuthkitCase), // RAMAN TBD JIRA-3763: pass down dsObjId to each of these subnodes - new HashsetHits(sleuthkitCase), // RAMAN TBD JIRA-3763: pass down dsObjId to each of these subnodes - new EmailExtracted(sleuthkitCase), // RAMAN TBD JIRA-3763: pass down dsObjId to each of these subnodes - new InterestingHits(sleuthkitCase), // RAMAN TBD JIRA-3763: pass down dsObjId to each of these subnodes - new Accounts(sleuthkitCase) ) // RAMAN TBD JIRA-3763: pass down dsObjId to each of these subnodes + new KeywordHits(sleuthkitCase, dsObjId), + new HashsetHits(sleuthkitCase, dsObjId), + new EmailExtracted(sleuthkitCase, dsObjId), + new InterestingHits(sleuthkitCase, dsObjId ), + new Accounts(sleuthkitCase, dsObjId) ) ), Lookups.singleton(NAME)); setName(NAME); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index 8301928528..557e6582ca 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -58,6 +58,7 @@ import org.openide.util.Utilities; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.AutopsyItemVisitor; @@ -94,6 +95,8 @@ final public class Accounts implements AutopsyVisitableItem { final public static String NAME = Bundle.AccountsRootNode_name(); private SleuthkitCase skCase; + private final long datasourceObjId; + private final EventBus reviewStatusBus = new EventBus("ReviewStatusBus"); /* Should rejected accounts be shown in the accounts section of the tree. */ @@ -108,12 +111,24 @@ final public class Accounts implements AutopsyVisitableItem { * @param skCase The SleuthkitCase object to use for db queries. */ public Accounts(SleuthkitCase skCase) { + this(skCase, 0); + } + + /** + * Constructor + * + * @param skCase The SleuthkitCase object to use for db queries. + * @param objId Object id of the data source + */ + public Accounts(SleuthkitCase skCase, long objId) { this.skCase = skCase; + this.datasourceObjId = objId; this.rejectActionInstance = new RejectAccounts(); this.approveActionInstance = new ApproveAccounts(); } - + + @Override public T accept(AutopsyItemVisitor visitor) { return visitor.visit(this); @@ -130,6 +145,18 @@ final public class Accounts implements AutopsyVisitableItem { return showRejected ? " " : " AND blackboard_artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() + " "; //NON-NLS } + /** + * Returns the clause to filter artifacts by data source. + * + * @return A clause that will or will not filter artifacts by datasource + * based on the UserPreferences groupItemsInTreeByDatasource setting + */ + private String getFilterByDataSourceClause() { + return (UserPreferences.groupItemsInTreeByDatasource()) ? + " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId + " " + : " "; + } + /** * Gets a new Action that when invoked toggles showing rejected artifacts on * or off. @@ -291,10 +318,14 @@ final public class Accounts implements AutopsyVisitableItem { @Override protected boolean createKeys(List list) { - try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery( - "SELECT DISTINCT blackboard_attributes.value_text as account_type " - + " FROM blackboard_attributes " - + " WHERE blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()); + String accountTypesInUseQuery = + "SELECT DISTINCT blackboard_attributes.value_text as account_type " + + " FROM blackboard_artifacts " //NON-NLS + + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS + + " WHERE blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() + + getFilterByDataSourceClause(); + + try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery ); ResultSet resultSet = executeQuery.getResultSet()) { while (resultSet.next()) { String accountType = resultSet.getString("account_type"); @@ -429,6 +460,7 @@ final public class Accounts implements AutopsyVisitableItem { + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_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() + getRejectedArtifactFilterClause(); //NON-NLS try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); ResultSet rs = results.getResultSet();) { @@ -739,6 +771,7 @@ final public class Accounts implements AutopsyVisitableItem { + " 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 + + getFilterByDataSourceClause() + getRejectedArtifactFilterClause() + " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS + " ORDER BY hits DESC "; //NON-NLS @@ -807,6 +840,7 @@ final public class Accounts implements AutopsyVisitableItem { + " 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 + + getFilterByDataSourceClause() + getRejectedArtifactFilterClause() + " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo"; try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); @@ -943,6 +977,7 @@ final public class Accounts implements AutopsyVisitableItem { + " 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 + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + + getFilterByDataSourceClause() + getRejectedArtifactFilterClause() + " GROUP BY BIN " //NON-NLS + " ORDER BY BIN "; //NON-NLS @@ -1009,6 +1044,7 @@ final public class Accounts implements AutopsyVisitableItem { + " 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 + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + + getFilterByDataSourceClause() + getRejectedArtifactFilterClause(); //NON-NLS try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); ResultSet resultSet = results.getResultSet();) { @@ -1304,6 +1340,7 @@ final public class Accounts implements AutopsyVisitableItem { + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_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() + getRejectedArtifactFilterClause() + " ORDER BY blackboard_attributes.value_text"; //NON-NLS try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); @@ -1375,6 +1412,7 @@ final public class Accounts implements AutopsyVisitableItem { + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_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() + getRejectedArtifactFilterClause(); try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); ResultSet resultSet = results.getResultSet();) { From 5da21f94da36ac9a3cc07e095c691a001da69b29 Mon Sep 17 00:00:00 2001 From: Raman Date: Wed, 23 May 2018 06:47:45 -0400 Subject: [PATCH 12/29] 3762: Group Tags by data source --- .../casemodule/services/TagsManager.java | 209 ++++++++++++++++++ .../datamodel/AbstractContentChildren.java | 2 +- .../datamodel/DataSourceGroupingNode.java | 2 +- .../datamodel/RootContentChildrenFactory.java | 2 - .../org/sleuthkit/autopsy/datamodel/Tags.java | 68 +++++- 5 files changed, 270 insertions(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index f113a622fe..f26c63db8a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; +import java.sql.ResultSet; +import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -36,6 +38,8 @@ import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; +import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -157,6 +161,47 @@ public class TagsManager implements Closeable { return caseDb.getTagNamesInUse(); } + /** + * Selects all of the rows from the tag_names table in the case database for + * which there is at least one matching row in the content_tags or + * blackboard_artifact_tags tables, for the given datasource object id. + * + * @return A list, possibly empty, of TagName data transfer objects (DTOs) + * for the rows. + * + * @throws TskCoreException + */ + public List getTagNamesInUse(long dsObjId) throws TskCoreException { + + + ArrayList tagNames = new ArrayList<>(); + String queryStr = "SELECT * FROM tag_names " + + "WHERE tag_name_id IN " + + "( SELECT content_tags.tag_name_id as tag_name_id " + + "FROM content_tags as content_tags, tsk_files as tsk_files" + + " WHERE content_tags.obj_id = tsk_files.obj_id" + + " AND tsk_files.data_source_obj_id = " + dsObjId + + " UNION " + + "SELECT artifact_tags.tag_name_id as tag_name_id " + + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts " + + " WHERE artifact_tags.artifact_id = arts.artifact_id" + + " AND arts.data_source_obj_id = " + dsObjId + + " )"; + + try (CaseDbQuery query = caseDb.executeQuery(queryStr);) { + ResultSet resultSet = query.getResultSet(); + while (resultSet.next()) { + tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"), + resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")), + TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")))); //NON-NLS + } + return tagNames; + } catch (SQLException | TskCoreException ex) { + throw new TskCoreException("Failed to get tag names in use for data source objID : " + dsObjId, ex); + } + + } + /** * Gets a map of tag display names to tag name entries in the case database. * It has keys for the display names of the standard tag types, the current @@ -392,6 +437,46 @@ public class TagsManager implements Closeable { return caseDb.getContentTagsCountByTagName(tagName); } + /** + * Gets content tags count by tag name, for the given data source + * + * @param tagName The representation of the desired tag type in the case + * database, which can be obtained by calling getTagNames and/or addTagName. + * + * @param dsObjId data source object id + * + * @return A count of the content tags with the specified tag name, and for + * the given data source + * + * @throws TskCoreException If there is an error getting the tags count from + * the case database. + */ + public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException { + + if (tagName.getId() == Tag.ID_NOT_SET) { + throw new TskCoreException("TagName object is invalid, id not set"); + } + + String queryStr = + "SELECT COUNT(*) AS count " + + " FROM content_tags as content_tags, tsk_files as tsk_files " + + " WHERE content_tags.obj_id = tsk_files.obj_id" + + " AND tsk_files.data_source_obj_id = " + dsObjId + + " AND content_tags.tag_name_id = " + tagName.getId(); + + try (CaseDbQuery query = caseDb.executeQuery(queryStr);) { + ResultSet resultSet = query.getResultSet(); + if (resultSet.next()) { + return resultSet.getLong("count"); + } else { + throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId ); + } + } catch (SQLException | TskCoreException ex) { + throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex); + } + + } + /** * Gets a content tag by tag id. * @@ -421,6 +506,48 @@ public class TagsManager implements Closeable { return caseDb.getContentTagsByTagName(tagName); } + /** + * Gets content tags by tag name, for the given data source. + * + * @param tagName The tag name of interest. + * + * @param dsObjId + * + * @return A list, possibly empty, of the content tags with the specified + * tag name, and for the given data source. + * + * @throws TskCoreException If there is an error getting the tags from the + * case database. + */ + public List getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException { + + if (tagName.getId() == Tag.ID_NOT_SET) { + throw new TskCoreException("TagName object is invalid, id not set"); + } + + String queryStr = + "SELECT * " + + " FROM content_tags as content_tags, tsk_files as tsk_files " + + " WHERE content_tags.obj_id = tsk_files.obj_id" + + " AND tsk_files.data_source_obj_id = " + dsObjId + + " AND content_tags.tag_name_id = " + tagName.getId(); + + try (CaseDbQuery query = caseDb.executeQuery(queryStr);) { + ResultSet resultSet = query.getResultSet(); + ArrayList tags = new ArrayList<>(); + while (resultSet.next()) { + ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), caseDb.getContentById(resultSet.getLong("obj_id")), + tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset")); //NON-NLS + tags.add(tag); + } + resultSet.close(); + return tags; + } catch (SQLException | TskCoreException ex) { + throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex); + } + + } + /** * Gets content tags count by content. * @@ -522,6 +649,45 @@ public class TagsManager implements Closeable { return caseDb.getBlackboardArtifactTagsCountByTagName(tagName); } + /** + * Gets an artifact tags count by tag name, for the given data source. + * + * @param tagName The representation of the desired tag type in the case + * database, which can be obtained by calling getTagNames + * and/or addTagName. + * @param dsObjId + * + * @return A count of the artifact tags with the specified tag name, + * for the given data source. + * + * @throws TskCoreException If there is an error getting the tags count from + * the case database. + */ + public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException { + if (tagName.getId() == Tag.ID_NOT_SET) { + throw new TskCoreException("TagName object is invalid, id not set"); + } + + String queryStr = "SELECT COUNT(*) AS count " + + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts " + + " WHERE artifact_tags.artifact_id = arts.artifact_id" + + " AND artifact_tags.tag_name_id = " + tagName.getId() + + " AND arts.data_source_obj_id = " + dsObjId + ; + + try (CaseDbQuery query = Case.getCurrentCaseThrows().getSleuthkitCase().executeQuery(queryStr);) { + ResultSet resultSet = query.getResultSet(); + if (resultSet.next()) { + return resultSet.getLong("count"); + } else { + throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId); + } + } catch (SQLException | TskCoreException | NoCurrentCaseException ex) { + throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex); + } + + } + /** * Gets an artifact tag by tag id. * @@ -553,6 +719,49 @@ public class TagsManager implements Closeable { return caseDb.getBlackboardArtifactTagsByTagName(tagName); } + /** + * Gets artifact tags by tag name, for specified data source. + * + * @param tagName The representation of the desired tag type in the case + * database, which can be obtained by calling getTagNames + * and/or addTagName. + * @param dsObjId + * + * @return A list, possibly empty, of the artifact tags with the specified + * tag name, for the specified data source. + * + * @throws TskCoreException If there is an error getting the tags from the + * case database. + */ + public List getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException { + if (tagName.getId() == Tag.ID_NOT_SET) { + throw new TskCoreException("TagName object is invalid, id not set"); + } + + String queryStr = "SELECT * " + + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts " + + " WHERE artifact_tags.artifact_id = arts.artifact_id" + + " AND artifact_tags.tag_name_id = " + tagName.getId() + + " AND arts.data_source_obj_id = " + dsObjId + ; + + try (CaseDbQuery query = Case.getCurrentCaseThrows().getSleuthkitCase().executeQuery(queryStr);) { + ResultSet resultSet = query.getResultSet(); + ArrayList tags = new ArrayList<>(); + while (resultSet.next()) { + BlackboardArtifact artifact = caseDb.getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS + Content content = caseDb.getContentById(artifact.getObjectID()); + BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"), + artifact, content, tagName, resultSet.getString("comment")); //NON-NLS + tags.add(tag); + } + return tags; + } catch (SQLException | TskCoreException | NoCurrentCaseException ex) { + throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex); + } + + } + /** * Gets artifact tags for a particular artifact. * diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index 7e2f35f0bb..9d47861786 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -192,7 +192,7 @@ abstract class AbstractContentChildren extends Keys { @Override public AbstractNode visit(Tags tagsNodeKey) { - return tagsNodeKey.new RootNode(); + return tagsNodeKey.new RootNode(tagsNodeKey.filteringDataSourceObjId()); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java index 314e2a78da..43054427a3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java @@ -77,7 +77,7 @@ public class DataSourceGroupingNode extends DisplayableItemNode { new DataSources(dsObjId), new Views(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId), new Results(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId), - new Tags() ) // RAMAN TBD JIRA-3762 : pass down dsObjId + new Tags(dsObjId) ) ); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java index e9e72e05cf..f6b7238d90 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java @@ -22,12 +22,10 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Observable; import java.util.Observer; -import java.util.Set; import java.util.logging.Level; import org.openide.nodes.ChildFactory; import org.openide.nodes.Node; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 9a01fa608f..c41a750f7e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -36,6 +36,7 @@ import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.BlackboardArtifactTag; @@ -57,6 +58,20 @@ public class Tags implements AutopsyVisitableItem { private final String DISPLAY_NAME = NbBundle.getMessage(RootNode.class, "TagsNode.displayName.text"); private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS + private final long datasourceObjId; + + Tags() { + this(0); + } + + Tags(long dsObjId) { + this.datasourceObjId = dsObjId; + } + + long filteringDataSourceObjId() { + return this.datasourceObjId; + } + @Override public T accept(AutopsyItemVisitor visitor) { return visitor.visit(this); @@ -83,11 +98,13 @@ public class Tags implements AutopsyVisitableItem { */ public class RootNode extends DisplayableItemNode { - public RootNode() { - super(Children.create(new TagNameNodeFactory(), true), Lookups.singleton(DISPLAY_NAME)); + + public RootNode(long objId) { + super(Children.create(new TagNameNodeFactory(objId), true), Lookups.singleton(DISPLAY_NAME)); super.setName(DISPLAY_NAME); super.setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension(ICON_PATH); + } @Override @@ -121,6 +138,8 @@ public class Tags implements AutopsyVisitableItem { private class TagNameNodeFactory extends ChildFactory.Detachable implements Observer { + private final long datasourceObjId; + private final Set CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED, Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED, Case.Events.CONTENT_TAG_ADDED, @@ -176,6 +195,15 @@ public class Tags implements AutopsyVisitableItem { } }; + /** + * Constructor + * @param objId data source object id + */ + TagNameNodeFactory(long objId) { + this.datasourceObjId = objId; + + } + @Override protected void addNotify() { IngestManager.getInstance().addIngestJobEventListener(pcl); @@ -196,7 +224,11 @@ public class Tags implements AutopsyVisitableItem { @Override protected boolean createKeys(List keys) { try { - List tagNamesInUse = Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(); + + List tagNamesInUse = UserPreferences.groupItemsInTreeByDatasource() ? + Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(datasourceObjId) : + Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse() + ; Collections.sort(tagNamesInUse); keys.addAll(tagNamesInUse); } catch (TskCoreException | NoCurrentCaseException ex) { @@ -244,8 +276,15 @@ public class Tags implements AutopsyVisitableItem { long tagsCount = 0; try { TagsManager tm = Case.getCurrentCaseThrows().getServices().getTagsManager(); - tagsCount = tm.getContentTagsCountByTagName(tagName); - tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName); + if (UserPreferences.groupItemsInTreeByDatasource()) { + tagsCount = tm.getContentTagsCountByTagName(tagName, datasourceObjId); + tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId); + } + else { + tagsCount = tm.getContentTagsCountByTagName(tagName); + tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName); + } + } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS } @@ -348,7 +387,9 @@ public class Tags implements AutopsyVisitableItem { private void updateDisplayName() { long tagsCount = 0; try { - tagsCount = Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName); + tagsCount = UserPreferences.groupItemsInTreeByDatasource() ? + Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, datasourceObjId) : + Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName); } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(ContentTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get content tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS } @@ -403,7 +444,11 @@ public class Tags implements AutopsyVisitableItem { protected boolean createKeys(List keys) { // Use the content tags bearing the specified tag name as the keys. try { - keys.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName)); + List contentTags = UserPreferences.groupItemsInTreeByDatasource() ? + Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName, datasourceObjId) : + Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName); + + keys.addAll(contentTags); } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(ContentTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } @@ -447,7 +492,9 @@ public class Tags implements AutopsyVisitableItem { private void updateDisplayName() { long tagsCount = 0; try { - tagsCount = Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName); + tagsCount = UserPreferences.groupItemsInTreeByDatasource() ? + Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId) : + Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName); } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(BlackboardArtifactTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS } @@ -502,7 +549,10 @@ public class Tags implements AutopsyVisitableItem { protected boolean createKeys(List keys) { try { // Use the blackboard artifact tags bearing the specified tag name as the keys. - keys.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName)); + List artifactTags = UserPreferences.groupItemsInTreeByDatasource() ? + Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, datasourceObjId) : + Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName); + keys.addAll(artifactTags); } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(BlackboardArtifactTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } From f5a95d37c66c625e78c97445485dc3c95446f955 Mon Sep 17 00:00:00 2001 From: Raman Date: Wed, 23 May 2018 13:01:55 -0400 Subject: [PATCH 13/29] 3763: Group Results by data source - Refactored previously added APIs to move from Sleuthkitcase to Blackboard. --- .../sleuthkit/autopsy/datamodel/ExtractedContent.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 3c1a2cd1d5..409b730345 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -39,6 +39,7 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; 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_EMAIL_MSG; @@ -58,6 +59,7 @@ import org.sleuthkit.datamodel.TskException; public class ExtractedContent implements AutopsyVisitableItem { private SleuthkitCase skCase; // set to null after case has been closed + private Blackboard blackboard; public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text"); private final long datasourceObjId; @@ -79,6 +81,7 @@ public class ExtractedContent implements AutopsyVisitableItem { public ExtractedContent(SleuthkitCase skCase, long objId) { this.skCase = skCase; this.datasourceObjId = objId; + this.blackboard = new Blackboard(skCase); } @Override @@ -289,7 +292,7 @@ public class ExtractedContent implements AutopsyVisitableItem { if (skCase != null) { try { List types = (UserPreferences.groupItemsInTreeByDatasource()) ? - skCase.getArtifactTypesInUseByDataSource(datasourceObjId) : + blackboard.getArtifactTypesInUseByDataSource(datasourceObjId) : skCase.getArtifactTypesInUse() ; types.removeAll(doNotShow); @@ -354,7 +357,7 @@ public class ExtractedContent implements AutopsyVisitableItem { // "getBlackboardArtifactCount()" method to skCase try { this.childCount = UserPreferences.groupItemsInTreeByDatasource() ? - skCase.getBlackboardArtifactsCountByDataSource(type.getTypeID(), datasourceObjId) : + blackboard.getBlackboardArtifactsCountByDataSource(type.getTypeID(), datasourceObjId) : skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); } catch (TskException ex) { Logger.getLogger(TypeNode.class.getName()) @@ -479,7 +482,7 @@ public class ExtractedContent implements AutopsyVisitableItem { try { List arts = UserPreferences.groupItemsInTreeByDatasource() ? - skCase.getBlackboardArtifactsByDataSource(type.getTypeID(), datasourceObjId) : + blackboard.getBlackboardArtifactsByDataSource(type.getTypeID(), datasourceObjId) : skCase.getBlackboardArtifacts(type.getTypeID()); list.addAll(arts); } catch (TskException ex) { From 0201df71d7a963768f988a36aee85090b7d9acbf Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 24 May 2018 08:00:13 -0400 Subject: [PATCH 14/29] Addressed Codacy comments. --- .../datamodel/DataSourceGroupingChildren.java | 8 ++++---- .../datamodel/RootContentChildrenFactory.java | 6 +++--- .../DirectoryTreeTopComponent.java | 20 +------------------ .../directorytree/ViewContextAction.java | 3 --- 4 files changed, 8 insertions(+), 29 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingChildren.java index 1b7d969100..3463d807dc 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingChildren.java @@ -90,12 +90,12 @@ public class DataSourceGroupingChildren extends Children.Keys { } @Override - protected Node[] createNodes(DataSource ds) { - return new Node[]{createNodeForKey(ds)}; + protected Node[] createNodes(DataSource datasource) { + return new Node[]{createNodeForKey(datasource)}; } - protected Node createNodeForKey(DataSource ds) { - return new DataSourceGroupingNode(ds); + protected Node createNodeForKey(DataSource datasource) { + return new DataSourceGroupingNode(datasource); } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java index f6b7238d90..c1de43c567 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java @@ -82,7 +82,7 @@ public class RootContentChildrenFactory extends ChildFactory.Detachable } @Override - public void update(Observable o, Object arg) { + public void update(Observable observable, Object arg) { refresh(true); } @@ -98,8 +98,8 @@ public class RootContentChildrenFactory extends ChildFactory.Detachable if (UserPreferences.groupItemsInTreeByDatasource()) { List dataSources = tskCase.getDataSources(); List keys = new ArrayList<>(); - dataSources.forEach((ds) -> { - keys.add(new DataSourceGrouping(tskCase, ds)); + dataSources.forEach((datasource) -> { + keys.add(new DataSourceGrouping(tskCase, datasource)); }); list.addAll(keys); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index a1002f79a8..1014cebc68 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -804,24 +804,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat SwingUtilities.invokeLater(this::rebuildTree); } - /** - * Refreshes changed content nodes - */ - private void refreshDataSourceTree() { - Node selectedNode = getSelectedNode(); - final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext()); - Children rootChildren = em.getRootContext().getChildren(); - Node dataSourcesFilterNode = rootChildren.findChild(DataSourcesNode.NAME); - if (dataSourcesFilterNode == null) { - LOGGER.log(Level.SEVERE, "Cannot find data sources filter node, won't refresh the content tree"); //NON-NLS - return; - } - Node dataSourcesNode = ((DirectoryTreeFilterNode) dataSourcesFilterNode).getOriginal(); - DataSourcesNode.DataSourcesNodeChildren contentRootChildren = (DataSourcesNode.DataSourcesNodeChildren) dataSourcesNode.getChildren(); - contentRootChildren.refreshContentKeys(); - setSelectedNode(selectedPath, DataSourcesNode.NAME); - } - /** * Rebuilds the directory tree */ @@ -834,7 +816,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // This should happen on the EDT once the tree has been rebuilt. // hence the timer to schedule it // TBD JIRA-3838: need to get rid of this delay hack. - Timer timer = new Timer( 10, (ActionEvent e) -> { + Timer timer = new Timer( 10, (ActionEvent event) -> { selectFirstChildNode(); resetHistory(); }); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index acec3cb1bd..9798216b9b 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -33,8 +33,6 @@ import org.openide.explorer.ExplorerManager; import org.openide.explorer.view.TreeView; import org.openide.nodes.Children; import org.openide.nodes.Node; -import org.openide.nodes.NodeOp; -import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -43,7 +41,6 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.ContentNodeSelectionInfo; -import org.sleuthkit.autopsy.datamodel.DataSourceGroupingNode; import org.sleuthkit.autopsy.datamodel.DataSourcesNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.RootContentChildren; From a32004ec0ac458a9cde67074c5466af3b35b825b Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 24 May 2018 08:17:52 -0400 Subject: [PATCH 15/29] Removed unused import. --- .../autopsy/directorytree/DirectoryTreeTopComponent.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 1014cebc68..807eaaf715 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -67,7 +67,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ArtifactNodeSelectionInfo; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.CreditCards; -import org.sleuthkit.autopsy.datamodel.DataSourcesNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.EmailExtracted; import org.sleuthkit.autopsy.datamodel.EmptyNode; From 4dc742f29bd8296d2e2c538e5ef0d62e37f35113 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 24 May 2018 08:57:32 -0400 Subject: [PATCH 16/29] Fixed the missing Reports node in "Group by data source" view. --- .../autopsy/datamodel/RootContentChildrenFactory.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java index c1de43c567..276f4c3f17 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java @@ -101,8 +101,9 @@ public class RootContentChildrenFactory extends ChildFactory.Detachable dataSources.forEach((datasource) -> { keys.add(new DataSourceGrouping(tskCase, datasource)); }); - list.addAll(keys); + + list.add(new Reports()); } else { List keys = new ArrayList<>(Arrays.asList( From ab32a318176432cc5bc51d686b66ebb9d546fc5d Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 25 May 2018 09:23:20 -0400 Subject: [PATCH 17/29] 3838: Fix/Remove delay hack. --- .../DirectoryTreeTopComponent.java | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 807eaaf715..ab50b388b3 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -807,21 +807,32 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * Rebuilds the directory tree */ private void rebuildTree() { - + // refresh all children of the root. rootChildrenFactory.refreshChildren(); - + // Select the first node and reset the selection history // This should happen on the EDT once the tree has been rebuilt. - // hence the timer to schedule it - // TBD JIRA-3838: need to get rid of this delay hack. - Timer timer = new Timer( 10, (ActionEvent event) -> { - selectFirstChildNode(); - resetHistory(); - }); + // hence the SwingWorker that does this in the done() method + new SwingWorker() { - timer.setRepeats( false ); - timer.start(); + @Override + protected Void doInBackground() throws Exception { + return null; + } + + @Override + protected void done() { + super.done(); + try { + get(); + selectFirstChildNode(); + resetHistory(); + } catch (InterruptedException | ExecutionException ex) { + LOGGER.log(Level.SEVERE, "Error selecting tree node.", ex); //NON-NLS + } //NON-NLS + } + }.execute(); } /** @@ -832,8 +843,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat Children rootChildren = em.getRootContext().getChildren(); if (rootChildren.getNodesCount() > 0) { - //Node[] ttt = new Node[]{rootChildren.getNodeAt(0)}; - //Node firstNode = ttt[0]; Node firstNode = rootChildren.getNodeAt(0); if (firstNode != null) { final String[] selectedPath = NodeOp.createPath(firstNode, em.getRootContext()); From f3dc5a42f5bdaf26522274ff2e8bcbf9607f1c0d Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 25 May 2018 10:08:19 -0400 Subject: [PATCH 18/29] Remove unused imports. --- .../autopsy/directorytree/DirectoryTreeTopComponent.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index ab50b388b3..b188da42fc 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.directorytree; import java.awt.Cursor; import java.awt.EventQueue; -import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; @@ -39,7 +38,6 @@ import java.util.prefs.PreferenceChangeListener; import javax.swing.Action; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; -import javax.swing.Timer; import javax.swing.tree.TreeSelectionModel; import org.apache.commons.lang3.StringUtils; import org.openide.explorer.ExplorerManager; From 06b72eb558056e16abe9a96e08f93aca1b3081a0 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 13 Jun 2018 13:35:22 -0400 Subject: [PATCH 19/29] Use new class for other occurrence data --- .../DataContentViewerOtherCases.java | 150 ++++++++---------- ...DataContentViewerOtherCasesTableModel.java | 50 +++--- .../OtherOccurrenceNodeData.java | 104 ++++++++++++ 3 files changed, 194 insertions(+), 110 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 2a9fd30a49..ea886c1e93 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -466,31 +466,43 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi * * @return A collection of correlated artifact instances from other cases */ - private Map getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) { + private Map getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) { // @@@ Check exception try { final Case openCase = Case.getCurrentCase(); String caseUUID = openCase.getName(); - HashMap artifactInstances = new HashMap<>(); + HashMap nodeDataMap = new HashMap<>(); if (EamDb.isEnabled()) { - EamDb dbManager = EamDb.getInstance(); - artifactInstances.putAll(dbManager.getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).stream() - .filter(artifactInstance -> !artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID) - || !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName) - || !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)) - .collect(Collectors.toMap(correlationAttr -> new UniquePathKey(correlationAttr.getCorrelationDataSource().getDeviceID(), correlationAttr.getFilePath()), - correlationAttr -> correlationAttr))); - } + List instances = EamDb.getInstance().getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()); - if (corAttr.getCorrelationType().getDisplayName().equals("Files")) { - List caseDbFiles = addCaseDbMatches(corAttr, openCase); - for (AbstractFile caseDbFile : caseDbFiles) { - addOrUpdateAttributeInstance(openCase, artifactInstances, caseDbFile); + for (CorrelationAttributeInstance artifactInstance:instances) { + + // Only add the attribute if it isn't the object the user selected. + // We consider it to be a different object if at least one of the following is true: + // - the case UUID is different + // - the data source name is different + // - the data source device ID is different + // - (TODO) file path is different + if (!artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID) + || !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName) + || !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)) { + + OtherOccurrenceNodeData newNode = new OtherOccurrenceNodeData(artifactInstance, corAttr.getCorrelationType().getDisplayName(), corAttr.getCorrelationValue()); + UniquePathKey uniquePathKey = new UniquePathKey(newNode); + nodeDataMap.put(uniquePathKey, newNode); + } } } - return artifactInstances; + if (corAttr.getCorrelationType().getDisplayName().equals("Files")) { + List caseDbFiles = getCaseDbMatches(corAttr, openCase); + for (AbstractFile caseDbFile : caseDbFiles) { + addOrUpdateNodeData(openCase, nodeDataMap, caseDbFile); + } + } + + return nodeDataMap; } catch (EamDbException ex) { LOGGER.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS } catch (NoCurrentCaseException ex) { @@ -504,7 +516,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi return new HashMap<>(0); } - private List addCaseDbMatches(CorrelationAttribute corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException { + private List getCaseDbMatches(CorrelationAttribute corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException { String md5 = corAttr.getCorrelationValue(); SleuthkitCase tsk = openCase.getSleuthkitCase(); @@ -522,58 +534,44 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi } /** - * Adds the file to the artifactInstances map if it does not already exist + * Adds the file to the nodeDataMap map if it does not already exist * * @param autopsyCase - * @param artifactInstances + * @param nodeDataMap * @param newFile * @throws TskCoreException * @throws EamDbException */ - private void addOrUpdateAttributeInstance(final Case autopsyCase, Map artifactInstances, AbstractFile newFile) throws TskCoreException, EamDbException { + private void addOrUpdateNodeData(final Case autopsyCase, Map nodeDataMap, AbstractFile newFile) throws TskCoreException, EamDbException { - // figure out if the casedb file is known via either hash or tags - TskData.FileKnown localKnown = newFile.getKnown(); - - if (localKnown != TskData.FileKnown.BAD) { + OtherOccurrenceNodeData newNode = new OtherOccurrenceNodeData(newFile, autopsyCase); + + // If the caseDB object has a notable tag associated with it, update + // the known status to BAD + if (newNode.getKnown() != TskData.FileKnown.BAD) { List fileMatchTags = autopsyCase.getServices().getTagsManager().getContentTagsByContent(newFile); for (ContentTag tag : fileMatchTags) { TskData.FileKnown tagKnownStatus = tag.getName().getKnownStatus(); if (tagKnownStatus.equals(TskData.FileKnown.BAD)) { - localKnown = TskData.FileKnown.BAD; + newNode.updateKnown(TskData.FileKnown.BAD); break; } } } - // make a key to see if the file is already in the map - String filePath = newFile.getParentPath() + newFile.getName(); - String deviceId; - try { - deviceId = autopsyCase.getSleuthkitCase().getDataSource(newFile.getDataSource().getId()).getDeviceId(); - } catch (TskDataException | TskCoreException ex) { - LOGGER.log(Level.WARNING, "Error getting data source info: " + ex); - return; - } - UniquePathKey uniquePathKey = new UniquePathKey(deviceId, filePath); + // Make a key to see if the file is already in the map + UniquePathKey uniquePathKey = new UniquePathKey(newNode); - // double check that the CR version is BAD if the caseDB version is BAD. - if (artifactInstances.containsKey(uniquePathKey)) { - if (localKnown == TskData.FileKnown.BAD) { - CorrelationAttributeInstance prevInstance = artifactInstances.get(uniquePathKey); - prevInstance.setKnownStatus(localKnown); + // If this node is already in the list, the only thing we need to do is + // update the known status to BAD if the caseDB version had known status BAD. + // Otherwise, add the new node to the map. + if (nodeDataMap.containsKey(uniquePathKey)) { + if (newNode.getKnown() == TskData.FileKnown.BAD) { + OtherOccurrenceNodeData prevInstance = nodeDataMap.get(uniquePathKey); + prevInstance.updateKnown(newNode.getKnown()); } - } - // add the data from the case DB by pushing data into CorrelationAttributeInstance class - else { - // NOTE: If we are in here, it is likely because CR is not enabled. So, we cannot rely - // on any of the methods that query the DB. - CorrelationCase correlationCase = new CorrelationCase(autopsyCase.getName(), autopsyCase.getDisplayName()); - - CorrelationDataSource correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, newFile.getDataSource()); - - CorrelationAttributeInstance caseDbInstance = new CorrelationAttributeInstance(correlationCase, correlationDataSource, filePath, "", localKnown); - artifactInstances.put(uniquePathKey, caseDbInstance); + } else { + nodeDataMap.put(uniquePathKey, newNode); } } @@ -632,22 +630,13 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi // get the attributes we can correlate on correlationAttributes.addAll(getCorrelationAttributesFromNode(node)); for (CorrelationAttribute corAttr : correlationAttributes) { - Map corAttrInstances = new HashMap<>(0); + Map correlatedNodeDataMap = new HashMap<>(0); // get correlation and reference set instances from DB - corAttrInstances.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId)); + correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId)); - corAttrInstances.values().forEach((corAttrInstance) -> { - try { - CorrelationAttribute newCeArtifact = new CorrelationAttribute( - corAttr.getCorrelationType(), - corAttr.getCorrelationValue() - ); - newCeArtifact.addInstance(corAttrInstance); - tableModel.addEamArtifact(newCeArtifact); - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error creating correlation attribute", ex); - } + correlatedNodeDataMap.values().forEach((nodeData) -> { + tableModel.addNodeData(nodeData); }); } @@ -816,33 +805,26 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi private final String dataSourceID; private final String filePath; + private final String type; - UniquePathKey(String theDataSource, String theFilePath) { + UniquePathKey(OtherOccurrenceNodeData nodeData) { super(); - dataSourceID = theDataSource; - filePath = theFilePath.toLowerCase(); - } - - /** - * - * @return the dataSourceID device ID - */ - String getDataSourceID() { - return dataSourceID; - } - - /** - * - * @return the filPath including the filename and extension. - */ - String getFilePath() { - return filePath; + dataSourceID = nodeData.getDeviceID(); + if (nodeData.getFilePath() != null) { + filePath = nodeData.getFilePath().toLowerCase(); + } else { + filePath = null; + } + type = nodeData.getType(); } @Override public boolean equals(Object other) { if (other instanceof UniquePathKey) { - return ((UniquePathKey) other).getDataSourceID().equals(dataSourceID) && ((UniquePathKey) other).getFilePath().equals(filePath); + UniquePathKey otherKey = (UniquePathKey)(other); + return ( Objects.equals(otherKey.dataSourceID, this.dataSourceID) + && Objects.equals(otherKey.filePath, this.filePath) + && Objects.equals(otherKey.type, this.type)); } return false; } @@ -852,7 +834,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi //int hash = 7; //hash = 67 * hash + this.dataSourceID.hashCode(); //hash = 67 * hash + this.filePath.hashCode(); - return Objects.hash(dataSourceID, filePath); + return Objects.hash(dataSourceID, filePath, type); } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java index f0ecb31e72..5febf88dc3 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java @@ -68,10 +68,10 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { } }; - List eamArtifacts; + List nodeDataList; DataContentViewerOtherCasesTableModel() { - eamArtifacts = new ArrayList<>(); + nodeDataList = new ArrayList<>(); } @Override @@ -95,7 +95,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { @Override public int getRowCount() { - return eamArtifacts.size(); + return nodeDataList.size(); } @Override @@ -105,15 +105,15 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { @Override public Object getValueAt(int rowIdx, int colIdx) { - if (0 == eamArtifacts.size()) { + if (0 == nodeDataList.size()) { return Bundle.DataContentViewerOtherCasesTableModel_noData(); } return mapValueById(rowIdx, TableColumns.values()[colIdx]); } - public Object getRow(int rowIdx) { - return eamArtifacts.get(rowIdx); + Object getRow(int rowIdx) { + return nodeDataList.get(rowIdx); } /** @@ -125,40 +125,39 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { * @return value in the cell */ private Object mapValueById(int rowIdx, TableColumns colId) { - CorrelationAttribute eamArtifact = eamArtifacts.get(rowIdx); - CorrelationAttributeInstance eamArtifactInstance = eamArtifact.getInstances().get(0); + OtherOccurrenceNodeData nodeData = nodeDataList.get(rowIdx); String value = Bundle.DataContentViewerOtherCasesTableModel_noData(); switch (colId) { case CASE_NAME: - if (null != eamArtifactInstance.getCorrelationCase()) { - value = eamArtifactInstance.getCorrelationCase().getDisplayName(); + if (null != nodeData.getCaseName()) { + value = nodeData.getCaseName(); } break; case DEVICE: - if (null != eamArtifactInstance.getCorrelationDataSource()) { - value = eamArtifactInstance.getCorrelationDataSource().getDeviceID(); + if (null != nodeData.getDeviceID()) { + value = nodeData.getDeviceID(); } break; case DATA_SOURCE: - if (null != eamArtifactInstance.getCorrelationDataSource()) { - value = eamArtifactInstance.getCorrelationDataSource().getName(); + if (null != nodeData.getDataSourceName()) { + value = nodeData.getDataSourceName(); } break; case FILE_PATH: - value = eamArtifactInstance.getFilePath(); + value = nodeData.getFilePath(); break; case TYPE: - value = eamArtifact.getCorrelationType().getDisplayName(); + value = nodeData.getType(); break; case VALUE: - value = eamArtifact.getCorrelationValue(); + value = nodeData.getValue(); break; case KNOWN: - value = eamArtifactInstance.getKnownStatus().getName(); + value = nodeData.getKnown().getName(); break; case COMMENT: - value = eamArtifactInstance.getComment(); + value = nodeData.getComment(); break; } return value; @@ -170,18 +169,17 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { } /** - * Add one local central repository artifact to the table. + * Add one correlated instance object to the table * - * @param eamArtifact central repository artifact to add to the - * table + * @param newNodeData data to add to the table */ - public void addEamArtifact(CorrelationAttribute eamArtifact) { - eamArtifacts.add(eamArtifact); + void addNodeData(OtherOccurrenceNodeData newNodeData) { + nodeDataList.add(newNodeData); fireTableDataChanged(); } - public void clearTable() { - eamArtifacts.clear(); + void clearTable() { + nodeDataList.clear(); fireTableDataChanged(); } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java new file mode 100644 index 0000000000..c988ff30d9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java @@ -0,0 +1,104 @@ +/* + * Central Repository + * + * Copyright 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.centralrepository.contentviewer; + +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.datamodel.TskDataException; + +class OtherOccurrenceNodeData { + + private String caseName; + private String deviceID; + private String dataSourceName; + private final String filePath; + private final String type; + private final String value; + private TskData.FileKnown known; + private final String comment; + + OtherOccurrenceNodeData(CorrelationAttributeInstance instance, String type, String value) { + caseName = instance.getCorrelationCase().getDisplayName(); + deviceID = instance.getCorrelationDataSource().getDeviceID(); + dataSourceName = instance.getCorrelationDataSource().getName(); + filePath = instance.getFilePath(); + this.type = type; + this.value = value; + known = instance.getKnownStatus(); + comment = instance.getComment(); + } + + OtherOccurrenceNodeData(AbstractFile newFile, Case autopsyCase) throws EamDbException { + caseName = autopsyCase.getDisplayName(); + try { + DataSource dataSource = autopsyCase.getSleuthkitCase().getDataSource(newFile.getDataSource().getId()); + deviceID = dataSource.getDeviceId(); + dataSourceName = dataSource.getName(); + } catch (TskDataException | TskCoreException ex) { + throw new EamDbException("Error loading data source for abstract file ID " + newFile.getId()); + } + + filePath = newFile.getParentPath() + newFile.getName(); + type = "Files"; + value = newFile.getMd5Hash(); + known = newFile.getKnown(); + comment = ""; + } + + void updateKnown(TskData.FileKnown newKnownStatus) { + known = newKnownStatus; + } + + String getCaseName() { + return caseName; + } + + String getDeviceID() { + return deviceID; + } + + String getDataSourceName() { + return dataSourceName; + } + + String getFilePath() { + return filePath; + } + + String getType() { + return type; + } + + String getValue() { + return value; + } + + TskData.FileKnown getKnown() { + return known; + } + + String getComment() { + return comment; + } +} From dbfabd55e1bdeb7284882b0ac0cf95a11b3516d0 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 14 Jun 2018 16:12:17 -0400 Subject: [PATCH 20/29] Data sources renamed. --- Core/build.xml | 22 +++++++++---------- .../datamodel/CentralRepoDatamodelTest.java | 6 ++--- .../commonfilessearch/IntraCaseUtils.java | 17 +++++++------- .../autopsy/ingest/EmbeddedFileTest.java | 6 +++-- .../autopsy/ingest/IngestFileFiltersTest.java | 7 ++++-- .../EncryptionDetectionTest.java | 11 ++++++---- 6 files changed, 38 insertions(+), 31 deletions(-) diff --git a/Core/build.xml b/Core/build.xml index 98644b8cb3..6cba803539 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -89,17 +89,17 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java index 0f0e950ec6..f30038b5f5 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java @@ -44,7 +44,7 @@ import static junit.framework.Assert.assertTrue; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** - * + * Functional tests for the Central Repository data model. */ public class CentralRepoDatamodelTest extends TestCase { @@ -112,7 +112,7 @@ public class CentralRepoDatamodelTest extends TestCase { EamDbUtil.setUseCentralRepo(true); EamDbPlatformEnum.setSelectedPlatform(EamDbPlatformEnum.SQLITE.name()); EamDbPlatformEnum.saveSelectedPlatform(); - } catch (Exception ex) { + } catch (EamDbException ex) { Exceptions.printStackTrace(ex); Assert.fail(ex); } @@ -2499,7 +2499,7 @@ public class CentralRepoDatamodelTest extends TestCase { // This seems to help in allowing the Autopsy case to be deleted try { Thread.sleep(2000); - } catch (Exception ex) { + } catch (InterruptedException ex) { } } catch (CaseActionException ex) { diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/IntraCaseUtils.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/IntraCaseUtils.java index 66a68f3a38..39f18e0696 100644 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/IntraCaseUtils.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/IntraCaseUtils.java @@ -1,5 +1,4 @@ /* - * * Autopsy Forensic Browser * * Copyright 2018 Basis Technology Corp. @@ -84,20 +83,20 @@ class IntraCaseUtils { static final String PDF = "adsf.pdf"; //not a typo - it appears this way in the test image static final String EMPTY = "file.dat"; - static final String SET1 = "commonfiles_image1_v1.vhd"; - static final String SET2 = "commonfiles_image2_v1.vhd"; - static final String SET3 = "commonfiles_image3_v1.vhd"; - static final String SET4 = "commonfiles_image4_v1.vhd"; + static final String SET1 = "CommonFiles_img1_v1.vhd"; + static final String SET2 = "CommonFiles_img2_v1.vhd"; + static final String SET3 = "CommonFiles_img3_v1.vhd"; + static final String SET4 = "CommonFiles_img4_v1.vhd"; private final DataSourceLoader dataSourceLoader; private final String caseName; IntraCaseUtils(NbTestCase nbTestCase, String caseName){ - imagePath1 = Paths.get(nbTestCase.getDataDir().toString(), "commonfiles_image1_v1.vhd"); - imagePath2 = Paths.get(nbTestCase.getDataDir().toString(), "commonfiles_image2_v1.vhd"); - imagePath3 = Paths.get(nbTestCase.getDataDir().toString(), "commonfiles_image3_v1.vhd"); - imagePath4 = Paths.get(nbTestCase.getDataDir().toString(), "commonfiles_image4_v1.vhd"); + imagePath1 = Paths.get(nbTestCase.getDataDir().toString(), SET1); + imagePath2 = Paths.get(nbTestCase.getDataDir().toString(), SET2); + imagePath3 = Paths.get(nbTestCase.getDataDir().toString(), SET3); + imagePath4 = Paths.get(nbTestCase.getDataDir().toString(), SET4); this.dataSourceLoader = new DataSourceLoader(); diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java index 813c09334a..8f562d698b 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java @@ -39,11 +39,13 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.TskCoreException; +/** + * Functional tests for embedded files. + */ public class EmbeddedFileTest extends NbTestCase { private static final String CASE_NAME = "EmbeddedFileTest"; - private static final Path CASE_DIRECTORY_PATH = Paths.get(System.getProperty("java.io.tmpdir"), CASE_NAME); - private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(),"embedded.vhd"); + private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(), "EmbeddedIM_img1_v1.vhd"); public static final String HASH_VALUE = "098f6bcd4621d373cade4e832627b4f6"; private static final int DEEP_FOLDER_COUNT = 25; private Case openCase; diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java index fcb2b8a4ca..16b0f2f4a4 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java @@ -50,10 +50,13 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; +/** + * Functional tests for ingest file filters. + */ public class IngestFileFiltersTest extends NbTestCase { - private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(),"filter_test1.img"); - private final Path ZIPFILE_PATH = Paths.get(this.getDataDir().toString(), "local_files_test.zip"); + private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(),"IngestFilters_img1_v1.img"); + private final Path ZIPFILE_PATH = Paths.get(this.getDataDir().toString(), "IngestFilters_local1_v1.zip"); private boolean testSucceeded; diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionTest.java index ef639bec5f..dc1f85afcd 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionTest.java @@ -47,6 +47,9 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Volume; import org.sleuthkit.datamodel.VolumeSystem; +/** + * Functional tests for Encryption Detection. + */ public class EncryptionDetectionTest extends NbTestCase { private static final String BITLOCKER_DETECTION_CASE_NAME = "testBitlockerEncryption"; @@ -54,10 +57,10 @@ public class EncryptionDetectionTest extends NbTestCase { private static final String VERACRYPT_DETECTION_CASE_NAME = "VeraCryptDetectionTest"; private static final String SQLCIPHER_DETECTION_CASE_NAME = "SQLCipherDetectionTest"; - private final Path BITLOCKER_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "encryption_detection_bitlocker_test.vhd"); - private final Path PASSWORD_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "password_detection_test.img"); - private final Path VERACRYPT_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "veracrypt_detection_test.vhd"); - private final Path SQLCIPHER_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "encryption_detection_sqlcipher_test.vhd"); + private final Path BITLOCKER_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "BitlockerDetection_img1_v1.vhd"); + private final Path PASSWORD_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "PasswordDetection_img1_v1.img"); + private final Path VERACRYPT_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "VeracryptDetection_img1_v1.vhd"); + private final Path SQLCIPHER_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "SqlCipherDetection_img1_v1.vhd"); private boolean testSucceeded; From a31bab151a4ac06691d0a71be20a9e592f62a6c8 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 15 Jun 2018 09:02:32 -0400 Subject: [PATCH 21/29] Moved context menu creation to new provider. --- ...CentralRepoContextMenuActionsProvider.java | 56 +++++++++++++++++++ .../datamodel/AbstractAbstractFileNode.java | 15 ----- .../datamodel/BlackboardArtifactNode.java | 5 -- 3 files changed, 56 insertions(+), 20 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoContextMenuActionsProvider.java diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoContextMenuActionsProvider.java b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoContextMenuActionsProvider.java new file mode 100755 index 0000000000..5a6e8fa652 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoContextMenuActionsProvider.java @@ -0,0 +1,56 @@ +/* + * Central Repository + * + * Copyright 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.centralrepository; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.swing.Action; +import org.openide.util.Utilities; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil; +import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider; +import org.sleuthkit.datamodel.AbstractFile; + +/** + * This creates a single context menu item for adding or editing a Central + * Repository comment. + */ +@ServiceProvider(service = ContextMenuActionsProvider.class) +public class CentralRepoContextMenuActionsProvider implements ContextMenuActionsProvider { + + @Override + public List getActions() { + ArrayList actions = new ArrayList<>(); + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + + if (selectedFiles.size() != 1) { + return actions; + } + + for (AbstractFile file : selectedFiles) { + if (EamDbUtil.useCentralRepo() && EamArtifactUtil.isSupportedAbstractFileType(file) && file.isFile()) { + actions.add(AddEditCentralRepoCommentAction.createAddEditCentralRepoCommentAction(file)); + } + } + + return actions; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index c9b271a68e..28329f17c5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -258,21 +258,6 @@ public abstract class AbstractAbstractFileNode extends A map.put(EXTENSION.toString(), content.getNameExtension()); } - @Override - public Action[] getActions(boolean context) { - List actionsList = new ArrayList<>(); - - actionsList.addAll(Arrays.asList(super.getActions(true))); - - // Create the "Add/Edit Central Repository Comment" menu item if the enabled. - AbstractFile file = content; - if (EamDbUtil.useCentralRepo() && EamArtifactUtil.isSupportedAbstractFileType(file) && file.isFile()) { - actionsList.add(AddEditCentralRepoCommentAction.createAddEditCentralRepoCommentAction(file)); - } - - return actionsList.toArray(new Action[actionsList.size()]); - } - /** * Used by subclasses of AbstractAbstractFileNode to add the tags property * to their sheets. diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 9e003c5be4..235f00cb1b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -221,11 +221,6 @@ public class BlackboardArtifactNode extends AbstractContentNode Date: Fri, 15 Jun 2018 09:21:45 -0400 Subject: [PATCH 22/29] Disable the CR-based context menu items if CR is not enabled. With CR disabled, don't enabled the other occurrences tab if the file has no MD5. Added comments. --- .../DataContentViewerOtherCases.java | 36 ++++---- .../OtherOccurrenceNodeData.java | 90 +++++++++++++++++-- 2 files changed, 104 insertions(+), 22 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index e9ab49cbf6..298a8763fc 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -56,7 +56,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -69,7 +68,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskData; -import org.sleuthkit.datamodel.TskDataException; /** * View correlation results from other cases @@ -458,9 +456,10 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi } /** - * Query the database for artifact instances from other cases correlated to - * the given central repository artifact. Instances from the same datasource - * / device will also be included. + * Query the central repo database (if enabled) and the case database to find all + * artifact instances correlated to the given central repository artifact. If the + * central repo is not enabled, this will only return files from the current case + * with matching MD5 hashes. * * @param corAttr CorrelationAttribute to query for * @param dataSourceName Data source to filter results @@ -521,6 +520,15 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi return new HashMap<>(0); } + /** + * Get all other abstract files in the current case with the same MD5 as the selected node. + * @param corAttr The CorrelationAttribute containing the MD5 to search for + * @param openCase The current case + * @return List of matching AbstractFile objects + * @throws NoCurrentCaseException + * @throws TskCoreException + * @throws EamDbException + */ private List getCaseDbMatches(CorrelationAttribute corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException { String md5 = corAttr.getCorrelationValue(); @@ -570,7 +578,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi // If this node is already in the list, the only thing we need to do is // update the known status to BAD if the caseDB version had known status BAD. - // Otherwise, add the new node to the map. + // Otherwise this is a new node so add the new node to the map. if (nodeDataMap.containsKey(uniquePathKey)) { if (newNode.getKnown() == TskData.FileKnown.BAD) { OtherOccurrenceNodeData prevInstance = nodeDataMap.get(uniquePathKey); @@ -583,18 +591,20 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi @Override public boolean isSupported(Node node) { - this.file = this.getAbstractFileFromNode(node); - // Is supported if this node - // has correlatable content (File, BlackboardArtifact) OR - // other common files across datasources. + // Is supported if one of the following is true: + // - The central repo is enabled and the node has correlatable content + // (either through the MD5 hash of the associated file or through a BlackboardArtifact) + // - The central repo is disabled and the backing file has a valid MD5 hash + this.file = this.getAbstractFileFromNode(node); if (EamDb.isEnabled()) { return this.file != null && this.file.getSize() > 0 && !getCorrelationAttributesFromNode(node).isEmpty(); } else { return this.file != null - && this.file.getSize() > 0; + && this.file.getSize() > 0 + && ((this.file.getMd5Hash() != null) && ( ! this.file.getMd5Hash().isEmpty())); } } @@ -813,16 +823,12 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi private void rightClickPopupMenuPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_rightClickPopupMenuPopupMenuWillBecomeVisible boolean enableCentralRepoActions = false; - boolean enableComment = false; if (EamDbUtil.useCentralRepo() && otherCasesTable.getSelectedRowCount() == 1) { int rowIndex = otherCasesTable.getSelectedRow(); OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(rowIndex); if (selectedNode.isCentralRepoNode()) { enableCentralRepoActions = true; - if (selectedNode.isFileType()) { - enableComment = true; - } } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java index 57534eb15e..3a13955974 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java @@ -28,9 +28,14 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskDataException; +/** + * Class for populating the Other Occurrences tab + */ class OtherOccurrenceNodeData { - private final String FILE_TYPE = "Files"; + // For now hard code the string for the central repo files type, since + // getting it dynamically can fail. + private final String FILE_TYPE_STR = "Files"; private String caseName; private String deviceID; @@ -45,6 +50,12 @@ class OtherOccurrenceNodeData { private AbstractFile originalAbstractFile = null; private CorrelationAttributeInstance originalCorrelationInstance = null; + /** + * Create a node from a central repo instance. + * @param instance The central repo instance + * @param type The type of the instance + * @param value The value of the instance + */ OtherOccurrenceNodeData(CorrelationAttributeInstance instance, CorrelationAttribute.Type type, String value) { caseName = instance.getCorrelationCase().getDisplayName(); deviceID = instance.getCorrelationDataSource().getDeviceID(); @@ -59,6 +70,12 @@ class OtherOccurrenceNodeData { originalCorrelationInstance = instance; } + /** + * Create a node from an abstract file. + * @param newFile The abstract file + * @param autopsyCase The current case + * @throws EamDbException + */ OtherOccurrenceNodeData(AbstractFile newFile, Case autopsyCase) throws EamDbException { caseName = autopsyCase.getDisplayName(); try { @@ -70,8 +87,8 @@ class OtherOccurrenceNodeData { } filePath = newFile.getParentPath() + newFile.getName(); - typeStr = FILE_TYPE; - this.type = null; // TEMP + typeStr = FILE_TYPE_STR; + this.type = null; // We can't make the Type object without the central repo enabled value = newFile.getMd5Hash(); known = newFile.getKnown(); comment = ""; @@ -79,21 +96,34 @@ class OtherOccurrenceNodeData { originalAbstractFile = newFile; } + /** + * Check if this node is a "file" type + * @return true if it is a file type + */ boolean isFileType() { - return FILE_TYPE.equals(typeStr); + return FILE_TYPE_STR.equals(typeStr); } + /** + * Update the known status for this node + * @param newKnownStatus The new known status + */ void updateKnown(TskData.FileKnown newKnownStatus) { known = newKnownStatus; } + /** + * Check if this is a central repo node. + * @return true if this node was created from a central repo instance, false otherwise + */ boolean isCentralRepoNode() { return (originalCorrelationInstance != null); } /** - * Uses the saved instance plus type and value to make a new CorrelationAttribute - * @return + * Uses the saved instance plus type and value to make a new CorrelationAttribute. + * Should only be called if isCentralRepoNode() is true. + * @return the newly created CorrelationAttribute */ CorrelationAttribute createCorrelationAttribute() throws EamDbException { if (! isCentralRepoNode() ) { @@ -104,42 +134,88 @@ class OtherOccurrenceNodeData { return attr; } + /** + * Get the case name + * @return the case name + */ String getCaseName() { return caseName; } + /** + * Get the device ID + * @return the device ID + */ String getDeviceID() { return deviceID; } + /** + * Get the data source name + * @return the data source name + */ String getDataSourceName() { return dataSourceName; } + /** + * Get the file path + * @return the file path + */ String getFilePath() { return filePath; } + /** + * Get the type (as a string) + * @return the type + */ String getType() { return typeStr; } + /** + * Get the value (MD5 hash for files) + * @return the value + */ String getValue() { return value; } + /** + * Get the known status + * @return the known status + */ TskData.FileKnown getKnown() { return known; } + /** + * Get the comment + * @return the comment + */ String getComment() { return comment; } - AbstractFile getAbstractFile() { + /** + * Get the backing abstract file. + * Should only be called if isCentralRepoNode() is false + * @return the original abstract file + */ + AbstractFile getAbstractFile() throws EamDbException { + if (originalCorrelationInstance == null) { + throw new EamDbException("AbstractFile is null"); + } return originalAbstractFile; } + /** + * Get the backing CorrelationAttributeInstance. + * Should only be called if isCentralRepoNode() is true + * @return the original CorrelationAttributeInstance + * @throws EamDbException + */ CorrelationAttributeInstance getCorrelationAttributeInstance() throws EamDbException { if (originalCorrelationInstance == null) { throw new EamDbException("CorrelationAttributeInstance is null"); From 5eccf7b4deb2f7724b15973aa706aae38460ade7 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 15 Jun 2018 10:12:33 -0400 Subject: [PATCH 23/29] Update the comment in the UI --- .../AddEditCentralRepoCommentAction.java | 8 +++++++- .../centralrepository/CentralRepoCommentDialog.java | 11 ++++++++++- .../contentviewer/DataContentViewerOtherCases.java | 5 ++++- .../contentviewer/OtherOccurrenceNodeData.java | 12 ++++++++++-- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java index 8c03883523..e3f2899278 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java @@ -83,8 +83,12 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { * comment. The comment will be updated in the database if the file instance * exists there, or a new file instance will be added to the database with * the comment attached otherwise. + * + * The new comment is returned in case it is needed to update the display + * + * @return the newly added comment or null if it was not updated */ - public void addEditCentralRepoComment() { + public String addEditCentralRepoComment() { CentralRepoCommentDialog centralRepoCommentDialog = new CentralRepoCommentDialog(correlationAttribute, title); centralRepoCommentDialog.display(); @@ -102,7 +106,9 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { } catch (EamDbException ex) { logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); } + return centralRepoCommentDialog.getComment(); } + return null; } /** diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java index 4e42bfe9d7..35e005daed 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java @@ -31,6 +31,7 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { private final CorrelationAttribute correlationAttribute; private boolean commentUpdated = false; + private String comment = ""; /** * Create an instance. @@ -71,6 +72,14 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { boolean isCommentUpdated() { return commentUpdated; } + + /** + * Get the newly added comment + * @return the comment + */ + String getComment() { + return comment; + } /** * This method is called from within the constructor to initialize the form. @@ -168,7 +177,7 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { }//GEN-LAST:event_cancelButtonActionPerformed private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - String comment = commentTextArea.getText(); + comment = commentTextArea.getText(); correlationAttribute.getInstances().get(0).setComment(comment); commentUpdated = true; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 298a8763fc..de0c6467c8 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -120,7 +120,10 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi try { OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(otherCasesTable.getSelectedRow()); AddEditCentralRepoCommentAction action = AddEditCentralRepoCommentAction.createAddEditCommentAction(selectedNode.createCorrelationAttribute()); - action.addEditCentralRepoComment(); + String newComment = action.addEditCentralRepoComment(); + if (newComment != null) { + selectedNode.updateComment(newComment); + } otherCasesTable.repaint(); } catch (EamDbException ex) { logger.log(Level.SEVERE, "Error performing Add/Edit Comment action", ex); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java index 3a13955974..03d33b3140 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java @@ -45,7 +45,7 @@ class OtherOccurrenceNodeData { private final CorrelationAttribute.Type type; private final String value; private TskData.FileKnown known; - private final String comment; + private String comment; private AbstractFile originalAbstractFile = null; private CorrelationAttributeInstance originalCorrelationInstance = null; @@ -88,7 +88,7 @@ class OtherOccurrenceNodeData { filePath = newFile.getParentPath() + newFile.getName(); typeStr = FILE_TYPE_STR; - this.type = null; // We can't make the Type object without the central repo enabled + this.type = null; value = newFile.getMd5Hash(); known = newFile.getKnown(); comment = ""; @@ -112,6 +112,14 @@ class OtherOccurrenceNodeData { known = newKnownStatus; } + /** + * Update the comment for this node + * @param newComment The new comment + */ + void updateComment(String newComment) { + comment = newComment; + } + /** * Check if this is a central repo node. * @return true if this node was created from a central repo instance, false otherwise From 0766f645a6aeac9cacd221ed1d848bf9e24d8743 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 15 Jun 2018 10:59:56 -0400 Subject: [PATCH 24/29] Codacy --- .../contentviewer/OtherOccurrenceNodeData.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java index 03d33b3140..958068fb14 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrenceNodeData.java @@ -35,9 +35,9 @@ class OtherOccurrenceNodeData { // For now hard code the string for the central repo files type, since // getting it dynamically can fail. - private final String FILE_TYPE_STR = "Files"; + private static final String FILE_TYPE_STR = "Files"; - private String caseName; + private final String caseName; private String deviceID; private String dataSourceName; private final String filePath; @@ -83,7 +83,7 @@ class OtherOccurrenceNodeData { deviceID = dataSource.getDeviceId(); dataSourceName = dataSource.getName(); } catch (TskDataException | TskCoreException ex) { - throw new EamDbException("Error loading data source for abstract file ID " + newFile.getId()); + throw new EamDbException("Error loading data source for abstract file ID " + newFile.getId(), ex); } filePath = newFile.getParentPath() + newFile.getName(); From 1cf2028d877bb0ec4c19754b82a029049c3b94e0 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 15 Jun 2018 11:25:33 -0400 Subject: [PATCH 25/29] Save the current comment to prevent having to return null if the user cancels. Fix a few deprecated function calls. --- .../AddEditCentralRepoCommentAction.java | 8 ++++---- .../CentralRepoCommentDialog.java | 17 ++++++++++++----- .../DataContentViewerOtherCases.java | 6 ++---- .../datamodel/AbstractSqlEamDb.java | 2 +- .../datamodel/PostgresEamDbSettings.java | 2 +- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java index e3f2899278..dfeb4fbdcd 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java @@ -84,9 +84,10 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { * exists there, or a new file instance will be added to the database with * the comment attached otherwise. * - * The new comment is returned in case it is needed to update the display + * The current comment for this instance is returned in case it is needed to + * update the display. * - * @return the newly added comment or null if it was not updated + * @return the current comment for this instance */ public String addEditCentralRepoComment() { CentralRepoCommentDialog centralRepoCommentDialog = new CentralRepoCommentDialog(correlationAttribute, title); @@ -106,9 +107,8 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { } catch (EamDbException ex) { logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); } - return centralRepoCommentDialog.getComment(); } - return null; + return centralRepoCommentDialog.getComment(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java index 35e005daed..c95b0bfde7 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/CentralRepoCommentDialog.java @@ -31,7 +31,7 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { private final CorrelationAttribute correlationAttribute; private boolean commentUpdated = false; - private String comment = ""; + private String currentComment = ""; /** * Create an instance. @@ -45,6 +45,11 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { initComponents(); CorrelationAttributeInstance instance = correlationAttribute.getInstances().get(0); + + // Store the original comment + if (instance.getComment() != null) { + currentComment = instance.getComment(); + } pathLabel.setText(instance.getFilePath()); commentTextArea.setText(instance.getComment()); @@ -74,11 +79,13 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { } /** - * Get the newly added comment + * Get the current comment. + * If the user hit OK, this will be the new comment. + * If the user canceled, this will be the original comment. * @return the comment */ String getComment() { - return comment; + return currentComment; } /** @@ -177,8 +184,8 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog { }//GEN-LAST:event_cancelButtonActionPerformed private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - comment = commentTextArea.getText(); - correlationAttribute.getInstances().get(0).setComment(comment); + currentComment = commentTextArea.getText(); + correlationAttribute.getInstances().get(0).setComment(currentComment); commentUpdated = true; dispose(); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index de0c6467c8..15ed21d753 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -120,10 +120,8 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi try { OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(otherCasesTable.getSelectedRow()); AddEditCentralRepoCommentAction action = AddEditCentralRepoCommentAction.createAddEditCommentAction(selectedNode.createCorrelationAttribute()); - String newComment = action.addEditCentralRepoComment(); - if (newComment != null) { - selectedNode.updateComment(newComment); - } + String currentComment = action.addEditCentralRepoComment(); + selectedNode.updateComment(currentComment); otherCasesTable.repaint(); } catch (EamDbException ex) { logger.log(Level.SEVERE, "Error performing Add/Edit Comment action", ex); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index 45bc197283..59df6b7bbc 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -1772,7 +1772,7 @@ abstract class AbstractSqlEamDb implements EamDb { } catch (SQLException ex) { throw new EamDbException("Error getting all artifact instances from instances table", ex); } finally { - EamDbUtil.closePreparedStatement(preparedStatement); + EamDbUtil.closeStatement(preparedStatement); EamDbUtil.closeResultSet(resultSet); EamDbUtil.closeConnection(conn); } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java index 1154da273d..32de4e7646 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java @@ -221,7 +221,7 @@ public final class PostgresEamDbSettings { LOGGER.log(Level.SEVERE, "Failed to execute database existance query.", ex); // NON-NLS return false; } finally { - EamDbUtil.closePreparedStatement(ps); + EamDbUtil.closeStatement(ps); EamDbUtil.closeResultSet(rs); EamDbUtil.closeConnection(conn); } From fb20a28bc418321b5ca266ec7055d8ebf40c993f Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 15 Jun 2018 11:57:06 -0400 Subject: [PATCH 26/29] Changed IDs for the four CommonFiles VHD images. --- Core/build.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/build.xml b/Core/build.xml index 6cba803539..1ad7bacc14 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -96,10 +96,10 @@ - - - - + + + + From c4d09ebdb024c71dcc5fde4e6af1b1b44245462f Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 15 Jun 2018 16:01:21 -0400 Subject: [PATCH 27/29] Addressed review comments. --- .../casemodule/services/TagsManager.java | 141 ++---------------- .../datamodel/AbstractContentChildren.java | 2 +- ...y.java => AutopsyTreeChildrenFactory.java} | 22 +-- .../autopsy/datamodel/Bundle.properties | 3 +- .../autopsy/datamodel/Bundle_ja.properties | 1 + .../autopsy/datamodel/DataSourceGrouping.java | 11 +- .../datamodel/DataSourceGroupingChildren.java | 101 ------------- .../datamodel/DataSourceGroupingNode.java | 4 +- .../autopsy/datamodel/DataSourcesNode.java | 4 +- .../autopsy/datamodel/ExtractedContent.java | 8 +- .../DirectoryTreeTopComponent.java | 16 +- .../directorytree/ViewContextAction.java | 2 +- 12 files changed, 43 insertions(+), 272 deletions(-) rename Core/src/org/sleuthkit/autopsy/datamodel/{RootContentChildrenFactory.java => AutopsyTreeChildrenFactory.java} (85%) delete mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingChildren.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 0c5d7727d0..f094d2623b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -173,44 +173,18 @@ public class TagsManager implements Closeable { /** * Selects all of the rows from the tag_names table in the case database for * which there is at least one matching row in the content_tags or - * blackboard_artifact_tags tables, for the given datasource object id. + * blackboard_artifact_tags tables, for the given data source object id. * + * @param dsObjId data source object id + * * @return A list, possibly empty, of TagName data transfer objects (DTOs) * for the rows. * * @throws TskCoreException */ public List getTagNamesInUse(long dsObjId) throws TskCoreException { - - - ArrayList tagNames = new ArrayList<>(); - String queryStr = "SELECT * FROM tag_names " - + "WHERE tag_name_id IN " - + "( SELECT content_tags.tag_name_id as tag_name_id " - + "FROM content_tags as content_tags, tsk_files as tsk_files" - + " WHERE content_tags.obj_id = tsk_files.obj_id" - + " AND tsk_files.data_source_obj_id = " + dsObjId - + " UNION " - + "SELECT artifact_tags.tag_name_id as tag_name_id " - + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts " - + " WHERE artifact_tags.artifact_id = arts.artifact_id" - + " AND arts.data_source_obj_id = " + dsObjId - + " )"; - - try (CaseDbQuery query = caseDb.executeQuery(queryStr);) { - ResultSet resultSet = query.getResultSet(); - while (resultSet.next()) { - tagNames.add(new TagName(resultSet.getLong("tag_name_id"), resultSet.getString("display_name"), - resultSet.getString("description"), TagName.HTML_COLOR.getColorByName(resultSet.getString("color")), - TskData.FileKnown.valueOf(resultSet.getByte("knownStatus")))); //NON-NLS - } - return tagNames; - } catch (SQLException | TskCoreException ex) { - throw new TskCoreException("Failed to get tag names in use for data source objID : " + dsObjId, ex); - } - + return caseDb.getTagNamesInUse(dsObjId); } - /** * Gets a map of tag display names to tag name entries in the case database. * It has keys for the display names of the standard tag types, the current @@ -461,29 +435,7 @@ public class TagsManager implements Closeable { * the case database. */ public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException { - - if (tagName.getId() == Tag.ID_NOT_SET) { - throw new TskCoreException("TagName object is invalid, id not set"); - } - - String queryStr = - "SELECT COUNT(*) AS count " - + " FROM content_tags as content_tags, tsk_files as tsk_files " - + " WHERE content_tags.obj_id = tsk_files.obj_id" - + " AND tsk_files.data_source_obj_id = " + dsObjId - + " AND content_tags.tag_name_id = " + tagName.getId(); - - try (CaseDbQuery query = caseDb.executeQuery(queryStr);) { - ResultSet resultSet = query.getResultSet(); - if (resultSet.next()) { - return resultSet.getLong("count"); - } else { - throw new TskCoreException("Error getting content_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId ); - } - } catch (SQLException | TskCoreException ex) { - throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex); - } - + return caseDb.getContentTagsCountByTagName(tagName, dsObjId); } /** @@ -520,7 +472,7 @@ public class TagsManager implements Closeable { * * @param tagName The tag name of interest. * - * @param dsObjId + * @param dsObjId data source object id * * @return A list, possibly empty, of the content tags with the specified * tag name, and for the given data source. @@ -529,32 +481,7 @@ public class TagsManager implements Closeable { * case database. */ public List getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException { - - if (tagName.getId() == Tag.ID_NOT_SET) { - throw new TskCoreException("TagName object is invalid, id not set"); - } - - String queryStr = - "SELECT * " - + " FROM content_tags as content_tags, tsk_files as tsk_files " - + " WHERE content_tags.obj_id = tsk_files.obj_id" - + " AND tsk_files.data_source_obj_id = " + dsObjId - + " AND content_tags.tag_name_id = " + tagName.getId(); - - try (CaseDbQuery query = caseDb.executeQuery(queryStr);) { - ResultSet resultSet = query.getResultSet(); - ArrayList tags = new ArrayList<>(); - while (resultSet.next()) { - ContentTag tag = new ContentTag(resultSet.getLong("tag_id"), caseDb.getContentById(resultSet.getLong("obj_id")), - tagName, resultSet.getString("comment"), resultSet.getLong("begin_byte_offset"), resultSet.getLong("end_byte_offset")); //NON-NLS - tags.add(tag); - } - resultSet.close(); - return tags; - } catch (SQLException | TskCoreException ex) { - throw new TskCoreException("Failed to get content_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex); - } - + return caseDb.getContentTagsByTagName(tagName, dsObjId); } /** @@ -664,7 +591,7 @@ public class TagsManager implements Closeable { * @param tagName The representation of the desired tag type in the case * database, which can be obtained by calling getTagNames * and/or addTagName. - * @param dsObjId + * @param dsObjId data source object id * * @return A count of the artifact tags with the specified tag name, * for the given data source. @@ -673,28 +600,7 @@ public class TagsManager implements Closeable { * the case database. */ public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException { - if (tagName.getId() == Tag.ID_NOT_SET) { - throw new TskCoreException("TagName object is invalid, id not set"); - } - - String queryStr = "SELECT COUNT(*) AS count " - + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts " - + " WHERE artifact_tags.artifact_id = arts.artifact_id" - + " AND artifact_tags.tag_name_id = " + tagName.getId() - + " AND arts.data_source_obj_id = " + dsObjId - ; - - try (CaseDbQuery query = Case.getCurrentCaseThrows().getSleuthkitCase().executeQuery(queryStr);) { - ResultSet resultSet = query.getResultSet(); - if (resultSet.next()) { - return resultSet.getLong("count"); - } else { - throw new TskCoreException("Error getting blackboard_artifact_tags row count for tag name (tag_name_id = " + tagName.getId() + ")" + " for dsObjId = " + dsObjId); - } - } catch (SQLException | TskCoreException | NoCurrentCaseException ex) { - throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex); - } - + return caseDb.getBlackboardArtifactTagsCountByTagName(tagName, dsObjId); } /** @@ -734,7 +640,7 @@ public class TagsManager implements Closeable { * @param tagName The representation of the desired tag type in the case * database, which can be obtained by calling getTagNames * and/or addTagName. - * @param dsObjId + * @param dsObjId data source object id * * @return A list, possibly empty, of the artifact tags with the specified * tag name, for the specified data source. @@ -743,32 +649,7 @@ public class TagsManager implements Closeable { * case database. */ public List getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException { - if (tagName.getId() == Tag.ID_NOT_SET) { - throw new TskCoreException("TagName object is invalid, id not set"); - } - - String queryStr = "SELECT * " - + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts " - + " WHERE artifact_tags.artifact_id = arts.artifact_id" - + " AND artifact_tags.tag_name_id = " + tagName.getId() - + " AND arts.data_source_obj_id = " + dsObjId - ; - - try (CaseDbQuery query = Case.getCurrentCaseThrows().getSleuthkitCase().executeQuery(queryStr);) { - ResultSet resultSet = query.getResultSet(); - ArrayList tags = new ArrayList<>(); - while (resultSet.next()) { - BlackboardArtifact artifact = caseDb.getBlackboardArtifact(resultSet.getLong("artifact_id")); //NON-NLS - Content content = caseDb.getContentById(artifact.getObjectID()); - BlackboardArtifactTag tag = new BlackboardArtifactTag(resultSet.getLong("tag_id"), - artifact, content, tagName, resultSet.getString("comment")); //NON-NLS - tags.add(tag); - } - return tags; - } catch (SQLException | TskCoreException | NoCurrentCaseException ex) { - throw new TskCoreException("Failed to get blackboard_artifact_tags row count for tag_name_id = " + tagName.getId() + "data source objID : " + dsObjId, ex); - } - + return caseDb.getBlackboardArtifactTagsByTagName(tagName, dsObjId); } /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index 9d47861786..71705d2725 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -202,7 +202,7 @@ abstract class AbstractContentChildren extends Keys { @Override public AbstractNode visit(DataSourceGrouping datasourceGrouping) { - return new DataSourceGroupingNode(datasourceGrouping.getgDataSource()); + return new DataSourceGroupingNode(datasourceGrouping.getDataSource()); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildrenFactory.java similarity index 85% rename from Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java rename to Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildrenFactory.java index 276f4c3f17..cc3b8cb8ae 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildrenFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildrenFactory.java @@ -24,8 +24,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; import java.util.List; -import java.util.Observable; -import java.util.Observer; import java.util.logging.Level; import org.openide.nodes.ChildFactory; import org.openide.nodes.Node; @@ -39,19 +37,19 @@ import org.sleuthkit.datamodel.TskCoreException; /** - * Child factory to create the top level children of the root of the directory tree + * Child factory to create the top level children of the autopsy tree * */ -public class RootContentChildrenFactory extends ChildFactory.Detachable implements Observer { +public class AutopsyTreeChildrenFactory extends ChildFactory.Detachable { - private static final Logger logger = Logger.getLogger(RootContentChildrenFactory.class.getName()); + private static final Logger logger = Logger.getLogger(AutopsyTreeChildrenFactory.class.getName()); private final SleuthkitCase tskCase; /** - * Constructs the child factory for root nodes + * Constructs the child factory * @param tskCase */ - public RootContentChildrenFactory(SleuthkitCase tskCase) { + public AutopsyTreeChildrenFactory(SleuthkitCase tskCase) { this.tskCase = tskCase; } @@ -81,15 +79,11 @@ public class RootContentChildrenFactory extends ChildFactory.Detachable Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl); } - @Override - public void update(Observable observable, Object arg) { - refresh(true); - } - /** * Creates keys for the top level children. * * @param list list of keys created + * @return true, indicating that the key list is complete */ @Override protected boolean createKeys(List list) { @@ -99,7 +93,7 @@ public class RootContentChildrenFactory extends ChildFactory.Detachable List dataSources = tskCase.getDataSources(); List keys = new ArrayList<>(); dataSources.forEach((datasource) -> { - keys.add(new DataSourceGrouping(tskCase, datasource)); + keys.add(new DataSourceGrouping(datasource)); }); list.addAll(keys); @@ -117,7 +111,7 @@ public class RootContentChildrenFactory extends ChildFactory.Detachable } } catch (TskCoreException tskCoreException) { - logger.log(Level.SEVERE, "Error getting datas sources list form the database.", tskCoreException); + logger.log(Level.SEVERE, "Error getting datas sources list from the database.", tskCoreException); } return true; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index f392d406d3..374c96069b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -55,7 +55,8 @@ DataModelActionsFactory.fileInDir.text=View File in Directory DataModelActionsFactory.viewNewWin.text=View in New Window DataModelActionsFactory.openExtViewer.text=Open in External Viewer DataModelActionsFactory.srfFileSameMD5.text=Search for files with the same MD5 hash -DataSourcesNode.name=Data Source Files +DataSourcesNode.name=Data Sources +DataSourcesNode.group_by_datasource.name=Data Source Files DataSourcesNode.createSheet.name.name=Name DataSourcesNode.createSheet.name.displayName=Name DataSourcesNode.createSheet.name.desc=no description diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle_ja.properties index 3d20fded35..979c4d50cb 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle_ja.properties @@ -57,6 +57,7 @@ DataModelActionsFactory.viewNewWin.text=\u65b0\u898f\u30a6\u30a3\u30f3\u30c9\u30 DataModelActionsFactory.openExtViewer.text=\u5916\u90e8\u30d3\u30e5\u30fc\u30a2\u306b\u8868\u793a DataModelActionsFactory.srfFileSameMD5.text=\u540c\u3058MD5\u30cf\u30c3\u30b7\u30e5\u3092\u6301\u3064\u30d5\u30a1\u30a4\u30eb\u3092\u691c\u7d22 DataSourcesNode.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9 +DataSourcesNode.group_by_datasource.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb DataSourcesNode.createSheet.name.name=\u540d\u524d DataSourcesNode.createSheet.name.displayName=\u540d\u524d DataSourcesNode.createSheet.name.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093 diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGrouping.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGrouping.java index 360ee735ce..91ae285c81 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGrouping.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGrouping.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.datamodel; import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.SleuthkitCase; /** * A top level UI grouping of Files, Views, Results, Tags @@ -28,15 +27,13 @@ import org.sleuthkit.datamodel.SleuthkitCase; */ public class DataSourceGrouping implements AutopsyVisitableItem { - private final SleuthkitCase skCase; private final DataSource dataSource; - public DataSourceGrouping(SleuthkitCase skCase, DataSource dataSource) { - this.skCase = skCase; + public DataSourceGrouping(DataSource dataSource) { this.dataSource = dataSource; } - DataSource getgDataSource() { + DataSource getDataSource() { return this.dataSource; } @@ -45,8 +42,4 @@ public class DataSourceGrouping implements AutopsyVisitableItem { return visitor.visit(this); } - public SleuthkitCase getSleuthkitCase() { - return skCase; - } - } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingChildren.java deleted file mode 100644 index 3463d807dc..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingChildren.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 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 java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.Collections; -import java.util.EnumSet; -import java.util.List; -import java.util.logging.Level; -import org.openide.nodes.Children; -import org.openide.nodes.Node; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Child factory for Data Source grouping nodes - * A node is created for each data source in the case - * - */ -public class DataSourceGroupingChildren extends Children.Keys { - - private static final Logger logger = Logger.getLogger(DataSourceGroupingChildren.class.getName()); - private final SleuthkitCase sleuthkitCase; - - - - /** - * Constructs the factory object - * - * @param tskCase - Case DB - */ - public DataSourceGroupingChildren(SleuthkitCase tskCase) { - this.sleuthkitCase = tskCase; - } - - /** - * Listener for handling DATA_SOURCE_ADDED events. - */ - private final PropertyChangeListener pcl = new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - String eventType = evt.getPropertyName(); - if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { - reloadKeys(); - } - } - }; - - private void reloadKeys() { - try { - List keys = sleuthkitCase.getDataSources(); - setKeys(keys); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get Datasources from DB", ex); - } - } - - @Override - protected void addNotify() { - super.addNotify(); - Case.addEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl); - reloadKeys(); - } - - @Override - protected void removeNotify() { - super.removeNotify(); - Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl); - setKeys(Collections.emptyList()); - } - - @Override - protected Node[] createNodes(DataSource datasource) { - return new Node[]{createNodeForKey(datasource)}; - } - - protected Node createNodeForKey(DataSource datasource) { - return new DataSourceGroupingNode(datasource); - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java index 43054427a3..4c8ee90e7c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java @@ -34,12 +34,12 @@ import org.sleuthkit.datamodel.LocalFilesDataSource; * Data source grouping node - an optional grouping node in the data tree view * */ -public class DataSourceGroupingNode extends DisplayableItemNode { +class DataSourceGroupingNode extends DisplayableItemNode { private static final Logger logger = Logger.getLogger(DataSourceGroupingNode.class.getName()); /** - * Creates the Data source grouping node for the given data source, + * Creates a data source grouping node for the given data source. * * @param dataSource specifies the data source */ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index 8441b8aaad..d4e0ebf261 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -42,6 +42,7 @@ import org.sleuthkit.datamodel.TskDataException; public class DataSourcesNode extends DisplayableItemNode { public static final String NAME = NbBundle.getMessage(DataSourcesNode.class, "DataSourcesNode.name"); + private final String displayName; // NOTE: The images passed in via argument will be ignored. @Deprecated @@ -55,12 +56,13 @@ public class DataSourcesNode extends DisplayableItemNode { public DataSourcesNode(long dsObjId) { super(new DataSourcesNodeChildren(dsObjId), Lookups.singleton(NAME)); + displayName = (dsObjId > 0) ? NbBundle.getMessage(DataSourcesNode.class, "DataSourcesNode.group_by_datasource.name") : NAME; init(); } private void init() { setName(NAME); - setDisplayName(NAME); + setDisplayName(displayName); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png"); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 409b730345..366aa12979 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -81,7 +81,7 @@ public class ExtractedContent implements AutopsyVisitableItem { public ExtractedContent(SleuthkitCase skCase, long objId) { this.skCase = skCase; this.datasourceObjId = objId; - this.blackboard = new Blackboard(skCase); + this.blackboard = skCase.getBlackboard(); } @Override @@ -292,7 +292,7 @@ public class ExtractedContent implements AutopsyVisitableItem { if (skCase != null) { try { List types = (UserPreferences.groupItemsInTreeByDatasource()) ? - blackboard.getArtifactTypesInUseByDataSource(datasourceObjId) : + blackboard.getArtifactTypesInUse(datasourceObjId) : skCase.getArtifactTypesInUse() ; types.removeAll(doNotShow); @@ -357,7 +357,7 @@ public class ExtractedContent implements AutopsyVisitableItem { // "getBlackboardArtifactCount()" method to skCase try { this.childCount = UserPreferences.groupItemsInTreeByDatasource() ? - blackboard.getBlackboardArtifactsCountByDataSource(type.getTypeID(), datasourceObjId) : + blackboard.getArtifactsCount(type.getTypeID(), datasourceObjId) : skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); } catch (TskException ex) { Logger.getLogger(TypeNode.class.getName()) @@ -482,7 +482,7 @@ public class ExtractedContent implements AutopsyVisitableItem { try { List arts = UserPreferences.groupItemsInTreeByDatasource() ? - blackboard.getBlackboardArtifactsByDataSource(type.getTypeID(), datasourceObjId) : + blackboard.getArtifacts(type.getTypeID(), datasourceObjId) : skCase.getBlackboardArtifacts(type.getTypeID()); list.addAll(arts); } catch (TskException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 596552262d..33977d5904 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -73,7 +73,7 @@ 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.RootContentChildrenFactory; +import org.sleuthkit.autopsy.datamodel.AutopsyTreeChildrenFactory; import org.sleuthkit.autopsy.datamodel.ViewsNode; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.autopsy.datamodel.accounts.BINRange; @@ -102,8 +102,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat private final LinkedList forwardList; private static final String PREFERRED_ID = "DirectoryTreeTopComponent"; //NON-NLS private static final Logger LOGGER = Logger.getLogger(DirectoryTreeTopComponent.class.getName()); - private RootContentChildrenFactory rootChildrenFactory; - private Children contentChildren; + private AutopsyTreeChildrenFactory autopsyTreeChildrenFactory; + private Children autopsyTreeChildren; /** * the constructor @@ -397,9 +397,9 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // if there's at least one image, load the image and open the top component final SleuthkitCase tskCase = currentCase.getSleuthkitCase(); - rootChildrenFactory = new RootContentChildrenFactory(tskCase); - contentChildren = Children.create(rootChildrenFactory, true); - Node root = new AbstractNode(contentChildren) { + autopsyTreeChildrenFactory = new AutopsyTreeChildrenFactory(tskCase); + autopsyTreeChildren = Children.create(autopsyTreeChildrenFactory, true); + Node root = new AbstractNode(autopsyTreeChildren) { //JIRA-2807: What is the point of these overrides? /** * to override the right click action in the white blank space @@ -512,7 +512,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat @Override public void componentClosed() { //@@@ push the selection node to null? - contentChildren = null; + autopsyTreeChildren = null; } void writeProperties(java.util.Properties p) { @@ -808,7 +808,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat private void rebuildTree() { // refresh all children of the root. - rootChildrenFactory.refreshChildren(); + autopsyTreeChildrenFactory.refreshChildren(); // Select the first node and reset the selection history // This should happen on the EDT once the tree has been rebuilt. diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index 9798216b9b..f4da3a3edf 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -147,7 +147,7 @@ public class ViewContextAction extends AbstractAction { try { // get the objid/name of the datasource of the selected content. skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - long contentDSObjid = skCase.getDataSourceObjectId(content.getId()); + long contentDSObjid = content.getDataSource().getId(); DataSource datasource = skCase.getDataSource(contentDSObjid); dsname = datasource.getName(); From a1a73786d85c547247a8b5603b7352842df4ba43 Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 15 Jun 2018 16:12:25 -0400 Subject: [PATCH 28/29] Remove unused imports --- .../sleuthkit/autopsy/casemodule/services/TagsManager.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index f094d2623b..d80feed87a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -20,8 +20,6 @@ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -38,8 +36,6 @@ import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; -import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; From 0361ba7a4545a1f80a8eaffadac0b1f62c0d3c21 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 18 Jun 2018 14:02:52 -0400 Subject: [PATCH 29/29] Update Autopsy version numbers to 4.8.0 --- .../org/sleuthkit/autopsy/corecomponents/Bundle.properties | 2 +- docs/doxygen-user/Doxyfile | 4 ++-- docs/doxygen/Doxyfile | 6 +++--- nbproject/project.properties | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index bae8218148..bb98cc90f6 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -26,7 +26,7 @@ LBL_Description=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2018.
URL_ON_IMG=http://www.sleuthkit.org/ -URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.7.0/ +URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.8.0/ FILE_FOR_LOCAL_HELP=file:/// INDEX_FOR_LOCAL_HELP=/docs/index.html LBL_Close=Close diff --git a/docs/doxygen-user/Doxyfile b/docs/doxygen-user/Doxyfile index 84605ac34f..ee0a85b2dd 100755 --- a/docs/doxygen-user/Doxyfile +++ b/docs/doxygen-user/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy User Documentation" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.7.0 +PROJECT_NUMBER = 4.8.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -1025,7 +1025,7 @@ GENERATE_HTML = YES # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_OUTPUT = 4.7.0 +HTML_OUTPUT = 4.8.0 # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 5dbdbf1479..7facd03b19 100755 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -38,10 +38,10 @@ PROJECT_NAME = "Autopsy" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.7.0 +PROJECT_NUMBER = 4.8.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer a +# for a project that appears a the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = "Graphical digital forensics platform for The Sleuth Kit and other tools." @@ -1063,7 +1063,7 @@ GENERATE_HTML = YES # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_OUTPUT = api-docs/4.7.0/ +HTML_OUTPUT = api-docs/4.8.0/ # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). diff --git a/nbproject/project.properties b/nbproject/project.properties index 3cbde84d3e..1ce749b501 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -4,10 +4,10 @@ app.title=Autopsy ### lowercase version of above app.name=${branding.token} ### if left unset, version will default to today's date -app.version=4.7.0 +app.version=4.8.0 ### build.type must be one of: DEVELOPMENT, RELEASE -#build.type=RELEASE -build.type=DEVELOPMENT +build.type=RELEASE +#build.type=DEVELOPMENT project.org.netbeans.progress=org-netbeans-api-progress project.org.sleuthkit.autopsy.experimental=Experimental