From 3a16b1433b502b72a011a6159a8f44b242074461 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 13 Apr 2021 13:58:43 -0400 Subject: [PATCH 01/21] Extended IG message dialog --- .../autopsy/imagegallery/actions/Bundle.properties-MERGED | 2 +- .../org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/Bundle.properties-MERGED b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/Bundle.properties-MERGED index 32b96181cb..8dea95da62 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/Bundle.properties-MERGED +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/Bundle.properties-MERGED @@ -37,7 +37,7 @@ OpenAction.noControllerDialog.text=An initialization error ocurred.\nPlease see OpenAction.notAnalyzedDlg.msg=No image/video files available to display yet.\nPlease run FileType and EXIF ingest modules. OpenAction.openTopComponent.error.message=An error occurred while attempting to open Image Gallery. OpenAction.openTopComponent.error.title=Failed to open Image Gallery -OpenAction.stale.confDlg.msg=The image / video database may be out of date. Do you want to update and listen for further ingest results?\nChoosing 'yes' will update the database and enable listening to future ingests. +OpenAction.stale.confDlg.msg=The image / video database may be out of date. Do you want to update and listen for further ingest results?\nChoosing 'yes' will update the database and enable listening to future ingests.\n\nDatabase update status will appear in the lower right corner of the application window. OpenAction.stale.confDlg.title=Image Gallery OpenExternalViewerAction.displayName=External Viewer RedoAction.name=Redo diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java index 92ea324105..4c286c5345 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java @@ -69,7 +69,8 @@ import org.sleuthkit.datamodel.TskCoreException; @Messages({"CTL_OpenAction=Images/Videos", "OpenAction.stale.confDlg.msg=The image / video database may be out of date. " + "Do you want to update and listen for further ingest results?\n" - + "Choosing 'yes' will update the database and enable listening to future ingests.", + + "Choosing 'yes' will update the database and enable listening to future ingests.\n\n" + + "Database update status will appear in the lower right corner of the application window.", "OpenAction.notAnalyzedDlg.msg=No image/video files available to display yet.\n" + "Please run FileType and EXIF ingest modules.", "OpenAction.stale.confDlg.title=Image Gallery"}) From 50121eccca8b69f5e5a4f50cffb3c5d96e81dcf9 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 28 Apr 2021 15:48:41 -0400 Subject: [PATCH 02/21] 7534 Modify actions to no longer construct top components when case closed --- .../menuactions/Bundle.properties-MERGED | 3 + .../menuactions/DataContentDynamicMenu.java | 64 +++++++++---------- .../autopsy/menuactions/SearchResultMenu.java | 51 +++++++-------- 3 files changed, 57 insertions(+), 61 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/menuactions/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/menuactions/Bundle.properties-MERGED index 27a95765fe..c13b676b92 100755 --- a/Core/src/org/sleuthkit/autopsy/menuactions/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/menuactions/Bundle.properties-MERGED @@ -1,3 +1,5 @@ +DataContentDynamicMenu.contentViewers.text=Content Viewers +DataContentDynamicMenu.mainContentViewer.name=Main OpenIDE-Module-Name=MenuActions DataContentDynamicMenu.menu.dataContentWin.text=Data Content Windows DataContentMenu.getName.text=DataContent Menu @@ -5,3 +7,4 @@ DataExplorerMenu.getName.text=DataExplorer Tools DataResultMenu.menu.dataResWin.text=DataResult Windows DataResultMenu.getName.text=DataResult Menu SearchResultMenu.menu.dataRes.text=Data Results +SearchResultMenu.resultViewers.text=Result Viewers diff --git a/Core/src/org/sleuthkit/autopsy/menuactions/DataContentDynamicMenu.java b/Core/src/org/sleuthkit/autopsy/menuactions/DataContentDynamicMenu.java index b025cebf79..876f4623af 100644 --- a/Core/src/org/sleuthkit/autopsy/menuactions/DataContentDynamicMenu.java +++ b/Core/src/org/sleuthkit/autopsy/menuactions/DataContentDynamicMenu.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2018 Basis Technology Corp. + * Copyright 2011-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,60 +23,53 @@ import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuItem; import org.openide.awt.DynamicMenuContent; -import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.windows.TopComponent; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent; import org.sleuthkit.autopsy.corecomponents.DataContentTopComponent; /** - * - * @author jantonius + * Class to provide menu access to the various instances of the content viewer + * suite. */ class DataContentDynamicMenu extends JMenuItem implements DynamicMenuContent { + private static final long serialVersionUID = 1L; + + @NbBundle.Messages({"DataContentDynamicMenu.mainContentViewer.name=Main", + "DataContentDynamicMenu.contentViewers.text=Content Viewers"}) @Override public JComponent[] getMenuPresenters() { - List newWindowLists = DataContentTopComponent.getNewWindowList(); + JMenu submenu = new JMenu(Bundle.DataContentDynamicMenu_contentViewers_text()); + if (Case.isCaseOpen()) { - // Get DataContent provider to include in the menu - int totalItems = newWindowLists.size() > 0 ? 2 : 1; - JComponent[] comps = new JComponent[totalItems]; - int counter = 0; + List newWindowLists = DataContentTopComponent.getNewWindowList(); - TopComponent contentWin = DataContentTopComponent.findInstance(); - JMenuItem defaultItem = new JMenuItem(contentWin.getName()); // set the main name - - defaultItem.addActionListener(new OpenTopComponentAction(contentWin)); - - try { - Case currentCase = Case.getCurrentCaseThrows(); - defaultItem.setEnabled(currentCase.hasData()); - } catch (NoCurrentCaseException ex) { - defaultItem.setEnabled(false); // disable the menu when no case is opened - } - - comps[counter++] = defaultItem; - - // add the submenu - if (newWindowLists != null) { - if (newWindowLists.size() > 0) { - - JMenu submenu = new JMenu( - NbBundle.getMessage(this.getClass(), "DataContentDynamicMenu.menu.dataContentWin.text")); + TopComponent contentWin = DataContentTopComponent.findInstance(); + JMenuItem defaultItem = new JMenuItem(Bundle.DataContentDynamicMenu_mainContentViewer_name()); // set the main name + defaultItem.addActionListener(new OpenTopComponentAction(contentWin)); + try { + Case currentCase = Case.getCurrentCaseThrows(); + defaultItem.setEnabled(currentCase.hasData()); + } catch (NoCurrentCaseException ex) { + defaultItem.setEnabled(false); // disable the menu when no case is opened + } + submenu.add(defaultItem); + // add the submenu + if (!newWindowLists.isEmpty()) { for (int i = 0; i < newWindowLists.size(); i++) { DataContentTopComponent dctc = newWindowLists.get(i); JMenuItem item = new JMenuItem(dctc.getName()); item.addActionListener(new OpenTopComponentAction(dctc)); submenu.add(item); } - - comps[counter++] = submenu; } - } + } + submenu.setEnabled(submenu.getItemCount() > 0); + JComponent[] comps = new JComponent[1]; + comps[0] = submenu; return comps; } @@ -84,4 +77,9 @@ class DataContentDynamicMenu extends JMenuItem implements DynamicMenuContent { public JComponent[] synchMenuPresenters(JComponent[] jcs) { return getMenuPresenters(); } + + @Override + public boolean isEnabled() { + return Case.isCaseOpen(); + } } diff --git a/Core/src/org/sleuthkit/autopsy/menuactions/SearchResultMenu.java b/Core/src/org/sleuthkit/autopsy/menuactions/SearchResultMenu.java index 43ad5b2f7d..da1fc5a83f 100644 --- a/Core/src/org/sleuthkit/autopsy/menuactions/SearchResultMenu.java +++ b/Core/src/org/sleuthkit/autopsy/menuactions/SearchResultMenu.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,45 +25,34 @@ import javax.swing.JMenu; import javax.swing.JMenuItem; import org.openide.awt.DynamicMenuContent; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; -import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; /** - * Menu item lists DataResult tabs. + * Class to provide menu access to the various result viewers. */ class SearchResultMenu extends JMenuItem implements DynamicMenuContent { - SearchResultMenu() { - - } + private static final long serialVersionUID = 1L; + @NbBundle.Messages({"SearchResultMenu.resultViewers.text=Result Viewers"}) @Override public JComponent[] getMenuPresenters() { + JMenu submenu = new JMenu(Bundle.SearchResultMenu_resultViewers_text()); List dataResultsIds = DataResultTopComponent.getActiveComponentIds(); - DirectoryTreeTopComponent directoryTree = DirectoryTreeTopComponent.findInstance(); - DataResultTopComponent directoryListing = directoryTree.getDirectoryListing(); - - List menuItems = new ArrayList(); - - // add the main "DirectoryListing" - JMenuItem dlItem = new JMenuItem(directoryListing.getName()); - dlItem.addActionListener(new OpenTopComponentAction(directoryListing)); - dlItem.setEnabled(directoryTree.isOpened()); - - menuItems.add(dlItem); - - // add search results if there are any - if (dataResultsIds.size() > 0) { - JMenu submenu = new JMenu(NbBundle.getMessage(this.getClass(), "SearchResultMenu.menu.dataRes.text")); - for (String resultTabId : dataResultsIds) { - JMenuItem item = new JMenuItem(resultTabId); - item.addActionListener(new OpenTopComponentAction(resultTabId)); - submenu.add(item); + if (Case.isCaseOpen()) { + // add search results if there are any + if (!dataResultsIds.isEmpty()) { + for (String resultTabId : dataResultsIds) { + JMenuItem item = new JMenuItem(resultTabId); + item.addActionListener(new OpenTopComponentAction(resultTabId)); + submenu.add(item); + } } - - menuItems.add(submenu); } - + submenu.setEnabled(!dataResultsIds.isEmpty()); + List menuItems = new ArrayList<>(); + menuItems.add(submenu); return menuItems.toArray(new JComponent[menuItems.size()]); } @@ -71,4 +60,10 @@ class SearchResultMenu extends JMenuItem implements DynamicMenuContent { public JComponent[] synchMenuPresenters(JComponent[] jcs) { return getMenuPresenters(); } + + @Override + public boolean isEnabled() { + return Case.isCaseOpen(); + } + } From cb0f0fd104e9798b8fe0a7d872597c5f3f23188b Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 28 Apr 2021 16:07:15 -0400 Subject: [PATCH 03/21] Fixed IG issue --- .../imagegallery/AddDrawableFilesTask.java | 78 ------- .../imagegallery/Bundle.properties-MERGED | 9 +- ...sTask.java => DrawableFileUpdateTask.java} | 196 ++++++++++++------ .../imagegallery/ImageGalleryController.java | 5 +- .../imagegallery/actions/OpenAction.java | 24 +-- .../autopsy/imagegallery/gui/Toolbar.java | 5 +- 6 files changed, 148 insertions(+), 169 deletions(-) delete mode 100755 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/AddDrawableFilesTask.java rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{BulkDrawableFilesTask.java => DrawableFileUpdateTask.java} (53%) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/AddDrawableFilesTask.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/AddDrawableFilesTask.java deleted file mode 100755 index 56b707ee49..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/AddDrawableFilesTask.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015-2019 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.imagegallery; - -import org.netbeans.api.progress.ProgressHandle; -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskData; - -/** - * A task that queries the case database for all files with supported - * image/video mime types or extensions and adds them to the drawables database. - */ -class AddDrawableFilesTask extends BulkDrawableFilesTask { - - private final ImageGalleryController controller; - private final DrawableDB taskDB; - - AddDrawableFilesTask(long dataSourceObjId, ImageGalleryController controller) { - super(dataSourceObjId, controller); - this.controller = controller; - this.taskDB = controller.getDrawablesDatabase(); - taskDB.buildFileMetaDataCache(); - } - - @Override - protected void cleanup() { - taskDB.freeFileMetaDataCache(); - // at the end of the task, set the stale status based on the - // cumulative status of all data sources - controller.setModelIsStale(controller.isDataSourcesTableStale()); - } - - @Override - void processFile(AbstractFile f, DrawableDB.DrawableTransaction tr, SleuthkitCase.CaseDbTransaction caseDbTransaction) throws TskCoreException { - final boolean known = f.getKnown() == TskData.FileKnown.KNOWN; - if (known) { - taskDB.removeFile(f.getId(), tr); //remove known files - } else { - // NOTE: Files are being processed because they have the right MIME type, - // so we do not need to worry about this calculating them - if (FileTypeUtils.hasDrawableMIMEType(f)) { - taskDB.updateFile(DrawableFile.create(f, true, false), tr, caseDbTransaction); - } //unsupported mimtype => analyzed but shouldn't include - else { - taskDB.removeFile(f.getId(), tr); - } - } - } - - @Override - @NbBundle.Messages({ - "AddDrawableFilesTask.populatingDb.status=populating analyzed image/video database" - }) - ProgressHandle getInitialProgressHandle() { - return ProgressHandle.createHandle(Bundle.AddDrawableFilesTask_populatingDb_status(), this); - } -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/Bundle.properties-MERGED b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/Bundle.properties-MERGED index 9b75078ae8..678dd85c44 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/Bundle.properties-MERGED +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/Bundle.properties-MERGED @@ -1,12 +1,11 @@ -AddDrawableFilesTask.populatingDb.status=populating analyzed image/video database -BulkDrawableFilesTask.committingDb.status=committing image/video database -BulkDrawableFilesTask.errPopulating.errMsg=There was an error populating Image Gallery database. -BulkDrawableFilesTask.populatingDb.status=populating analyzed image/video database -BulkDrawableFilesTask.stopCopy.status=Stopping copy to drawable db task. CTL_ImageGalleryAction=Image/Video Gallery CTL_ImageGalleryTopComponent=Image/Video Gallery DrawableDbTask.InnerTask.message.name=status DrawableDbTask.InnerTask.progress.name=progress +DrawableFileUpdateTask_committingDb.status=committing image/video database +DrawableFileUpdateTask_errPopulating_errMsg=There was an error populating Image Gallery database. +DrawableFileUpdateTask_populatingDb_status=populating analyzed image/video database +DrawableFileUpdateTask_stopCopy_status=Stopping copy to drawable db task. ImageGallery.dialogTitle=Image Gallery ImageGallery.showTooManyFiles.contentText=There are too many files in the selected datasource(s) to ensure reasonable performance. ImageGallery.showTooManyFiles.headerText= diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/BulkDrawableFilesTask.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableFileUpdateTask.java similarity index 53% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/BulkDrawableFilesTask.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableFileUpdateTask.java index 95ee3c9852..0e265b1fda 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/BulkDrawableFilesTask.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableFileUpdateTask.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015-2019 Basis Technology Corp. + * Copyright 2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,100 +22,163 @@ import java.sql.SQLException; import java.util.List; import java.util.logging.Level; import org.netbeans.api.progress.ProgressHandle; -import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; /** - * An abstract base class for tasks that add or modify the drawables database - * records for multiple drawable files. + * A bulk update task for adding images to the image gallery. */ -@NbBundle.Messages({ - "BulkDrawableFilesTask.committingDb.status=committing image/video database", - "BulkDrawableFilesTask.stopCopy.status=Stopping copy to drawable db task.", - "BulkDrawableFilesTask.errPopulating.errMsg=There was an error populating Image Gallery database." -}) -abstract class BulkDrawableFilesTask extends DrawableDbTask { +final class DrawableFileUpdateTask extends DrawableDbTask { + + private static final Logger logger = Logger.getLogger(DrawableFileUpdateTask.class.getName()); - private static final Logger logger = Logger.getLogger(BulkDrawableFilesTask.class.getName()); private static final String MIMETYPE_CLAUSE = "(mime_type LIKE '" //NON-NLS + String.join("' OR mime_type LIKE '", FileTypeUtils.getAllSupportedMimeTypes()) //NON-NLS + "') "; - private final String drawableQuery; - private final ImageGalleryController controller; - private final DrawableDB taskDB; - private final SleuthkitCase tskCase; - private final long dataSourceObjId; - //NON-NLS - BulkDrawableFilesTask(long dataSourceObjId, ImageGalleryController controller) { + private final ImageGalleryController controller; + + /** + * Construct a new task. + * + * @param controller A handle to the IG controller. + */ + DrawableFileUpdateTask(ImageGalleryController controller) { this.controller = controller; - this.taskDB = controller.getDrawablesDatabase(); - this.tskCase = controller.getCaseDatabase(); - this.dataSourceObjId = dataSourceObjId; - drawableQuery = " (data_source_obj_id = " + dataSourceObjId + ") " + } + + @Override + public void run() { + for (Long dataSourceObjId : controller.getStaleDataSourceIds()) { + updateFileForDataSource(dataSourceObjId); + } + } + + /** + * Gets the drawables database that is part of the model for the controller. + * + * @return The the drawable db object. + */ + private DrawableDB getDrawableDB() { + return controller.getDrawablesDatabase(); + } + + /** + * Return the sleuthkit case object for the open case. + * + * @return The case db object. + */ + private SleuthkitCase getCaseDB() { + return controller.getCaseDatabase(); + } + + /** + * Returns a list of files to be processed by the task for the given + * datasource. + * + * @param dataSourceObjId + * @return + * @throws TskCoreException + */ + private List getFilesForDataSource(long dataSourceObjId) throws TskCoreException { + List list = getCaseDB().findAllFilesWhere(getDrawableQuery(dataSourceObjId)); + return list; + + } + + /** + * Process a single file for the IG drawable db. + * + * @param file The file to process. + * @param tr A valid DrawableTransaction object. + * @param caseDbTransaction A valid caseDBTransaction object. + * + * @throws TskCoreException + */ + void processFile(AbstractFile file, DrawableDB.DrawableTransaction tr, SleuthkitCase.CaseDbTransaction caseDbTransaction) throws TskCoreException { + final boolean known = file.getKnown() == TskData.FileKnown.KNOWN; + if (known) { + getDrawableDB().removeFile(file.getId(), tr); //remove known files + } else { + // NOTE: Files are being processed because they have the right MIME type, + // so we do not need to worry about this calculating them + if (FileTypeUtils.hasDrawableMIMEType(file)) { + getDrawableDB().updateFile(DrawableFile.create(file, true, false), tr, caseDbTransaction); + } //unsupported mimtype => analyzed but shouldn't include + else { + getDrawableDB().removeFile(file.getId(), tr); + } + } + } + + /** + * Returns the image query for the given data source. + * + * @param dataSourceObjId + * + * @return SQL query for given data source. + */ + private String getDrawableQuery(long dataSourceObjId) { + return " (data_source_obj_id = " + dataSourceObjId + ") " + " AND ( meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue() + ")" + " AND ( " + MIMETYPE_CLAUSE //NON-NLS + " OR mime_type LIKE 'video/%' OR mime_type LIKE 'image/%' )" //NON-NLS + " ORDER BY parent_path "; } - /** - * Do any cleanup for this task. - */ - abstract void cleanup(); - - abstract void processFile(final AbstractFile f, DrawableDB.DrawableTransaction tr, SleuthkitCase.CaseDbTransaction caseDBTransaction) throws TskCoreException; - - /** - * Gets a list of files to process. - * - * @return list of files to process - * - * @throws TskCoreException - */ - List getFiles() throws TskCoreException { - return tskCase.findAllFilesWhere(drawableQuery); - } - - @Override - @NbBundle.Messages({ - "BulkDrawableFilesTask.populatingDb.status=populating analyzed image/video database" + @Messages({ + "DrawableFileUpdateTask_populatingDb_status=populating analyzed image/video database", + "DrawableFileUpdateTask_committingDb.status=committing image/video database", + "DrawableFileUpdateTask_stopCopy_status=Stopping copy to drawable db task.", + "DrawableFileUpdateTask_errPopulating_errMsg=There was an error populating Image Gallery database." }) - public void run() { + private void updateFileForDataSource(long dataSourceObjId) { ProgressHandle progressHandle = getInitialProgressHandle(); progressHandle.start(); - updateMessage(Bundle.BulkDrawableFilesTask_populatingDb_status() + " (Data Source " + dataSourceObjId + ")"); + updateMessage(Bundle.DrawableFileUpdateTask_populatingDb_status() + " (Data Source " + dataSourceObjId + ")"); + DrawableDB.DrawableTransaction drawableDbTransaction = null; SleuthkitCase.CaseDbTransaction caseDbTransaction = null; boolean hasFilesWithNoMime = true; boolean endedEarly = false; try { + + getDrawableDB().buildFileMetaDataCache(); // See if there are any files in the DS w/out a MIME TYPE hasFilesWithNoMime = controller.hasFilesWithNoMimeType(dataSourceObjId); + //grab all files with detected mime types - final List files = getFiles(); + final List files = getFilesForDataSource(dataSourceObjId); progressHandle.switchToDeterminate(files.size()); - taskDB.insertOrUpdateDataSource(dataSourceObjId, DrawableDB.DrawableDbBuildStatusEnum.IN_PROGRESS); + getDrawableDB().insertOrUpdateDataSource(dataSourceObjId, DrawableDB.DrawableDbBuildStatusEnum.IN_PROGRESS); updateProgress(0.0); int workDone = 0; // Cycle through all of the files returned and call processFile on each //do in transaction - drawableDbTransaction = taskDB.beginTransaction(); + /* * We are going to periodically commit the CaseDB transaction and * sleep so that the user can have Autopsy do other stuff while * these bulk tasks are ongoing. */ int caseDbCounter = 0; + for (final AbstractFile f : files) { + updateMessage(f.getName()); if (caseDbTransaction == null) { - caseDbTransaction = tskCase.beginTransaction(); + caseDbTransaction = getCaseDB().beginTransaction(); } + + if (drawableDbTransaction == null) { + drawableDbTransaction = getDrawableDB().beginTransaction(); + } + if (isCancelled() || Thread.interrupted()) { logger.log(Level.WARNING, "Task cancelled or interrupted: not all contents may be transfered to drawable database."); //NON-NLS endedEarly = true; @@ -132,20 +195,23 @@ abstract class BulkDrawableFilesTask extends DrawableDbTask { if ((++caseDbCounter % 200) == 0) { caseDbTransaction.commit(); caseDbTransaction = null; + + getDrawableDB().commitTransaction(drawableDbTransaction, true); + drawableDbTransaction = null; + Thread.sleep(500); // 1/2 second } } progressHandle.finish(); - progressHandle = ProgressHandle.createHandle(Bundle.BulkDrawableFilesTask_committingDb_status()); - updateMessage(Bundle.BulkDrawableFilesTask_committingDb_status() + " (Data Source " + dataSourceObjId + ")"); + progressHandle = ProgressHandle.createHandle(Bundle.DrawableFileUpdateTask_committingDb_status()); + updateMessage(Bundle.DrawableFileUpdateTask_committingDb_status() + " (Data Source " + dataSourceObjId + ")"); updateProgress(1.0); - progressHandle.start(); if (caseDbTransaction != null) { caseDbTransaction.commit(); caseDbTransaction = null; } // pass true so that groupmanager is notified of the changes - taskDB.commitTransaction(drawableDbTransaction, true); + getDrawableDB().commitTransaction(drawableDbTransaction, true); drawableDbTransaction = null; } catch (TskCoreException | SQLException | InterruptedException ex) { if (null != caseDbTransaction) { @@ -157,14 +223,14 @@ abstract class BulkDrawableFilesTask extends DrawableDbTask { } if (null != drawableDbTransaction) { try { - taskDB.rollbackTransaction(drawableDbTransaction); + getDrawableDB().rollbackTransaction(drawableDbTransaction); } catch (SQLException ex2) { logger.log(Level.SEVERE, String.format("Failed to roll back drawables db transaction after error: %s", ex.getMessage()), ex2); //NON-NLS } } - progressHandle.progress(Bundle.BulkDrawableFilesTask_stopCopy_status()); + progressHandle.progress(Bundle.DrawableFileUpdateTask_stopCopy_status()); logger.log(Level.WARNING, "Stopping copy to drawable db task. Failed to transfer all database contents", ex); //NON-NLS - MessageNotifyUtil.Notify.warn(Bundle.BulkDrawableFilesTask_errPopulating_errMsg(), ex.getMessage()); + MessageNotifyUtil.Notify.warn(Bundle.DrawableFileUpdateTask_errPopulating_errMsg(), ex.getMessage()); endedEarly = true; } finally { progressHandle.finish(); @@ -172,15 +238,27 @@ abstract class BulkDrawableFilesTask extends DrawableDbTask { // if there was cancellation or errors DrawableDB.DrawableDbBuildStatusEnum datasourceDrawableDBStatus = ((hasFilesWithNoMime == true) || (endedEarly == true)) ? DrawableDB.DrawableDbBuildStatusEnum.REBUILT_STALE : DrawableDB.DrawableDbBuildStatusEnum.COMPLETE; try { - taskDB.insertOrUpdateDataSource(dataSourceObjId, datasourceDrawableDBStatus); + getDrawableDB().insertOrUpdateDataSource(dataSourceObjId, datasourceDrawableDBStatus); } catch (SQLException ex) { logger.log(Level.SEVERE, String.format("Error updating datasources table (data source object ID = %d, status = %s)", dataSourceObjId, datasourceDrawableDBStatus.toString(), ex)); //NON-NLS } updateMessage(""); updateProgress(-1.0); + + getDrawableDB().freeFileMetaDataCache(); + // at the end of the task, set the stale status based on the + // cumulative status of all data sources + controller.setModelIsStale(controller.isDataSourcesTableStale()); } - cleanup(); + } - abstract ProgressHandle getInitialProgressHandle(); + /** + * Returns a ProgressHandle. + * + * @return A new ProgressHandle. + */ + private ProgressHandle getInitialProgressHandle() { + return ProgressHandle.createHandle(Bundle.DrawableFileUpdateTask_populatingDb_status(), this); + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 4ecb35a455..c61f24fcd0 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -486,8 +486,7 @@ public final class ImageGalleryController { * */ public void rebuildDrawablesDb() { - // queue a rebuild task for each stale data source - getStaleDataSourceIds().forEach(dataSourceObjId -> queueDBTask(new AddDrawableFilesTask(dataSourceObjId, this))); + queueDBTask(new DrawableFileUpdateTask(this)); } /** @@ -670,7 +669,7 @@ public final class ImageGalleryController { * * @param bgTask */ - public synchronized void queueDBTask(DrawableDbTask bgTask) { + public synchronized void queueDBTask(Runnable bgTask) { if (!dbExecutor.isShutdown()) { incrementQueueSize(); dbExecutor.submit(bgTask).addListener(this::decrementQueueSize, MoreExecutors.directExecutor()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java index 4c286c5345..5723e8e63e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java @@ -40,6 +40,7 @@ import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; import org.openide.awt.ActionRegistration; +import org.openide.util.Exceptions; import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; @@ -255,28 +256,7 @@ public final class OpenAction extends CallableSystemAction { // They don't want to rebuild. Just open the UI as is. // NOTE: There could be no data.... } else if (answer == ButtonType.YES) { - if (controller.getCase().getCaseType() == Case.CaseType.SINGLE_USER_CASE) { - /* - * For a single-user case, we favor user - * experience, and rebuild the database as soon - * as Image Gallery is enabled for the case. - * - * Turning listening off is necessary in order - * to invoke the listener that will call - * controller.rebuildDB(); - */ - controller.setListeningEnabled(false); - controller.setListeningEnabled(true); - } else { - /* - * For a multi-user case, we favor overall - * performance and user experience, not every - * user may want to review images, so we rebuild - * the database only when a user launches Image - * Gallery. - */ - controller.rebuildDrawablesDb(); - } + controller.rebuildDrawablesDb(); } openTopComponent(); return; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java index f492b5f325..1d7e7bc716 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java @@ -66,6 +66,7 @@ import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeGroupAction; import org.sleuthkit.autopsy.imagegallery.actions.TagGroupAction; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; @@ -236,8 +237,8 @@ public class Toolbar extends ToolBar { } private void initDataSourceComboBox() { - dataSourceComboBox.setCellFactory(param -> new DataSourceCell(dataSourcesViewable, controller.getAllDataSourcesDrawableDBStatus())); - dataSourceComboBox.setButtonCell(new DataSourceCell(dataSourcesViewable, controller.getAllDataSourcesDrawableDBStatus())); + dataSourceComboBox.setCellFactory(param -> new DataSourceCell(dataSourcesViewable, new HashMap<>())); + dataSourceComboBox.setButtonCell(new DataSourceCell(dataSourcesViewable, new HashMap<>())); dataSourceComboBox.setConverter(new StringConverter>() { @Override public String toString(Optional object) { From 949c43d56d481ef49c88176052625503fd0d34f2 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 28 Apr 2021 16:11:04 -0400 Subject: [PATCH 04/21] start on hierarchy --- .../autopsy/datamodel/AnalysisResults.java | 59 ++++++ .../autopsy/datamodel/AutopsyItemVisitor.java | 15 ++ .../datamodel/AutopsyTreeChildFactory.java | 1 + .../autopsy/datamodel/Bundle.properties | 2 +- .../datamodel/Bundle.properties-MERGED | 2 +- .../autopsy/datamodel/DataArtifacts.java | 59 ++++++ .../datamodel/DataSourceGroupingNode.java | 29 +-- .../autopsy/datamodel/ExtractedContent.java | 176 ++++++++++++------ .../datamodel/RootContentChildren.java | 10 + 9 files changed, 275 insertions(+), 78 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java new file mode 100644 index 0000000000..2a55ce2e4b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java @@ -0,0 +1,59 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.datamodel; + +/** + * Analysis Results node support + */ +public class AnalysisResults implements AutopsyVisitableItem { + + private final long datasourceObjId; + + /** + * Main constructor. + */ + public AnalysisResults() { + this(null); + } + + /** + * Main constructor. + * + * @param dsObjId The data source object id. + */ + public AnalysisResults(Long dsObjId) { + this.datasourceObjId = dsObjId; + } + + @Override + public T accept(AutopsyItemVisitor visitor) { + return visitor.visit(this); + } + + /** + * Returns whether or not there is a data source object for which results + * should be filtered. + * + * @return Whether or not there is a data source object for which results + * should be filtered. + */ + Long filteringDataSourceObjId() { + return datasourceObjId; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java index aabb21bbec..ed719a341e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java @@ -85,6 +85,11 @@ public interface AutopsyItemVisitor { T visit(DataSourcesByType aThis); + T visit(AnalysisResults aThis); + + T visit(DataArtifacts aThis); + + static abstract public class Default implements AutopsyItemVisitor { protected abstract T defaultVisit(AutopsyVisitableItem ec); @@ -233,5 +238,15 @@ public interface AutopsyItemVisitor { public T visit(DataSourcesByType dataSourceHosts) { return defaultVisit(dataSourceHosts); } + + @Override + public T visit(DataArtifacts aThis) { + return defaultVisit(aThis); + } + + @Override + public T visit(AnalysisResults aThis) { + return defaultVisit(aThis); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java index 22b340d5f1..c037a72251 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java @@ -127,6 +127,7 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.datamodel; + +/** + * Analysis Results node support + */ +public class DataArtifacts implements AutopsyVisitableItem { + + private final long datasourceObjId; + + /** + * Main constructor. + */ + public DataArtifacts() { + this(null); + } + + /** + * Main constructor. + * + * @param dsObjId The data source object id. + */ + public DataArtifacts(Long dsObjId) { + this.datasourceObjId = dsObjId; + } + + @Override + public T accept(AutopsyItemVisitor visitor) { + return visitor.visit(this); + } + + /** + * Returns whether or not there is a data source object for which results + * should be filtered. + * + * @return Whether or not there is a data source object for which results + * should be filtered. + */ + Long filteringDataSourceObjId() { + return datasourceObjId; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java index 214ab3ead9..9dc7529729 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java @@ -30,24 +30,23 @@ import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.LocalFilesDataSource; - /** - * Data source grouping node - an optional grouping node in the data tree view - * + * Data source grouping node - an optional grouping node in the data tree view + * */ class DataSourceGroupingNode extends DisplayableItemNode { private static final Logger logger = Logger.getLogger(DataSourceGroupingNode.class.getName()); /** - * Creates a data source grouping node for the given data source. - * - * @param dataSource specifies the data source + * Creates a data source grouping node for the given data source. + * + * @param dataSource specifies the data source */ DataSourceGroupingNode(DataSource dataSource) { - super (Optional.ofNullable(createDSGroupingNodeChildren(dataSource)) - .orElse(new RootContentChildren(Arrays.asList(Collections.EMPTY_LIST))), + super(Optional.ofNullable(createDSGroupingNodeChildren(dataSource)) + .orElse(new RootContentChildren(Arrays.asList(Collections.EMPTY_LIST))), Lookups.singleton(dataSource)); if (dataSource instanceof Image) { @@ -70,7 +69,7 @@ class DataSourceGroupingNode extends DisplayableItemNode { public boolean isLeafTypeNode() { return false; } - + private static RootContentChildren createDSGroupingNodeChildren(DataSource dataSource) { long dsObjId = dataSource.getId(); @@ -78,11 +77,13 @@ class DataSourceGroupingNode extends DisplayableItemNode { return new RootContentChildren(Arrays.asList( new DataSources(dsObjId), new Views(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId), - new Results(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId), - new Tags(dsObjId) ) - - ); - + new DataArtifacts(dsObjId), + new AnalysisResults(dsObjId), + new OsAccounts(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId), + new Tags(dsObjId), + new Reports(dsObjId) + )); + } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Error getting open case.", ex); //NON-NLS return null; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 8408c0c74a..af132a3f56 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -37,6 +37,7 @@ import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.RootContentChildren.CreateAutopsyNodeVisitor; import org.sleuthkit.autopsy.datamodel.utils.IconsUtil; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -99,7 +100,7 @@ public class ExtractedContent implements AutopsyVisitableItem { return skCase; } - public class RootNode extends DisplayableItemNode { + public static class RootNode extends DisplayableItemNode { public RootNode(SleuthkitCase skCase) { super(Children.create(new TypeFactory(), true), Lookups.singleton(NAME)); @@ -139,17 +140,51 @@ public class ExtractedContent implements AutopsyVisitableItem { return getClass().getName(); } } + + static class DataArtifactTypeFactory extends TypeFactory { + + } + + static class ArtifactKey { + private static final CreateAutopsyNodeVisitor visitor new CreateAutopsyNodeVisitor(); + private final AutopsyVisitableItem visitable; + private final BlackboardArtifact.Type type; + private final Long dsFilteringObjId; + + ArtifactKey(AutopsyVisitableItem visitable, BlackboardArtifact.Type type, long dsFilteringObjId) { + this.visitable = visitable; + this.type = type; + this.dsFilteringObjId = dsFilteringObjId; + } + + Node getNode() { + if (visitable!= null) { + return visitable.accept(visitor); + } else { + TypeNode node = new TypeNode(type, dsFilteringObjId); + node.updateDisplayName(); + return node; + } + } + + String getName() { + + } + } /** * Creates the children for the ExtractedContent area of the results tree. * This area has all of the blackboard artifacts that are not displayed in a * more specific form elsewhere in the tree. */ - private class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { + abstract static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { + + private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); private final ArrayList doNotShow = new ArrayList<>(); // maps the artifact type to its child node private final HashMap typeNodeList = new HashMap<>(); + private final Long filteringDSObjId; /** * RefreshThrottler is used to limit the number of refreshes performed @@ -159,8 +194,9 @@ public class ExtractedContent implements AutopsyVisitableItem { private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); @SuppressWarnings("deprecation") - TypeFactory() { + TypeFactory(Long filteringDSObjId) { super(); + this.filteringDSObjId = filteringDSObjId; // these are shown in other parts of the UI doNotShow.add(new BlackboardArtifact.Type(TSK_GEN_INFO)); @@ -184,7 +220,6 @@ public class ExtractedContent implements AutopsyVisitableItem { // case was closed. Remove listeners so that we don't get called with a stale case handle if (evt.getNewValue() == null) { removeNotify(); - skCase = null; } } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { @@ -219,42 +254,59 @@ public class ExtractedContent implements AutopsyVisitableItem { typeNodeList.clear(); } + /** + * Retrieves all the artifact types that should be displayed for this + * factory. + * + * @param filteringDSObjId The data source object id to filter on or + * null if no filtering on data source should + * occur. + * + * @return The list of artifact types to be displayed. + * + * @throws NoCurrentCaseException + * @throws TskCoreException + */ + protected abstract List getTypes(Long filteringDSObjId) throws NoCurrentCaseException, TskCoreException; + + // Potentially can reuse +// (filteringDSObjId > 0) +// ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactTypesInUse(filteringDSObjId) +// : Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse(); + // types.removeAll(doNotShow); @Override - protected boolean createKeys(List list) { - if (skCase != null) { - try { - List types = (filteringDSObjId > 0) - ? blackboard.getArtifactTypesInUse(filteringDSObjId) - : skCase.getArtifactTypesInUse(); + protected boolean createKeys(List list) { - types.removeAll(doNotShow); - Collections.sort(types, - new Comparator() { - @Override - public int compare(BlackboardArtifact.Type a, BlackboardArtifact.Type b) { - return a.getDisplayName().compareTo(b.getDisplayName()); - } - }); - list.addAll(types); - - // the create node method will get called only for new types - // refresh the counts if we already created them from a previous update - for (BlackboardArtifact.Type art : types) { - TypeNode node = typeNodeList.get(art); - if (node != null) { - node.updateDisplayName(); - } + try { + List types = getTypes(this.filteringDSObjId); + Collections.sort(types, + new Comparator() { + @Override + public int compare(BlackboardArtifact.Type a, BlackboardArtifact.Type b) { + return a.getDisplayName().compareTo(b.getDisplayName()); + } + }); + list.addAll(types); + + // the create node method will get called only for new types + // refresh the counts if we already created them from a previous update + for (BlackboardArtifact.Type art : types) { + TypeNode node = typeNodeList.get(art); + if (node != null) { + node.updateDisplayName(); } - } catch (TskCoreException ex) { - Logger.getLogger(TypeFactory.class.getName()).log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage()); //NON-NLS } + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Trying to access case when no case is open.", ex); //NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage()); //NON-NLS } return true; } @Override protected Node createNodeForKey(BlackboardArtifact.Type key) { - TypeNode node = new TypeNode(key); + TypeNode node = new TypeNode(key, filteringDSObjId); typeNodeList.put(key, node); return node; } @@ -300,35 +352,33 @@ public class ExtractedContent implements AutopsyVisitableItem { * the artifacts of a given type. Its children will be * BlackboardArtifactNode objects. */ - public class TypeNode extends DisplayableItemNode { + public static class TypeNode extends DisplayableItemNode { + + private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); private final BlackboardArtifact.Type type; private long childCount = 0; + private final Long filteringDSObjId; - TypeNode(BlackboardArtifact.Type type) { - super(Children.create(new ArtifactFactory(type), true), Lookups.singleton(type.getDisplayName())); + TypeNode(BlackboardArtifact.Type type, Long filteringDSObjId) { + super(Children.create(new ArtifactFactory(type, filteringDSObjId), true), Lookups.singleton(type.getDisplayName())); super.setName(type.getTypeName()); this.type = type; + this.filteringDSObjId = filteringDSObjId; String iconPath = IconsUtil.getIconFilePath(type.getTypeID()); setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath); updateDisplayName(); } final void updateDisplayName() { - if (skCase == null) { - return; - } - - // NOTE: This completely destroys our lazy-loading ideal - // a performance increase might be had by adding a - // "getBlackboardArtifactCount()" method to skCase try { this.childCount = (filteringDSObjId > 0) - ? blackboard.getArtifactsCount(type.getTypeID(), filteringDSObjId) - : skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); + ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactsCount(type.getTypeID(), filteringDSObjId) + : Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifactsTypeCount(type.getTypeID()); + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Error fetching data when case closed.", ex); } catch (TskCoreException ex) { - Logger.getLogger(TypeNode.class.getName()) - .log(Level.WARNING, "Error getting child count", ex); //NON-NLS + logger.log(Level.WARNING, "Error getting child count", ex); //NON-NLS } super.setDisplayName(type.getDisplayName() + " \u200E(\u200E" + childCount + ")\u200E"); } @@ -374,8 +424,9 @@ public class ExtractedContent implements AutopsyVisitableItem { /** * Creates children for a given artifact type */ - private class ArtifactFactory extends BaseChildFactory implements RefreshThrottler.Refresher { + private static class ArtifactFactory extends BaseChildFactory implements RefreshThrottler.Refresher { + private static final Logger logger = Logger.getLogger(ArtifactFactory.class.getName()); private final BlackboardArtifact.Type type; /** @@ -384,10 +435,12 @@ public class ExtractedContent implements AutopsyVisitableItem { * received. */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); + private final Long filteringDSObjId; - ArtifactFactory(BlackboardArtifact.Type type) { + ArtifactFactory(BlackboardArtifact.Type type, Long filteringDSObjId) { super(type.getTypeName()); this.type = type; + this.filteringDSObjId = filteringDSObjId; } private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { @@ -430,23 +483,22 @@ public class ExtractedContent implements AutopsyVisitableItem { @Override protected List makeKeys() { - if (skCase != null) { - try { - List arts; - if (filteringDSObjId > 0) { - arts = blackboard.getArtifacts(type.getTypeID(), filteringDSObjId); - } else { - arts = skCase.getBlackboardArtifacts(type.getTypeID()); - } - for (BlackboardArtifact art : arts) { - //Cache attributes while we are off the EDT. - //See JIRA-5969 - art.getAttributes(); - } - return arts; - } catch (TskCoreException ex) { - Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS + try { + List arts; + arts = (filteringDSObjId != null) + ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(type.getTypeID(), filteringDSObjId) + : Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifacts(type.getTypeID()); + + for (BlackboardArtifact art : arts) { + //Cache attributes while we are off the EDT. + //See JIRA-5969 + art.getAttributes(); } + return arts; + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Trying to access case when no case is open.", ex); //NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS } return Collections.emptyList(); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index 07ea924d82..355790976e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -204,5 +204,15 @@ public class RootContentChildren extends Children.Keys { public AbstractNode visit(DataSourcesByType dataSourceHosts) { return new DataSourcesByTypeNode(); } + + @Override + public AbstractNode visit(AnalysisResults analysisResults) { + return new AnalysisResultsNode(analysisResults); + } + + @Override + public AbstractNode visit(DataArtifacts dataArtifacts) { + return new DataArtifactsNode(dataArtifacts); + } } } From bfd41bd6831000bc853f0f97dce03a3cd9e14dde Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 28 Apr 2021 20:46:21 -0400 Subject: [PATCH 05/21] work on type factory --- .../autopsy/datamodel/ExtractedContent.java | 298 +++++++++++++----- 1 file changed, 219 insertions(+), 79 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index af132a3f56..a65bd7dc3e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.datamodel; +import com.google.common.collect.ImmutableSet; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; @@ -26,8 +27,13 @@ import java.util.Comparator; import java.util.EnumSet; import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; @@ -38,6 +44,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.RootContentChildren.CreateAutopsyNodeVisitor; +import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.autopsy.datamodel.utils.IconsUtil; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -57,6 +64,7 @@ import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNL import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.guiutils.RefreshThrottler; +import org.sleuthkit.datamodel.BlackboardArtifact.Category; /** * Parent of the "extracted content" artifacts to be displayed in the tree. @@ -140,36 +148,184 @@ public class ExtractedContent implements AutopsyVisitableItem { return getClass().getName(); } } + - static class DataArtifactTypeFactory extends TypeFactory { + // The “Email Messages” and “Accounts” nodes should become children of the “Data Artifacts” node, but should retain their current structure. + + // The “Keyword Hits,” “Hashset Hits,” and “Interesting Items” nodes should become children of the “Analysis Results” node, but should retain their current structure. + +// new KeywordHits(sleuthkitCase, dsObjId), +// new HashsetHits(sleuthkitCase, dsObjId), +// new EmailExtracted(sleuthkitCase, dsObjId), +// new InterestingHits(sleuthkitCase, dsObjId ), +// new Accounts(sleuthkitCase, dsObjId), +// new OsAccounts(sleuthkitCase, dsObjId)) + + + static class AnalysisResultsTypeFactory extends TypeFactory { + private static Map getVisitableItems(Long filteringDSObjId) throws NoCurrentCaseException { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return new HashMap<>() {{ + put(filteringDSObjId == null ? new KeywordHits(skCase) : new KeywordHits(skCase, filteringDSObjId), TODO); //BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getDisplayName()); + put(filteringDSObjId == null ? new HashsetHits(skCase) : new HashsetHits(skCase, filteringDSObjId), TODO); // Bundle.Accounts_RootNode_displayName()); + put(filteringDSObjId == null ? new InterestingHits(skCase) : new InterestingHits(skCase, filteringDSObjId), TODO); // Bundle.Accounts_RootNode_displayName()); + }}; + } + + public AnalysisResultsTypeFactory(Long filteringDSObjId) throws NoCurrentCaseException { + super(getVisitableItems(filteringDSObjId), Category.DATA_ARTIFACT, filteringDSObjId); + } } - static class ArtifactKey { - private static final CreateAutopsyNodeVisitor visitor new CreateAutopsyNodeVisitor(); + + static class DataArtifactsTypeFactory extends TypeFactory { + + private static Map getVisitableItems(Long filteringDSObjId) throws NoCurrentCaseException { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return new HashMap<>() {{ + put(filteringDSObjId == null ? new EmailExtracted(skCase) : new EmailExtracted(skCase, filteringDSObjId), TODO); //BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getDisplayName()); + put(filteringDSObjId == null ? new Accounts(skCase) : new Accounts(skCase, filteringDSObjId), TODO); // Bundle.Accounts_RootNode_displayName()); + }}; + } + + public DataArtifactsTypeFactory(Long filteringDSObjId) throws NoCurrentCaseException { + super(getVisitableItems(filteringDSObjId), Category.DATA_ARTIFACT, filteringDSObjId); + } + } + + interface ArtifactKey { + + Node getNode(); + + String getName(); + + void update(); + } + + static class VisitableArtifactKey implements ArtifactKey { + + private static final CreateAutopsyNodeVisitor visitor = new CreateAutopsyNodeVisitor(); private final AutopsyVisitableItem visitable; - private final BlackboardArtifact.Type type; + private final String name; private final Long dsFilteringObjId; - ArtifactKey(AutopsyVisitableItem visitable, BlackboardArtifact.Type type, long dsFilteringObjId) { + VisitableArtifactKey(AutopsyVisitableItem visitable, String name, Long dsFilteringObjId) { this.visitable = visitable; - this.type = type; + this.name = name; this.dsFilteringObjId = dsFilteringObjId; } - Node getNode() { - if (visitable!= null) { - return visitable.accept(visitor); - } else { - TypeNode node = new TypeNode(type, dsFilteringObjId); - node.updateDisplayName(); - return node; - } + @Override + public Node getNode() { + return visitable.accept(visitor); } - - String getName() { + @Override + public String getName() { + return this.name; } + + @Override + public void update() { + // no need to handle updates for a visitable item + } + + @Override + public int hashCode() { + int hash = 5; + hash = 37 * hash + Objects.hashCode(this.visitable); + hash = 37 * hash + Objects.hashCode(this.name); + hash = 37 * hash + Objects.hashCode(this.dsFilteringObjId); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final VisitableArtifactKey other = (VisitableArtifactKey) obj; + if (!Objects.equals(this.name, other.name)) { + return false; + } + if (!Objects.equals(this.visitable, other.visitable)) { + return false; + } + if (!Objects.equals(this.dsFilteringObjId, other.dsFilteringObjId)) { + return false; + } + return true; + } + + } + + static class TypeArtifactKey implements ArtifactKey { + + private final BlackboardArtifact.Type type; + private final Map typeMapping; + private final Long dsFilteringObjId; + + TypeArtifactKey(BlackboardArtifact.Type type, Map typeMapping, Long dsFilteringObjId) { + this.type = type; + this.typeMapping = typeMapping; + this.dsFilteringObjId = dsFilteringObjId; + } + + @Override + public TypeNode getNode() { + return typeMapping.computeIfAbsent(type, (tp) -> new TypeNode(type, dsFilteringObjId)); + } + + @Override + public String getName() { + return this.type.getDisplayName(); + } + + @Override + public void update() { + getNode().updateDisplayName(); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 83 * hash + Objects.hashCode(this.type); + hash = 83 * hash + Objects.hashCode(this.typeMapping); + hash = 83 * hash + Objects.hashCode(this.dsFilteringObjId); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final TypeArtifactKey other = (TypeArtifactKey) obj; + if (!Objects.equals(this.type, other.type)) { + return false; + } + if (!Objects.equals(this.typeMapping, other.typeMapping)) { + return false; + } + if (!Objects.equals(this.dsFilteringObjId, other.dsFilteringObjId)) { + return false; + } + return true; + } + } /** @@ -177,13 +333,29 @@ public class ExtractedContent implements AutopsyVisitableItem { * This area has all of the blackboard artifacts that are not displayed in a * more specific form elsewhere in the tree. */ - abstract static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { + static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { + + @SuppressWarnings("deprecation") + private static final Set DO_NOT_SHOW = Stream.of( + // these are shown in other parts of the UI (and different node types) + new BlackboardArtifact.Type(TSK_GEN_INFO), + new BlackboardArtifact.Type(TSK_EMAIL_MSG), + new BlackboardArtifact.Type(TSK_HASHSET_HIT), + new BlackboardArtifact.Type(TSK_KEYWORD_HIT), + new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT), + new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), + new BlackboardArtifact.Type(TSK_ACCOUNT), + new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE), + new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE), + new BlackboardArtifact.Type(TSK_TL_EVENT), + //This is not meant to be shown in the UI at all. It is more of a meta artifact. + new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) + ).collect(Collectors.toSet()); private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); - private final ArrayList doNotShow = new ArrayList<>(); // maps the artifact type to its child node - private final HashMap typeNodeList = new HashMap<>(); + private final HashMap typeNodeMap = new HashMap<>(); private final Long filteringDSObjId; /** @@ -192,26 +364,15 @@ public class ExtractedContent implements AutopsyVisitableItem { * received. */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); + private final Map visitableItems; + private final Category category; @SuppressWarnings("deprecation") - TypeFactory(Long filteringDSObjId) { + TypeFactory(Map visitableItems, Category category, Long filteringDSObjId) { super(); this.filteringDSObjId = filteringDSObjId; - - // these are shown in other parts of the UI - doNotShow.add(new BlackboardArtifact.Type(TSK_GEN_INFO)); - doNotShow.add(new BlackboardArtifact.Type(TSK_EMAIL_MSG)); - doNotShow.add(new BlackboardArtifact.Type(TSK_HASHSET_HIT)); - doNotShow.add(new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); - doNotShow.add(new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT)); - doNotShow.add(new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT)); - doNotShow.add(new BlackboardArtifact.Type(TSK_ACCOUNT)); - doNotShow.add(new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE)); - doNotShow.add(new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE)); - doNotShow.add(new BlackboardArtifact.Type(TSK_TL_EVENT)); - - //This is not meant to be shown in the UI at all. It is more of a meta artifact. - doNotShow.add(new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT)); + this.visitableItems = visitableItems; + this.category = category; } private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { @@ -251,51 +412,32 @@ public class ExtractedContent implements AutopsyVisitableItem { refreshThrottler.unregisterEventListener(); IngestManager.getInstance().removeIngestJobEventListener(pcl); Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl); - typeNodeList.clear(); + typeNodeMap.clear(); } - /** - * Retrieves all the artifact types that should be displayed for this - * factory. - * - * @param filteringDSObjId The data source object id to filter on or - * null if no filtering on data source should - * occur. - * - * @return The list of artifact types to be displayed. - * - * @throws NoCurrentCaseException - * @throws TskCoreException - */ - protected abstract List getTypes(Long filteringDSObjId) throws NoCurrentCaseException, TskCoreException; - - // Potentially can reuse -// (filteringDSObjId > 0) -// ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactTypesInUse(filteringDSObjId) -// : Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse(); - // types.removeAll(doNotShow); @Override protected boolean createKeys(List list) { - try { - List types = getTypes(this.filteringDSObjId); - Collections.sort(types, - new Comparator() { - @Override - public int compare(BlackboardArtifact.Type a, BlackboardArtifact.Type b) { - return a.getDisplayName().compareTo(b.getDisplayName()); - } - }); - list.addAll(types); + // Potentially can reuse + List types = (this.filteringDSObjId != null) + ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactTypesInUse(this.filteringDSObjId) + : Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse(); + + Stream typeArtifactKeys = types.stream() + .filter(tp -> category.equals(tp.getCategory())) + .filter(tp -> !DO_NOT_SHOW.contains(tp)) + .map(tp -> new TypeArtifactKey(tp, this.typeNodeMap, this.filteringDSObjId)); + + Stream visitableKeys = visitableItems.entrySet().stream() + .map(entry -> new VisitableArtifactKey(entry.getKey(), entry.getValue(), filteringDSObjId)); + + Stream.concat(typeArtifactKeys, visitableKeys) + .sorted((a, b) -> StringUtils.compareIgnoreCase(a.getName(), b.getName())) + .forEach((artifactTypeKey -> { + artifactTypeKey.update(); + list.add(artifactTypeKey); + })); - // the create node method will get called only for new types - // refresh the counts if we already created them from a previous update - for (BlackboardArtifact.Type art : types) { - TypeNode node = typeNodeList.get(art); - if (node != null) { - node.updateDisplayName(); - } - } } catch (NoCurrentCaseException ex) { logger.log(Level.WARNING, "Trying to access case when no case is open.", ex); //NON-NLS } catch (TskCoreException ex) { @@ -305,10 +447,8 @@ public class ExtractedContent implements AutopsyVisitableItem { } @Override - protected Node createNodeForKey(BlackboardArtifact.Type key) { - TypeNode node = new TypeNode(key, filteringDSObjId); - typeNodeList.put(key, node); - return node; + protected Node createNodeForKey(ArtifactKey key) { + return key.getNode(); } @Override @@ -333,7 +473,7 @@ public class ExtractedContent implements AutopsyVisitableItem { * the event is a remote event. */ final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); - if (null != event && !(this.doNotShow.contains(event.getBlackboardArtifactType()))) { + if (null != event && !(DO_NOT_SHOW.contains(event.getBlackboardArtifactType()))) { return true; } } catch (NoCurrentCaseException notUsed) { From 58993d7e6224531d1b66c510e080b0ee1c2f54af Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 29 Apr 2021 09:00:21 -0400 Subject: [PATCH 06/21] beginning debug --- .../autopsy/datamodel/AnalysisResults.java | 6 +- .../datamodel/AutopsyTreeChildFactory.java | 11 +- .../autopsy/datamodel/DataArtifacts.java | 6 +- .../datamodel/DataSourceGroupingNode.java | 2 +- .../autopsy/datamodel/EmailExtracted.java | 8 + .../autopsy/datamodel/ExtractedContent.java | 188 +++++++++++------- .../autopsy/datamodel/HashsetHits.java | 8 + .../autopsy/datamodel/InterestingHits.java | 8 + .../autopsy/datamodel/KeywordHits.java | 9 + .../datamodel/RootContentChildren.java | 12 +- .../autopsy/datamodel/accounts/Accounts.java | 12 +- 11 files changed, 179 insertions(+), 91 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java index 2a55ce2e4b..ed6bd37319 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java @@ -29,7 +29,7 @@ public class AnalysisResults implements AutopsyVisitableItem { * Main constructor. */ public AnalysisResults() { - this(null); + this(0); } /** @@ -37,7 +37,7 @@ public class AnalysisResults implements AutopsyVisitableItem { * * @param dsObjId The data source object id. */ - public AnalysisResults(Long dsObjId) { + public AnalysisResults(long dsObjId) { this.datasourceObjId = dsObjId; } @@ -53,7 +53,7 @@ public class AnalysisResults implements AutopsyVisitableItem { * @return Whether or not there is a data source object for which results * should be filtered. */ - Long filteringDataSourceObjId() { + Long getFilteringDataSourceObjId() { return datasourceObjId; } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java index c037a72251..9ebb44cb40 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java @@ -92,6 +92,7 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable keys = new ArrayList<>(Arrays.asList( new DataSourcesByType(), - new Views(tskCase), - new Results(tskCase), - new OsAccounts(tskCase), + new Views(Case.getCurrentCaseThrows().getSleuthkitCase()), + new DataArtifacts(), + new AnalysisResults(), + new OsAccounts(Case.getCurrentCaseThrows().getSleuthkitCase()), new Tags(), - new Reports())); + new Reports() + )); list.addAll(keys); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java index d327da0f4a..e273d8cf12 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java @@ -29,7 +29,7 @@ public class DataArtifacts implements AutopsyVisitableItem { * Main constructor. */ public DataArtifacts() { - this(null); + this(0); } /** @@ -37,7 +37,7 @@ public class DataArtifacts implements AutopsyVisitableItem { * * @param dsObjId The data source object id. */ - public DataArtifacts(Long dsObjId) { + public DataArtifacts(long dsObjId) { this.datasourceObjId = dsObjId; } @@ -53,7 +53,7 @@ public class DataArtifacts implements AutopsyVisitableItem { * @return Whether or not there is a data source object for which results * should be filtered. */ - Long filteringDataSourceObjId() { + Long getFilteringDataSourceObjId() { return datasourceObjId; } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java index 9dc7529729..28ad25fe59 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourceGroupingNode.java @@ -81,7 +81,7 @@ class DataSourceGroupingNode extends DisplayableItemNode { new AnalysisResults(dsObjId), new OsAccounts(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId), new Tags(dsObjId), - new Reports(dsObjId) + new Reports() )); } catch (NoCurrentCaseException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 58becb183c..6495e9d7fe 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -92,6 +92,14 @@ public class EmailExtracted implements AutopsyVisitableItem { private final EmailResults emailResults; private final long filteringDSObjId; // 0 if not filtering/grouping by data source + /** + * Returns the display name for this module. + * @return The display name for this module. + */ + static String getDisplayName() { + return DISPLAY_NAME; + } + /** * Constructor * diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index a65bd7dc3e..8f3f737e41 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -38,6 +38,7 @@ import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; @@ -74,9 +75,11 @@ public class ExtractedContent implements AutopsyVisitableItem { private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text"); + private static final Category DEFAULT_CATEGORY = Category.DATA_ARTIFACT; + private final long filteringDSObjId; // 0 if not filtering/grouping by data source private SleuthkitCase skCase; // set to null after case has been closed - private Blackboard blackboard; + private final Category category; /** * Constructs extracted content object @@ -84,7 +87,11 @@ public class ExtractedContent implements AutopsyVisitableItem { * @param skCase Case DB */ public ExtractedContent(SleuthkitCase skCase) { - this(skCase, 0); + this(skCase, 0, DEFAULT_CATEGORY); + } + + public ExtractedContent(SleuthkitCase skCase, Category category) { + this(skCase, 0, DEFAULT_CATEGORY); } /** @@ -94,9 +101,13 @@ public class ExtractedContent implements AutopsyVisitableItem { * @param objId Object id of the parent datasource */ public ExtractedContent(SleuthkitCase skCase, long objId) { + this(skCase, objId, DEFAULT_CATEGORY); + } + + public ExtractedContent(SleuthkitCase skCase, long dataSourceObjId, Category category) { this.skCase = skCase; - this.filteringDSObjId = objId; - this.blackboard = skCase.getBlackboard(); + this.filteringDSObjId = dataSourceObjId; + this.category = category; } @Override @@ -107,11 +118,38 @@ public class ExtractedContent implements AutopsyVisitableItem { public SleuthkitCase getSleuthkitCase() { return skCase; } + + long getFilteringDSObjId() { + return filteringDSObjId; + } + + Category getCategory() { + return category; + } + + + + + + + static class RootNode extends DisplayableItemNode { + private static final Logger logger = Logger.getLogger(RootNode.class.getName()); + + private static Children getFactory(Category category, long filteringDSObjId) { + try { + TypeFactory factory = Category.ANALYSIS_RESULT.equals(category) ? + new AnalysisResultsTypeFactory(filteringDSObjId) : + new DataArtifactsTypeFactory(filteringDSObjId); + + return Children.create(factory, true); + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Attempt to instantiate TypeFactory with no open case.", ex); + return null; + } + } - public static class RootNode extends DisplayableItemNode { - - public RootNode(SleuthkitCase skCase) { - super(Children.create(new TypeFactory(), true), Lookups.singleton(NAME)); + RootNode(Category category, long filteringDSObjId) { + super(getFactory(category, filteringDSObjId), Lookups.singleton(NAME)); super.setName(NAME); super.setDisplayName(NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png"); //NON-NLS @@ -150,47 +188,59 @@ public class ExtractedContent implements AutopsyVisitableItem { } - // The “Email Messages” and “Accounts” nodes should become children of the “Data Artifacts” node, but should retain their current structure. + private static class AnalysisResultsTypeFactory extends TypeFactory { - // The “Keyword Hits,” “Hashset Hits,” and “Interesting Items” nodes should become children of the “Analysis Results” node, but should retain their current structure. - -// new KeywordHits(sleuthkitCase, dsObjId), -// new HashsetHits(sleuthkitCase, dsObjId), -// new EmailExtracted(sleuthkitCase, dsObjId), -// new InterestingHits(sleuthkitCase, dsObjId ), -// new Accounts(sleuthkitCase, dsObjId), -// new OsAccounts(sleuthkitCase, dsObjId)) + private static final Set EXCLUDED_ANALYSIS_RESULTS = Stream.of( + // these are shown in other parts of the UI (and different node types) + new BlackboardArtifact.Type(TSK_HASHSET_HIT), + new BlackboardArtifact.Type(TSK_KEYWORD_HIT), + new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT), + new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), + new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE) + ).collect(Collectors.toSet()); - - static class AnalysisResultsTypeFactory extends TypeFactory { - - private static Map getVisitableItems(Long filteringDSObjId) throws NoCurrentCaseException { + private static Map getVisitableItems(long filteringDSObjId) throws NoCurrentCaseException { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return new HashMap<>() {{ - put(filteringDSObjId == null ? new KeywordHits(skCase) : new KeywordHits(skCase, filteringDSObjId), TODO); //BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getDisplayName()); - put(filteringDSObjId == null ? new HashsetHits(skCase) : new HashsetHits(skCase, filteringDSObjId), TODO); // Bundle.Accounts_RootNode_displayName()); - put(filteringDSObjId == null ? new InterestingHits(skCase) : new InterestingHits(skCase, filteringDSObjId), TODO); // Bundle.Accounts_RootNode_displayName()); - }}; + return new HashMap() { + { + put(new KeywordHits(skCase, filteringDSObjId), KeywordHits.getDisplayName()); + put(new HashsetHits(skCase, filteringDSObjId), HashsetHits.getDisplayName()); + put(new InterestingHits(skCase, filteringDSObjId), InterestingHits.getDisplayName()); + } + }; } - - public AnalysisResultsTypeFactory(Long filteringDSObjId) throws NoCurrentCaseException { - super(getVisitableItems(filteringDSObjId), Category.DATA_ARTIFACT, filteringDSObjId); + + AnalysisResultsTypeFactory(long filteringDSObjId) throws NoCurrentCaseException { + super(getVisitableItems(filteringDSObjId), EXCLUDED_ANALYSIS_RESULTS, Category.DATA_ARTIFACT, filteringDSObjId); } } - - - static class DataArtifactsTypeFactory extends TypeFactory { - - private static Map getVisitableItems(Long filteringDSObjId) throws NoCurrentCaseException { + + private static class DataArtifactsTypeFactory extends TypeFactory { + + @SuppressWarnings("deprecation") + private static final Set EXCLUDED_DATA_ARTIFACTS = Stream.of( + // these are shown in other parts of the UI (and different node types) + new BlackboardArtifact.Type(TSK_GEN_INFO), + new BlackboardArtifact.Type(TSK_EMAIL_MSG), + new BlackboardArtifact.Type(TSK_ACCOUNT), + new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE), + new BlackboardArtifact.Type(TSK_TL_EVENT), + //This is not meant to be shown in the UI at all. It is more of a meta artifact. + new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) + ).collect(Collectors.toSet()); + + private static Map getVisitableItems(long filteringDSObjId) throws NoCurrentCaseException { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return new HashMap<>() {{ - put(filteringDSObjId == null ? new EmailExtracted(skCase) : new EmailExtracted(skCase, filteringDSObjId), TODO); //BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getDisplayName()); - put(filteringDSObjId == null ? new Accounts(skCase) : new Accounts(skCase, filteringDSObjId), TODO); // Bundle.Accounts_RootNode_displayName()); - }}; + return new HashMap() { + { + put(new EmailExtracted(skCase, filteringDSObjId), EmailExtracted.getDisplayName()); + put(new Accounts(skCase, filteringDSObjId), Accounts.getDisplayName()); + } + }; } - - public DataArtifactsTypeFactory(Long filteringDSObjId) throws NoCurrentCaseException { - super(getVisitableItems(filteringDSObjId), Category.DATA_ARTIFACT, filteringDSObjId); + + DataArtifactsTypeFactory(long filteringDSObjId) throws NoCurrentCaseException { + super(getVisitableItems(filteringDSObjId), EXCLUDED_DATA_ARTIFACTS, Category.DATA_ARTIFACT, filteringDSObjId); } } @@ -203,14 +253,14 @@ public class ExtractedContent implements AutopsyVisitableItem { void update(); } - static class VisitableArtifactKey implements ArtifactKey { + private static class VisitableArtifactKey implements ArtifactKey { private static final CreateAutopsyNodeVisitor visitor = new CreateAutopsyNodeVisitor(); private final AutopsyVisitableItem visitable; private final String name; - private final Long dsFilteringObjId; + private final long dsFilteringObjId; - VisitableArtifactKey(AutopsyVisitableItem visitable, String name, Long dsFilteringObjId) { + VisitableArtifactKey(AutopsyVisitableItem visitable, String name, long dsFilteringObjId) { this.visitable = visitable; this.name = name; this.dsFilteringObjId = dsFilteringObjId; @@ -266,13 +316,13 @@ public class ExtractedContent implements AutopsyVisitableItem { } - static class TypeArtifactKey implements ArtifactKey { + private static class TypeArtifactKey implements ArtifactKey { private final BlackboardArtifact.Type type; private final Map typeMapping; - private final Long dsFilteringObjId; + private final long dsFilteringObjId; - TypeArtifactKey(BlackboardArtifact.Type type, Map typeMapping, Long dsFilteringObjId) { + TypeArtifactKey(BlackboardArtifact.Type type, Map typeMapping, long dsFilteringObjId) { this.type = type; this.typeMapping = typeMapping; this.dsFilteringObjId = dsFilteringObjId; @@ -333,30 +383,13 @@ public class ExtractedContent implements AutopsyVisitableItem { * This area has all of the blackboard artifacts that are not displayed in a * more specific form elsewhere in the tree. */ - static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { - - @SuppressWarnings("deprecation") - private static final Set DO_NOT_SHOW = Stream.of( - // these are shown in other parts of the UI (and different node types) - new BlackboardArtifact.Type(TSK_GEN_INFO), - new BlackboardArtifact.Type(TSK_EMAIL_MSG), - new BlackboardArtifact.Type(TSK_HASHSET_HIT), - new BlackboardArtifact.Type(TSK_KEYWORD_HIT), - new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT), - new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), - new BlackboardArtifact.Type(TSK_ACCOUNT), - new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE), - new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE), - new BlackboardArtifact.Type(TSK_TL_EVENT), - //This is not meant to be shown in the UI at all. It is more of a meta artifact. - new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) - ).collect(Collectors.toSet()); + private static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); // maps the artifact type to its child node private final HashMap typeNodeMap = new HashMap<>(); - private final Long filteringDSObjId; + private final long filteringDSObjId; /** * RefreshThrottler is used to limit the number of refreshes performed @@ -366,11 +399,14 @@ public class ExtractedContent implements AutopsyVisitableItem { private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); private final Map visitableItems; private final Category category; + private final Set excludeTypes; @SuppressWarnings("deprecation") - TypeFactory(Map visitableItems, Category category, Long filteringDSObjId) { + TypeFactory(Map visitableItems, Set excludeTypes, + Category category, long filteringDSObjId) { super(); this.filteringDSObjId = filteringDSObjId; + this.excludeTypes = excludeTypes; this.visitableItems = visitableItems; this.category = category; } @@ -419,13 +455,12 @@ public class ExtractedContent implements AutopsyVisitableItem { protected boolean createKeys(List list) { try { // Potentially can reuse - List types = (this.filteringDSObjId != null) + List types = (this.filteringDSObjId > 0) ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactTypesInUse(this.filteringDSObjId) : Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse(); Stream typeArtifactKeys = types.stream() - .filter(tp -> category.equals(tp.getCategory())) - .filter(tp -> !DO_NOT_SHOW.contains(tp)) + .filter(tp -> category.equals(tp.getCategory()) && !excludeTypes.contains(tp)) .map(tp -> new TypeArtifactKey(tp, this.typeNodeMap, this.filteringDSObjId)); Stream visitableKeys = visitableItems.entrySet().stream() @@ -473,7 +508,8 @@ public class ExtractedContent implements AutopsyVisitableItem { * the event is a remote event. */ final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); - if (null != event && !(DO_NOT_SHOW.contains(event.getBlackboardArtifactType()))) { + if (null != event && category.equals(event.getBlackboardArtifactType().getCategory()) + && !(excludeTypes.contains(event.getBlackboardArtifactType()))) { return true; } } catch (NoCurrentCaseException notUsed) { @@ -498,9 +534,9 @@ public class ExtractedContent implements AutopsyVisitableItem { private final BlackboardArtifact.Type type; private long childCount = 0; - private final Long filteringDSObjId; + private final long filteringDSObjId; - TypeNode(BlackboardArtifact.Type type, Long filteringDSObjId) { + TypeNode(BlackboardArtifact.Type type, long filteringDSObjId) { super(Children.create(new ArtifactFactory(type, filteringDSObjId), true), Lookups.singleton(type.getDisplayName())); super.setName(type.getTypeName()); this.type = type; @@ -575,9 +611,9 @@ public class ExtractedContent implements AutopsyVisitableItem { * received. */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); - private final Long filteringDSObjId; + private final long filteringDSObjId; - ArtifactFactory(BlackboardArtifact.Type type, Long filteringDSObjId) { + ArtifactFactory(BlackboardArtifact.Type type, long filteringDSObjId) { super(type.getTypeName()); this.type = type; this.filteringDSObjId = filteringDSObjId; @@ -625,7 +661,7 @@ public class ExtractedContent implements AutopsyVisitableItem { protected List makeKeys() { try { List arts; - arts = (filteringDSObjId != null) + arts = (filteringDSObjId > 0) ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(type.getTypeID(), filteringDSObjId) : Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifacts(type.getTypeID()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index a939d977d0..e9eeb392d0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -66,6 +66,14 @@ public class HashsetHits implements AutopsyVisitableItem { private final HashsetResults hashsetResults; private final long filteringDSObjId; // 0 if not filtering/grouping by data source + /** + * Returns the display name for this module. + * @return The display name for this module. + */ + static String getDisplayName() { + return DISPLAY_NAME; + } + /** * Constructor * diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 677aef8df3..8db8588338 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -63,6 +63,14 @@ public class InterestingHits implements AutopsyVisitableItem { private final InterestingResults interestingResults = new InterestingResults(); private final long filteringDSObjId; // 0 if not filtering/grouping by data source + /** + * Returns the display name for this module. + * @return The display name for this module. + */ + static String getDisplayName() { + return DISPLAY_NAME; + } + /** * Constructor * diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 79c6b9a32e..230e35ff65 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -103,6 +103,15 @@ public class KeywordHits implements AutopsyVisitableItem { static private boolean isOnlyDefaultInstance(List instances) { return (instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME)); } + + + /** + * Returns the display name for KeywordHits. + * @return The display name for KeywordHits. + */ + static String getDisplayName() { + return KEYWORD_HITS; + } /** * Constructor diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index 355790976e..48193fde3c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -25,6 +25,8 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardArtifact.Category; import org.sleuthkit.datamodel.SleuthkitVisitableItem; /** @@ -85,7 +87,7 @@ public class RootContentChildren extends Children.Keys { @Override public ExtractedContent.RootNode visit(ExtractedContent ec) { - return ec.new RootNode(ec.getSleuthkitCase()); + return new ExtractedContent.RootNode(ec.getCategory(), ec.getFilteringDSObjId()); } @Override @@ -207,12 +209,16 @@ public class RootContentChildren extends Children.Keys { @Override public AbstractNode visit(AnalysisResults analysisResults) { - return new AnalysisResultsNode(analysisResults); + return new ExtractedContent.RootNode( + Category.ANALYSIS_RESULT, + analysisResults.getFilteringDataSourceObjId()); } @Override public AbstractNode visit(DataArtifacts dataArtifacts) { - return new DataArtifactsNode(dataArtifacts); + return new ExtractedContent.RootNode( + Category.ANALYSIS_RESULT, + dataArtifacts.getFilteringDataSourceObjId()); } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index 39f4303ef1..5ca9ba08c5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -93,6 +93,7 @@ final public class Accounts implements AutopsyVisitableItem { private static final String ICON_BASE_PATH = "/org/sleuthkit/autopsy/images/"; //NON-NLS private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED); + private static final String DISPLAY_NAME = Bundle.Accounts_RootNode_displayName(); @NbBundle.Messages("AccountsRootNode.name=Accounts") final public static String NAME = Bundle.AccountsRootNode_name(); @@ -113,6 +114,15 @@ final public class Accounts implements AutopsyVisitableItem { // tracks the number of each account type found private final AccountTypeResults accountTypeResults; + + /** + * Returns the display name for this module. + * @return The display name for this module. + */ + public static String getDisplayName() { + return DISPLAY_NAME; + } + /** * Constructor * @@ -236,7 +246,7 @@ final public class Accounts implements AutopsyVisitableItem { public AccountsRootNode() { super(Children.create(new AccountTypeFactory(), true), Lookups.singleton(Accounts.this)); setName(Accounts.NAME); - setDisplayName(Bundle.Accounts_RootNode_displayName()); + setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/accounts.png"); //NON-NLS } From 8d0ed1c1600f6d4db59458d9e32a3767f18fe00e Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 29 Apr 2021 10:41:41 -0400 Subject: [PATCH 07/21] IG removed intermin commits of drawabledb during bulk commit --- .../imagegallery/DrawableFileUpdateTask.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableFileUpdateTask.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableFileUpdateTask.java index 0e265b1fda..150aa04145 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableFileUpdateTask.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableFileUpdateTask.java @@ -161,7 +161,7 @@ final class DrawableFileUpdateTask extends DrawableDbTask { int workDone = 0; // Cycle through all of the files returned and call processFile on each //do in transaction - + drawableDbTransaction = getDrawableDB().beginTransaction(); /* * We are going to periodically commit the CaseDB transaction and * sleep so that the user can have Autopsy do other stuff while @@ -174,11 +174,7 @@ final class DrawableFileUpdateTask extends DrawableDbTask { if (caseDbTransaction == null) { caseDbTransaction = getCaseDB().beginTransaction(); } - - if (drawableDbTransaction == null) { - drawableDbTransaction = getDrawableDB().beginTransaction(); - } - + if (isCancelled() || Thread.interrupted()) { logger.log(Level.WARNING, "Task cancelled or interrupted: not all contents may be transfered to drawable database."); //NON-NLS endedEarly = true; @@ -195,11 +191,7 @@ final class DrawableFileUpdateTask extends DrawableDbTask { if ((++caseDbCounter % 200) == 0) { caseDbTransaction.commit(); caseDbTransaction = null; - - getDrawableDB().commitTransaction(drawableDbTransaction, true); - drawableDbTransaction = null; - - Thread.sleep(500); // 1/2 second + Thread.sleep(500); // 1/2 millisecond } } progressHandle.finish(); From 1d1904478c0e0a967d47f8cd9fa80f2447b3543c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 29 Apr 2021 13:59:07 -0400 Subject: [PATCH 08/21] fixes --- .../datamodel/Bundle.properties-MERGED | 2 + .../autopsy/datamodel/ExtractedContent.java | 184 +++++++++--------- .../datamodel/RootContentChildren.java | 10 +- .../autopsy/images/analysis_result.png | Bin 0 -> 443 bytes 4 files changed, 102 insertions(+), 94 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/images/analysis_result.png diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED index 49d648c6c0..aa955c23e8 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED @@ -39,6 +39,7 @@ AbstractAbstractFileNode.useridColLbl=UserID AbstractContentNode.nodescription=no description AbstractContentNode.valueLoading=value loading AbstractFsContentNode.noDesc.text=no description +AnalysisResultsNode_name=Analysis Results ArtifactStringContent.attrsTableHeader.sources=Source(s) ArtifactStringContent.attrsTableHeader.type=Type ArtifactStringContent.attrsTableHeader.value=Value @@ -93,6 +94,7 @@ ContentTagNode.createSheet.artifactMD5.displayName=MD5 Hash ContentTagNode.createSheet.artifactMD5.name=MD5 Hash ContentTagNode.createSheet.origFileName=Original Name ContentTagNode.createSheet.userName.text=User Name +DataArtifactsNode_name=Data Artifacts DataSourcesHostsNode_name=Data Sources DeletedContent.allDelFilter.text=All DeletedContent.createSheet.filterType.desc=no description diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 8f3f737e41..4c2caa54d8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -18,12 +18,9 @@ */ package org.sleuthkit.autopsy.datamodel; -import com.google.common.collect.ImmutableSet; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.EnumSet; import java.util.HashMap; import java.util.List; @@ -33,13 +30,12 @@ import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.lang3.StringUtils; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -49,7 +45,6 @@ import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.autopsy.datamodel.utils.IconsUtil; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.Blackboard; import org.sleuthkit.datamodel.BlackboardArtifact; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT; @@ -76,7 +71,7 @@ public class ExtractedContent implements AutopsyVisitableItem { private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text"); private static final Category DEFAULT_CATEGORY = Category.DATA_ARTIFACT; - + private final long filteringDSObjId; // 0 if not filtering/grouping by data source private SleuthkitCase skCase; // set to null after case has been closed private final Category category; @@ -89,7 +84,7 @@ public class ExtractedContent implements AutopsyVisitableItem { public ExtractedContent(SleuthkitCase skCase) { this(skCase, 0, DEFAULT_CATEGORY); } - + public ExtractedContent(SleuthkitCase skCase, Category category) { this(skCase, 0, DEFAULT_CATEGORY); } @@ -103,7 +98,7 @@ public class ExtractedContent implements AutopsyVisitableItem { public ExtractedContent(SleuthkitCase skCase, long objId) { this(skCase, objId, DEFAULT_CATEGORY); } - + public ExtractedContent(SleuthkitCase skCase, long dataSourceObjId, Category category) { this.skCase = skCase; this.filteringDSObjId = dataSourceObjId; @@ -118,41 +113,45 @@ public class ExtractedContent implements AutopsyVisitableItem { public SleuthkitCase getSleuthkitCase() { return skCase; } - + long getFilteringDSObjId() { return filteringDSObjId; } - + Category getCategory() { return category; } - - - - - - - static class RootNode extends DisplayableItemNode { - private static final Logger logger = Logger.getLogger(RootNode.class.getName()); - - private static Children getFactory(Category category, long filteringDSObjId) { - try { - TypeFactory factory = Category.ANALYSIS_RESULT.equals(category) ? - new AnalysisResultsTypeFactory(filteringDSObjId) : - new DataArtifactsTypeFactory(filteringDSObjId); - - return Children.create(factory, true); - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Attempt to instantiate TypeFactory with no open case.", ex); - return null; - } - } - RootNode(Category category, long filteringDSObjId) { - super(getFactory(category, filteringDSObjId), Lookups.singleton(NAME)); - super.setName(NAME); - super.setDisplayName(NAME); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png"); //NON-NLS + @Messages({ + "AnalysisResultsNode_name=Analysis Results",}) + static class AnalysisResultsNode extends RootNode { + + AnalysisResultsNode(long filteringDSObjId) { + super(Children.create(new AnalysisResultsTypeFactory(filteringDSObjId), true), + "org/sleuthkit/autopsy/images/analysis_result.png", + Bundle.AnalysisResultsNode_name(), + Bundle.AnalysisResultsNode_name()); + } + } + + @Messages({ + "DataArtifactsNode_name=Data Artifacts",}) + static class DataArtifactsNode extends RootNode { + + DataArtifactsNode(long filteringDSObjId) { + super(Children.create(new DataArtifactsTypeFactory(filteringDSObjId), true), + "org/sleuthkit/autopsy/images/extracted_content.png", + Bundle.DataArtifactsNode_name(), + Bundle.DataArtifactsNode_name()); + } + } + + static class RootNode extends DisplayableItemNode { + RootNode(Children children, String icon, String name, String displayName) { + super(children, Lookups.singleton(name)); + super.setName(name); + super.setDisplayName(displayName); + this.setIconBaseWithExtension(icon); //NON-NLS } @Override @@ -187,9 +186,10 @@ public class ExtractedContent implements AutopsyVisitableItem { } } - private static class AnalysisResultsTypeFactory extends TypeFactory { + private static final Logger logger = Logger.getLogger(AnalysisResultsTypeFactory.class.getName()); + private static final Set EXCLUDED_ANALYSIS_RESULTS = Stream.of( // these are shown in other parts of the UI (and different node types) new BlackboardArtifact.Type(TSK_HASHSET_HIT), @@ -199,24 +199,31 @@ public class ExtractedContent implements AutopsyVisitableItem { new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE) ).collect(Collectors.toSet()); - private static Map getVisitableItems(long filteringDSObjId) throws NoCurrentCaseException { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return new HashMap() { - { - put(new KeywordHits(skCase, filteringDSObjId), KeywordHits.getDisplayName()); - put(new HashsetHits(skCase, filteringDSObjId), HashsetHits.getDisplayName()); - put(new InterestingHits(skCase, filteringDSObjId), InterestingHits.getDisplayName()); - } - }; + private static Map getVisitableItems(long filteringDSObjId) { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return new HashMap() { + { + put(KeywordHits.getDisplayName(), new KeywordHits(skCase, filteringDSObjId)); + put(HashsetHits.getDisplayName(), new HashsetHits(skCase, filteringDSObjId)); + put(InterestingHits.getDisplayName(), new InterestingHits(skCase, filteringDSObjId)); + } + }; + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Trying to create AnalysisResultsTypeFactory with no open case.", ex); + return Collections.emptyMap(); + } } - AnalysisResultsTypeFactory(long filteringDSObjId) throws NoCurrentCaseException { - super(getVisitableItems(filteringDSObjId), EXCLUDED_ANALYSIS_RESULTS, Category.DATA_ARTIFACT, filteringDSObjId); + AnalysisResultsTypeFactory(long filteringDSObjId) { + super(getVisitableItems(filteringDSObjId), EXCLUDED_ANALYSIS_RESULTS, Category.ANALYSIS_RESULT, filteringDSObjId); } } private static class DataArtifactsTypeFactory extends TypeFactory { + private static final Logger logger = Logger.getLogger(DataArtifactsTypeFactory.class.getName()); + @SuppressWarnings("deprecation") private static final Set EXCLUDED_DATA_ARTIFACTS = Stream.of( // these are shown in other parts of the UI (and different node types) @@ -229,17 +236,22 @@ public class ExtractedContent implements AutopsyVisitableItem { new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) ).collect(Collectors.toSet()); - private static Map getVisitableItems(long filteringDSObjId) throws NoCurrentCaseException { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return new HashMap() { - { - put(new EmailExtracted(skCase, filteringDSObjId), EmailExtracted.getDisplayName()); - put(new Accounts(skCase, filteringDSObjId), Accounts.getDisplayName()); - } - }; + private static Map getVisitableItems(long filteringDSObjId) { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return new HashMap() { + { + put(EmailExtracted.getDisplayName(), new EmailExtracted(skCase, filteringDSObjId)); + put(Accounts.getDisplayName(), new Accounts(skCase, filteringDSObjId)); + } + }; + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Trying to create DataArtifactsTypeFactory with no open case.", ex); + return Collections.emptyMap(); + } } - DataArtifactsTypeFactory(long filteringDSObjId) throws NoCurrentCaseException { + DataArtifactsTypeFactory(long filteringDSObjId) { super(getVisitableItems(filteringDSObjId), EXCLUDED_DATA_ARTIFACTS, Category.DATA_ARTIFACT, filteringDSObjId); } } @@ -283,10 +295,9 @@ public class ExtractedContent implements AutopsyVisitableItem { @Override public int hashCode() { - int hash = 5; - hash = 37 * hash + Objects.hashCode(this.visitable); - hash = 37 * hash + Objects.hashCode(this.name); - hash = 37 * hash + Objects.hashCode(this.dsFilteringObjId); + int hash = 7; + hash = 53 * hash + Objects.hashCode(this.name); + hash = 53 * hash + (int) (this.dsFilteringObjId ^ (this.dsFilteringObjId >>> 32)); return hash; } @@ -302,18 +313,14 @@ public class ExtractedContent implements AutopsyVisitableItem { return false; } final VisitableArtifactKey other = (VisitableArtifactKey) obj; + if (this.dsFilteringObjId != other.dsFilteringObjId) { + return false; + } if (!Objects.equals(this.name, other.name)) { return false; } - if (!Objects.equals(this.visitable, other.visitable)) { - return false; - } - if (!Objects.equals(this.dsFilteringObjId, other.dsFilteringObjId)) { - return false; - } return true; } - } private static class TypeArtifactKey implements ArtifactKey { @@ -346,9 +353,8 @@ public class ExtractedContent implements AutopsyVisitableItem { @Override public int hashCode() { int hash = 7; - hash = 83 * hash + Objects.hashCode(this.type); - hash = 83 * hash + Objects.hashCode(this.typeMapping); - hash = 83 * hash + Objects.hashCode(this.dsFilteringObjId); + hash = 53 * hash + Objects.hashCode(this.type); + hash = 53 * hash + (int) (this.dsFilteringObjId ^ (this.dsFilteringObjId >>> 32)); return hash; } @@ -364,18 +370,14 @@ public class ExtractedContent implements AutopsyVisitableItem { return false; } final TypeArtifactKey other = (TypeArtifactKey) obj; + if (this.dsFilteringObjId != other.dsFilteringObjId) { + return false; + } if (!Objects.equals(this.type, other.type)) { return false; } - if (!Objects.equals(this.typeMapping, other.typeMapping)) { - return false; - } - if (!Objects.equals(this.dsFilteringObjId, other.dsFilteringObjId)) { - return false; - } return true; } - } /** @@ -397,12 +399,12 @@ public class ExtractedContent implements AutopsyVisitableItem { * received. */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); - private final Map visitableItems; + private final Map visitableItems; private final Category category; private final Set excludeTypes; @SuppressWarnings("deprecation") - TypeFactory(Map visitableItems, Set excludeTypes, + TypeFactory(Map visitableItems, Set excludeTypes, Category category, long filteringDSObjId) { super(); this.filteringDSObjId = filteringDSObjId; @@ -464,14 +466,20 @@ public class ExtractedContent implements AutopsyVisitableItem { .map(tp -> new TypeArtifactKey(tp, this.typeNodeMap, this.filteringDSObjId)); Stream visitableKeys = visitableItems.entrySet().stream() - .map(entry -> new VisitableArtifactKey(entry.getKey(), entry.getValue(), filteringDSObjId)); + .map(entry -> new VisitableArtifactKey(entry.getValue(), entry.getKey(), filteringDSObjId)); - Stream.concat(typeArtifactKeys, visitableKeys) - .sorted((a, b) -> StringUtils.compareIgnoreCase(a.getName(), b.getName())) - .forEach((artifactTypeKey -> { - artifactTypeKey.update(); - list.add(artifactTypeKey); - })); + List allKeysSorted = Stream.concat(typeArtifactKeys, visitableKeys) + .filter(item -> item != null) + .sorted((a, b) -> { + String aSafe = (a.getName() == null) ? "" : a.getName(); + String bSafe = (b.getName() == null) ? "" : b.getName(); + return aSafe.compareToIgnoreCase(bSafe); + }) + .collect(Collectors.toList()); + + allKeysSorted.forEach(ArtifactKey::update); + + list.addAll(allKeysSorted); } catch (NoCurrentCaseException ex) { logger.log(Level.WARNING, "Trying to access case when no case is open.", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index 48193fde3c..192a966490 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -87,7 +87,7 @@ public class RootContentChildren extends Children.Keys { @Override public ExtractedContent.RootNode visit(ExtractedContent ec) { - return new ExtractedContent.RootNode(ec.getCategory(), ec.getFilteringDSObjId()); + return new ExtractedContent.DataArtifactsNode(0); } @Override @@ -169,7 +169,7 @@ public class RootContentChildren extends Children.Keys { public AbstractNode visit(Accounts accountsItem) { return accountsItem.new AccountsRootNode(); } - + @Override public AbstractNode visit(OsAccounts osAccountsItem) { return osAccountsItem.new OsAccountListNode(); @@ -209,15 +209,13 @@ public class RootContentChildren extends Children.Keys { @Override public AbstractNode visit(AnalysisResults analysisResults) { - return new ExtractedContent.RootNode( - Category.ANALYSIS_RESULT, + return new ExtractedContent.AnalysisResultsNode( analysisResults.getFilteringDataSourceObjId()); } @Override public AbstractNode visit(DataArtifacts dataArtifacts) { - return new ExtractedContent.RootNode( - Category.ANALYSIS_RESULT, + return new ExtractedContent.DataArtifactsNode( dataArtifacts.getFilteringDataSourceObjId()); } } diff --git a/Core/src/org/sleuthkit/autopsy/images/analysis_result.png b/Core/src/org/sleuthkit/autopsy/images/analysis_result.png new file mode 100644 index 0000000000000000000000000000000000000000..0ff446770a14779b07fb8e55f547327489006fe3 GIT binary patch literal 443 zcmV;s0Yv_ZP)* zfC5ufQwb|;>uFXtwvU1A|K=7J-z+UHcbb@(=)lzA1m@=E7FJf)9}6q%zpmSR`v2*B z@BSaV@#6o4*-O4!S=)RvHa0dw*8>M2n=LJ^KFnXUd^Iq0Wc8zGYiTdqH9FPImH!ELF&-;f&nNNfZljBd->*9=o&$I;@lPQf%4yh z>fQpeJ-U7{0Hp&nGqcx8Y1tQ7?KpZL6eg>79(|aUk$V}a=?^e5y?1nU{AFQb@d2kH zAeR8~M4&;pK`9YRgZQC91AYKg<$ot9r@wd&!3BUCoClvFpfCaQU!toa2w;W)>90UM l6J4Gt05Sv^xDP-94*;r!O$*M}Fj4>j002ovPDHLkV1f_j%)0;p literal 0 HcmV?d00001 From 4c8b609d52a4b0881584636e974d375119ce56b5 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 29 Apr 2021 17:03:17 -0400 Subject: [PATCH 09/21] 7534 adjust menu item order --- .../sleuthkit/autopsy/apputils/ResetWindowsAction.java | 2 +- Core/src/org/sleuthkit/autopsy/core/layer.xml | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/apputils/ResetWindowsAction.java b/Core/src/org/sleuthkit/autopsy/apputils/ResetWindowsAction.java index c5298bc64e..25bacd3761 100644 --- a/Core/src/org/sleuthkit/autopsy/apputils/ResetWindowsAction.java +++ b/Core/src/org/sleuthkit/autopsy/apputils/ResetWindowsAction.java @@ -44,7 +44,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil; */ @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.apputils.ResetWindowsAction") @ActionReferences(value = { - @ActionReference(path = "Menu/Window", position = 105)}) + @ActionReference(path = "Menu/Window", position = 205)}) @ActionRegistration(displayName = "#CTL_ResetWindowsAction", lazy = false) @NbBundle.Messages({"CTL_ResetWindowsAction=Reset Windows"}) public final class ResetWindowsAction extends CallableSystemAction { diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index f9f537541d..3a8865f643 100644 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -250,18 +250,10 @@ - - - - - - - - From e2f83a897a01d4fddfc035e5a5f286b36e9620e7 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 30 Apr 2021 09:20:25 -0400 Subject: [PATCH 10/21] changes to hide nodes with no results --- .../autopsy/datamodel/ExtractedContent.java | 307 ++++++------------ 1 file changed, 106 insertions(+), 201 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 4c2caa54d8..2204fcf64c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -24,8 +24,6 @@ import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; @@ -40,27 +38,26 @@ import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.RootContentChildren.CreateAutopsyNodeVisitor; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.autopsy.datamodel.utils.IconsUtil; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_TL_EVENT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.guiutils.RefreshThrottler; import org.sleuthkit.datamodel.BlackboardArtifact.Category; +import org.python.google.common.collect.Sets; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; /** * Parent of the "extracted content" artifacts to be displayed in the tree. @@ -147,6 +144,7 @@ public class ExtractedContent implements AutopsyVisitableItem { } static class RootNode extends DisplayableItemNode { + RootNode(Children children, String icon, String name, String displayName) { super(children, Lookups.singleton(name)); super.setName(name); @@ -187,197 +185,51 @@ public class ExtractedContent implements AutopsyVisitableItem { } private static class AnalysisResultsTypeFactory extends TypeFactory { - - private static final Logger logger = Logger.getLogger(AnalysisResultsTypeFactory.class.getName()); - - private static final Set EXCLUDED_ANALYSIS_RESULTS = Stream.of( - // these are shown in other parts of the UI (and different node types) - new BlackboardArtifact.Type(TSK_HASHSET_HIT), - new BlackboardArtifact.Type(TSK_KEYWORD_HIT), - new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT), - new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), - new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE) - ).collect(Collectors.toSet()); - - private static Map getVisitableItems(long filteringDSObjId) { - try { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return new HashMap() { - { - put(KeywordHits.getDisplayName(), new KeywordHits(skCase, filteringDSObjId)); - put(HashsetHits.getDisplayName(), new HashsetHits(skCase, filteringDSObjId)); - put(InterestingHits.getDisplayName(), new InterestingHits(skCase, filteringDSObjId)); - } - }; - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Trying to create AnalysisResultsTypeFactory with no open case.", ex); - return Collections.emptyMap(); - } - } - AnalysisResultsTypeFactory(long filteringDSObjId) { - super(getVisitableItems(filteringDSObjId), EXCLUDED_ANALYSIS_RESULTS, Category.ANALYSIS_RESULT, filteringDSObjId); + super(Category.ANALYSIS_RESULT, filteringDSObjId); } } private static class DataArtifactsTypeFactory extends TypeFactory { - - private static final Logger logger = Logger.getLogger(DataArtifactsTypeFactory.class.getName()); - - @SuppressWarnings("deprecation") - private static final Set EXCLUDED_DATA_ARTIFACTS = Stream.of( - // these are shown in other parts of the UI (and different node types) - new BlackboardArtifact.Type(TSK_GEN_INFO), - new BlackboardArtifact.Type(TSK_EMAIL_MSG), - new BlackboardArtifact.Type(TSK_ACCOUNT), - new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE), - new BlackboardArtifact.Type(TSK_TL_EVENT), - //This is not meant to be shown in the UI at all. It is more of a meta artifact. - new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) - ).collect(Collectors.toSet()); - - private static Map getVisitableItems(long filteringDSObjId) { - try { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return new HashMap() { - { - put(EmailExtracted.getDisplayName(), new EmailExtracted(skCase, filteringDSObjId)); - put(Accounts.getDisplayName(), new Accounts(skCase, filteringDSObjId)); - } - }; - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Trying to create DataArtifactsTypeFactory with no open case.", ex); - return Collections.emptyMap(); - } - } - DataArtifactsTypeFactory(long filteringDSObjId) { - super(getVisitableItems(filteringDSObjId), EXCLUDED_DATA_ARTIFACTS, Category.DATA_ARTIFACT, filteringDSObjId); + super(Category.DATA_ARTIFACT, filteringDSObjId); } } - interface ArtifactKey { + private static class TypeNodeRecord { - Node getNode(); + private final Node node; + private final Runnable onUpdate; + private final Set applicableTypes; - String getName(); - - void update(); - } - - private static class VisitableArtifactKey implements ArtifactKey { - - private static final CreateAutopsyNodeVisitor visitor = new CreateAutopsyNodeVisitor(); - private final AutopsyVisitableItem visitable; - private final String name; - private final long dsFilteringObjId; - - VisitableArtifactKey(AutopsyVisitableItem visitable, String name, long dsFilteringObjId) { - this.visitable = visitable; - this.name = name; - this.dsFilteringObjId = dsFilteringObjId; + TypeNodeRecord(BlackboardArtifact.Type type, long dsObjId) { + this(new TypeNode(type, dsObjId), type); } - @Override - public Node getNode() { - return visitable.accept(visitor); + private TypeNodeRecord(TypeNode typeNode, BlackboardArtifact.Type type) { + this(typeNode, typeNode::updateDisplayName, Stream.of(type).collect(Collectors.toSet())); } - @Override - public String getName() { - return this.name; + TypeNodeRecord(Node node, Runnable onUpdate, Set applicableTypes) { + this.node = node; + this.onUpdate = onUpdate; + this.applicableTypes = applicableTypes; } - @Override - public void update() { - // no need to handle updates for a visitable item + Node getNode() { + return node; } - @Override - public int hashCode() { - int hash = 7; - hash = 53 * hash + Objects.hashCode(this.name); - hash = 53 * hash + (int) (this.dsFilteringObjId ^ (this.dsFilteringObjId >>> 32)); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; + void update() { + if (onUpdate != null) { + onUpdate.run(); } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final VisitableArtifactKey other = (VisitableArtifactKey) obj; - if (this.dsFilteringObjId != other.dsFilteringObjId) { - return false; - } - if (!Objects.equals(this.name, other.name)) { - return false; - } - return true; - } - } - - private static class TypeArtifactKey implements ArtifactKey { - - private final BlackboardArtifact.Type type; - private final Map typeMapping; - private final long dsFilteringObjId; - - TypeArtifactKey(BlackboardArtifact.Type type, Map typeMapping, long dsFilteringObjId) { - this.type = type; - this.typeMapping = typeMapping; - this.dsFilteringObjId = dsFilteringObjId; } - @Override - public TypeNode getNode() { - return typeMapping.computeIfAbsent(type, (tp) -> new TypeNode(type, dsFilteringObjId)); + Set getApplicableTypes() { + return applicableTypes; } - @Override - public String getName() { - return this.type.getDisplayName(); - } - - @Override - public void update() { - getNode().updateDisplayName(); - } - - @Override - public int hashCode() { - int hash = 7; - hash = 53 * hash + Objects.hashCode(this.type); - hash = 53 * hash + (int) (this.dsFilteringObjId ^ (this.dsFilteringObjId >>> 32)); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final TypeArtifactKey other = (TypeArtifactKey) obj; - if (this.dsFilteringObjId != other.dsFilteringObjId) { - return false; - } - if (!Objects.equals(this.type, other.type)) { - return false; - } - return true; - } } /** @@ -385,12 +237,59 @@ public class ExtractedContent implements AutopsyVisitableItem { * This area has all of the blackboard artifacts that are not displayed in a * more specific form elsewhere in the tree. */ - private static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { + private static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); + private static final Set IGNORED_TYPES = Sets.newHashSet( + // these are shown in other parts of the UI (and different node types) + new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE), + new BlackboardArtifact.Type(TSK_GEN_INFO), + new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE), + new BlackboardArtifact.Type(TSK_TL_EVENT), + //This is not meant to be shown in the UI at all. It is more of a meta artifact. + new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) + ); + + private static TypeNodeRecord getRecord(BlackboardArtifact.Type type, SleuthkitCase skCase, long dsObjId) { + int typeId = type.getTypeID(); + if (TSK_EMAIL_MSG.getTypeID() == typeId) { + EmailExtracted.RootNode emailNode = new EmailExtracted(skCase, dsObjId).new RootNode(); + return new TypeNodeRecord( + emailNode, + null, + Sets.newHashSet(new BlackboardArtifact.Type(TSK_EMAIL_MSG))); + + } else if (TSK_ACCOUNT.getTypeID() == typeId) { + Accounts.AccountsRootNode accountsNode = new Accounts(skCase, dsObjId).new AccountsRootNode(); + return new TypeNodeRecord( + accountsNode, + null, + Sets.newHashSet(new BlackboardArtifact.Type(TSK_ACCOUNT))); + + } else if (TSK_KEYWORD_HIT.getTypeID() == typeId) { + KeywordHits.RootNode keywordsNode = new KeywordHits(skCase, dsObjId).new RootNode(); + return new TypeNodeRecord( + keywordsNode, + null, + Sets.newHashSet(new BlackboardArtifact.Type(TSK_KEYWORD_HIT))); + + } else if (TSK_EMAIL_MSG.getTypeID() == typeId) { + InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, dsObjId).new RootNode(); + return new TypeNodeRecord( + interestingHitsNode, + null, + Sets.newHashSet( + new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), + new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT))); + + } else { + return new TypeNodeRecord(type, dsObjId); + } + } + // maps the artifact type to its child node - private final HashMap typeNodeMap = new HashMap<>(); + private final HashMap typeNodeMap = new HashMap<>(); private final long filteringDSObjId; /** @@ -399,17 +298,12 @@ public class ExtractedContent implements AutopsyVisitableItem { * received. */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); - private final Map visitableItems; private final Category category; - private final Set excludeTypes; @SuppressWarnings("deprecation") - TypeFactory(Map visitableItems, Set excludeTypes, - Category category, long filteringDSObjId) { + TypeFactory(Category category, long filteringDSObjId) { super(); this.filteringDSObjId = filteringDSObjId; - this.excludeTypes = excludeTypes; - this.visitableItems = visitableItems; this.category = category; } @@ -454,31 +348,42 @@ public class ExtractedContent implements AutopsyVisitableItem { } @Override - protected boolean createKeys(List list) { + protected boolean createKeys(List list) { try { + // Potentially can reuse List types = (this.filteringDSObjId > 0) ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactTypesInUse(this.filteringDSObjId) : Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse(); - Stream typeArtifactKeys = types.stream() - .filter(tp -> category.equals(tp.getCategory()) && !excludeTypes.contains(tp)) - .map(tp -> new TypeArtifactKey(tp, this.typeNodeMap, this.filteringDSObjId)); - - Stream visitableKeys = visitableItems.entrySet().stream() - .map(entry -> new VisitableArtifactKey(entry.getValue(), entry.getKey(), filteringDSObjId)); - - List allKeysSorted = Stream.concat(typeArtifactKeys, visitableKeys) - .filter(item -> item != null) + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + + List allKeysSorted = types.stream() + .filter(tp -> category.equals(tp.getCategory()) && !IGNORED_TYPES.contains(tp)) + .map(tp -> { + if (typeNodeMap.containsKey(tp)) { + TypeNodeRecord record = typeNodeMap.get(tp); + record.update(); + return record; + } else { + TypeNodeRecord newRecord = getRecord(tp, skCase, filteringDSObjId); + for (BlackboardArtifact.Type recordType : newRecord.getApplicableTypes()) { + typeNodeMap.put(recordType, newRecord); + } + return newRecord; + } + }) + .filter(record -> record != null) + .distinct() .sorted((a, b) -> { - String aSafe = (a.getName() == null) ? "" : a.getName(); - String bSafe = (b.getName() == null) ? "" : b.getName(); + String aSafe = (a.getNode() == null || a.getNode().getDisplayName() == null) ? "" : a.getNode().getDisplayName(); + String bSafe = (b.getNode() == null || b.getNode().getDisplayName() == null) ? "" : b.getNode().getDisplayName(); return aSafe.compareToIgnoreCase(bSafe); }) .collect(Collectors.toList()); - - allKeysSorted.forEach(ArtifactKey::update); - + + allKeysSorted.forEach(record -> record.update()); + list.addAll(allKeysSorted); } catch (NoCurrentCaseException ex) { @@ -490,7 +395,7 @@ public class ExtractedContent implements AutopsyVisitableItem { } @Override - protected Node createNodeForKey(ArtifactKey key) { + protected Node createNodeForKey(TypeNodeRecord key) { return key.getNode(); } @@ -517,7 +422,7 @@ public class ExtractedContent implements AutopsyVisitableItem { */ final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); if (null != event && category.equals(event.getBlackboardArtifactType().getCategory()) - && !(excludeTypes.contains(event.getBlackboardArtifactType()))) { + && !(IGNORED_TYPES.contains(event.getBlackboardArtifactType()))) { return true; } } catch (NoCurrentCaseException notUsed) { From eadb3a8c6bd5259efcbd249ae7231eaa69995d96 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 30 Apr 2021 11:01:09 -0400 Subject: [PATCH 11/21] counts in special artifact nodes --- .../autopsy/datamodel/EmailExtracted.java | 22 ++-- .../autopsy/datamodel/ExtractedContent.java | 102 +++++++++++++----- .../autopsy/datamodel/HashsetHits.java | 20 ++-- .../autopsy/datamodel/InterestingHits.java | 21 ++-- .../autopsy/datamodel/KeywordHits.java | 21 ++-- .../autopsy/datamodel/accounts/Accounts.java | 23 ++-- 6 files changed, 125 insertions(+), 84 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 6495e9d7fe..9e3555d438 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -32,7 +32,6 @@ import java.util.Observable; import java.util.Observer; import java.util.Set; import java.util.logging.Level; -import org.apache.commons.lang3.tuple.Pair; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; @@ -45,10 +44,12 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; /** * Support for TSK_EMAIL_MSG nodes and displaying emails in the directory tree. @@ -59,7 +60,6 @@ import org.sleuthkit.datamodel.TskCoreException; public class EmailExtracted implements AutopsyVisitableItem { private static final String LABEL_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getLabel(); - private static final String DISPLAY_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getDisplayName(); private static final Logger logger = Logger.getLogger(EmailExtracted.class.getName()); private static final String MAIL_ACCOUNT = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailAccount.text"); private static final String MAIL_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text"); @@ -91,14 +91,6 @@ public class EmailExtracted implements AutopsyVisitableItem { private SleuthkitCase skCase; private final EmailResults emailResults; private final long filteringDSObjId; // 0 if not filtering/grouping by data source - - /** - * Returns the display name for this module. - * @return The display name for this module. - */ - static String getDisplayName() { - return DISPLAY_NAME; - } /** * Constructor @@ -213,12 +205,16 @@ public class EmailExtracted implements AutopsyVisitableItem { * Mail root node grouping all mail accounts, supports account-> folder * structure */ - public class RootNode extends DisplayableItemNode { + public class RootNode extends UpdatableTypeCountNode { public RootNode() { - super(Children.create(new AccountFactory(), true), Lookups.singleton(DISPLAY_NAME)); + super(Children.create(new AccountFactory(), true), + Lookups.singleton(TSK_EMAIL_MSG.getDisplayName()), + TSK_EMAIL_MSG.getDisplayName(), + filteringDSObjId, + new BlackboardArtifact.Type(TSK_EMAIL_MSG)); + //super(Children.create(new AccountFactory(), true), Lookups.singleton(DISPLAY_NAME)); super.setName(LABEL_NAME); - super.setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/mail-icon-16.png"); //NON-NLS emailResults.update(); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 2204fcf64c..6893c546db 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -20,9 +20,11 @@ package org.sleuthkit.autopsy.datamodel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; @@ -32,6 +34,7 @@ import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; +import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.Lookups; @@ -185,12 +188,14 @@ public class ExtractedContent implements AutopsyVisitableItem { } private static class AnalysisResultsTypeFactory extends TypeFactory { + AnalysisResultsTypeFactory(long filteringDSObjId) { super(Category.ANALYSIS_RESULT, filteringDSObjId); } } private static class DataArtifactsTypeFactory extends TypeFactory { + DataArtifactsTypeFactory(long filteringDSObjId) { super(Category.DATA_ARTIFACT, filteringDSObjId); } @@ -274,7 +279,9 @@ public class ExtractedContent implements AutopsyVisitableItem { null, Sets.newHashSet(new BlackboardArtifact.Type(TSK_KEYWORD_HIT))); - } else if (TSK_EMAIL_MSG.getTypeID() == typeId) { + } else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId || + TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) { + InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, dsObjId).new RootNode(); return new TypeNodeRecord( interestingHitsNode, @@ -351,13 +358,11 @@ public class ExtractedContent implements AutopsyVisitableItem { protected boolean createKeys(List list) { try { - // Potentially can reuse - List types = (this.filteringDSObjId > 0) - ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactTypesInUse(this.filteringDSObjId) - : Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse(); - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - + List types = (this.filteringDSObjId > 0) + ? skCase.getBlackboard().getArtifactTypesInUse(this.filteringDSObjId) + : skCase.getArtifactTypesInUse(); + List allKeysSorted = types.stream() .filter(tp -> category.equals(tp.getCategory()) && !IGNORED_TYPES.contains(tp)) .map(tp -> { @@ -435,41 +440,84 @@ public class ExtractedContent implements AutopsyVisitableItem { } } + public static abstract class UpdatableTypeCountNode extends DisplayableItemNode { + + private static final Logger logger = Logger.getLogger(UpdatableTypeCountNode.class.getName()); + + private final Set types; + private final long filteringDSObjId; + private long childCount = 0; + private final String baseName; + + /** + * Constructs a node that is eligible for display in the tree view or + * results view. Capabilitites include accepting a + * DisplayableItemNodeVisitor, indicating whether or not the node is a + * leaf node, providing an item type string suitable for use as a key, + * and storing information about a child node that is to be selected if + * the node is selected in the tree view. + * + * @param children The Children object for the node. + * @param lookup The Lookup object for the node. + */ + public UpdatableTypeCountNode(Children children, Lookup lookup, String baseName, long filteringDSObjId, BlackboardArtifact.Type... types) { + super(children, lookup); + this.types = Stream.of(types).collect(Collectors.toSet()); + this.filteringDSObjId = filteringDSObjId; + this.baseName = baseName; + updateDisplayName(); + } + + protected long getChildCount() { + return this.childCount; + } + + void updateDisplayName() { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + + int count = 0; + for (BlackboardArtifact.Type type : this.types) { + if (filteringDSObjId > 0) { + count += skCase.getBlackboard().getArtifactsCount(type.getTypeID(), filteringDSObjId); + } else { + count += skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); + } + } + + this.childCount = count; + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Error fetching data when case closed.", ex); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Error getting child count", ex); //NON-NLS + } + super.setDisplayName(this.baseName + " \u200E(\u200E" + this.childCount + ")\u200E"); + } + } + /** * Node encapsulating blackboard artifact type. This is used on the * left-hand navigation side of the Autopsy UI as the parent node for all of * the artifacts of a given type. Its children will be * BlackboardArtifactNode objects. */ - public static class TypeNode extends DisplayableItemNode { + public static class TypeNode extends UpdatableTypeCountNode { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); private final BlackboardArtifact.Type type; - private long childCount = 0; - private final long filteringDSObjId; TypeNode(BlackboardArtifact.Type type, long filteringDSObjId) { - super(Children.create(new ArtifactFactory(type, filteringDSObjId), true), Lookups.singleton(type.getDisplayName())); + super(Children.create(new ArtifactFactory(type, filteringDSObjId), true), + Lookups.singleton(type.getDisplayName()), + type.getDisplayName(), + filteringDSObjId, + type); + super.setName(type.getTypeName()); this.type = type; - this.filteringDSObjId = filteringDSObjId; String iconPath = IconsUtil.getIconFilePath(type.getTypeID()); setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath); - updateDisplayName(); - } - - final void updateDisplayName() { - try { - this.childCount = (filteringDSObjId > 0) - ? Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifactsCount(type.getTypeID(), filteringDSObjId) - : Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifactsTypeCount(type.getTypeID()); - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Error fetching data when case closed.", ex); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error getting child count", ex); //NON-NLS - } - super.setDisplayName(type.getDisplayName() + " \u200E(\u200E" + childCount + ")\u200E"); } @Override @@ -489,7 +537,7 @@ public class ExtractedContent implements AutopsyVisitableItem { sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.name"), NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.displayName"), NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.desc"), - childCount)); + getChildCount())); return sheet; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index e9eeb392d0..c063081699 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -47,10 +47,14 @@ import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; + /** * Hash set hits node support. Inner classes have all of the nodes in the tree. @@ -66,13 +70,6 @@ public class HashsetHits implements AutopsyVisitableItem { private final HashsetResults hashsetResults; private final long filteringDSObjId; // 0 if not filtering/grouping by data source - /** - * Returns the display name for this module. - * @return The display name for this module. - */ - static String getDisplayName() { - return DISPLAY_NAME; - } /** * Constructor @@ -176,10 +173,15 @@ public class HashsetHits implements AutopsyVisitableItem { /** * Top-level node for all hash sets */ - public class RootNode extends DisplayableItemNode { + public class RootNode extends UpdatableTypeCountNode { public RootNode() { - super(Children.create(new HashsetNameFactory(), true), Lookups.singleton(DISPLAY_NAME)); + super(Children.create(new HashsetNameFactory(), true), + Lookups.singleton(DISPLAY_NAME), + DISPLAY_NAME, + filteringDSObjId, + new BlackboardArtifact.Type(TSK_HASHSET_HIT)); + super.setName(HASHSET_HITS); super.setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 8db8588338..93b6480c26 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -50,6 +50,9 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; + public class InterestingHits implements AutopsyVisitableItem { @@ -63,14 +66,6 @@ public class InterestingHits implements AutopsyVisitableItem { private final InterestingResults interestingResults = new InterestingResults(); private final long filteringDSObjId; // 0 if not filtering/grouping by data source - /** - * Returns the display name for this module. - * @return The display name for this module. - */ - static String getDisplayName() { - return DISPLAY_NAME; - } - /** * Constructor * @@ -173,12 +168,16 @@ public class InterestingHits implements AutopsyVisitableItem { /** * Node for the interesting items */ - public class RootNode extends DisplayableItemNode { + public class RootNode extends UpdatableTypeCountNode { public RootNode() { - super(Children.create(new SetNameFactory(), true), Lookups.singleton(DISPLAY_NAME)); + super(Children.create(new SetNameFactory(), true), + Lookups.singleton(DISPLAY_NAME), + DISPLAY_NAME, + filteringDSObjId, + new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT), + new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT)); super.setName(INTERESTING_ITEMS); - super.setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 230e35ff65..82ea4263b1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -55,6 +55,8 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; +import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; /** * Keyword hits node support @@ -104,15 +106,6 @@ public class KeywordHits implements AutopsyVisitableItem { return (instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME)); } - - /** - * Returns the display name for KeywordHits. - * @return The display name for KeywordHits. - */ - static String getDisplayName() { - return KEYWORD_HITS; - } - /** * Constructor * @@ -384,12 +377,16 @@ public class KeywordHits implements AutopsyVisitableItem { } // Created by CreateAutopsyNodeVisitor - public class RootNode extends DisplayableItemNode { + public class RootNode extends UpdatableTypeCountNode { public RootNode() { - super(Children.create(new ListFactory(), true), Lookups.singleton(KEYWORD_HITS)); + super(Children.create(new ListFactory(), true), + Lookups.singleton(KEYWORD_HITS), + KEYWORD_HITS, + filteringDSObjId, + new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); + super.setName(NAME); - super.setDisplayName(KEYWORD_HITS); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index 5ca9ba08c5..2eb2c6e021 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -69,6 +69,8 @@ import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; +import org.sleuthkit.autopsy.datamodel.ExtractedContent; +import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -77,6 +79,7 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; @@ -115,14 +118,6 @@ final public class Accounts implements AutopsyVisitableItem { private final AccountTypeResults accountTypeResults; - /** - * Returns the display name for this module. - * @return The display name for this module. - */ - public static String getDisplayName() { - return DISPLAY_NAME; - } - /** * Constructor * @@ -241,12 +236,16 @@ final public class Accounts implements AutopsyVisitableItem { * Top-level node for the accounts tree */ @NbBundle.Messages({"Accounts.RootNode.displayName=Accounts"}) - final public class AccountsRootNode extends DisplayableItemNode { + final public class AccountsRootNode extends UpdatableTypeCountNode { public AccountsRootNode() { - super(Children.create(new AccountTypeFactory(), true), Lookups.singleton(Accounts.this)); + super(Children.create(new AccountTypeFactory(), true), + Lookups.singleton(Accounts.this), + DISPLAY_NAME, + filteringDSObjId, + new BlackboardArtifact.Type(TSK_ACCOUNT)); + setName(Accounts.NAME); - setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/accounts.png"); //NON-NLS } @@ -303,7 +302,7 @@ final public class Accounts implements AutopsyVisitableItem { = "SELECT blackboard_attributes.value_text as account_type, COUNT(*) as count " + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + getFilterByDataSourceClause() + " GROUP BY blackboard_attributes.value_text "; From 758b5fcc36037f571a1d541480f9cbd2a71ce27f Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 30 Apr 2021 11:06:11 -0400 Subject: [PATCH 12/21] refactor --- .../autopsy/datamodel/ExtractedContent.java | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 6893c546db..48519061d0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -211,14 +211,16 @@ public class ExtractedContent implements AutopsyVisitableItem { this(new TypeNode(type, dsObjId), type); } - private TypeNodeRecord(TypeNode typeNode, BlackboardArtifact.Type type) { - this(typeNode, typeNode::updateDisplayName, Stream.of(type).collect(Collectors.toSet())); + private TypeNodeRecord(UpdatableTypeCountNode typeNode, BlackboardArtifact.Type...types) { + this(typeNode, typeNode::updateDisplayName, types); } - TypeNodeRecord(Node node, Runnable onUpdate, Set applicableTypes) { + TypeNodeRecord(Node node, Runnable onUpdate, BlackboardArtifact.Type...types) { this.node = node; this.onUpdate = onUpdate; - this.applicableTypes = applicableTypes; + this.applicableTypes = Stream.of(types) + .filter(t -> t != null) + .collect(Collectors.toSet()); } Node getNode() { @@ -246,6 +248,7 @@ public class ExtractedContent implements AutopsyVisitableItem { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); + @SuppressWarnings("deprecation") private static final Set IGNORED_TYPES = Sets.newHashSet( // these are shown in other parts of the UI (and different node types) new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE), @@ -260,35 +263,23 @@ public class ExtractedContent implements AutopsyVisitableItem { int typeId = type.getTypeID(); if (TSK_EMAIL_MSG.getTypeID() == typeId) { EmailExtracted.RootNode emailNode = new EmailExtracted(skCase, dsObjId).new RootNode(); - return new TypeNodeRecord( - emailNode, - null, - Sets.newHashSet(new BlackboardArtifact.Type(TSK_EMAIL_MSG))); + return new TypeNodeRecord(emailNode, new BlackboardArtifact.Type(TSK_EMAIL_MSG)); } else if (TSK_ACCOUNT.getTypeID() == typeId) { Accounts.AccountsRootNode accountsNode = new Accounts(skCase, dsObjId).new AccountsRootNode(); - return new TypeNodeRecord( - accountsNode, - null, - Sets.newHashSet(new BlackboardArtifact.Type(TSK_ACCOUNT))); + return new TypeNodeRecord(accountsNode, new BlackboardArtifact.Type(TSK_ACCOUNT)); } else if (TSK_KEYWORD_HIT.getTypeID() == typeId) { KeywordHits.RootNode keywordsNode = new KeywordHits(skCase, dsObjId).new RootNode(); - return new TypeNodeRecord( - keywordsNode, - null, - Sets.newHashSet(new BlackboardArtifact.Type(TSK_KEYWORD_HIT))); + return new TypeNodeRecord(keywordsNode, new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); } else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId || TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) { InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, dsObjId).new RootNode(); - return new TypeNodeRecord( - interestingHitsNode, - null, - Sets.newHashSet( + return new TypeNodeRecord(interestingHitsNode, new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), - new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT))); + new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT)); } else { return new TypeNodeRecord(type, dsObjId); From ff946979a1bf7de7714deef0c1f87659ed2f3754 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 30 Apr 2021 12:49:16 -0400 Subject: [PATCH 13/21] cleanup --- .../autopsy/datamodel/AnalysisResults.java | 4 +- .../autopsy/datamodel/AutopsyItemVisitor.java | 14 --- .../datamodel/AutopsyTreeChildFactory.java | 7 +- .../autopsy/datamodel/DataArtifacts.java | 4 +- .../datamodel/DisplayableItemNodeVisitor.java | 10 -- .../autopsy/datamodel/EmailExtracted.java | 36 ++++--- .../autopsy/datamodel/ExtractedContent.java | 74 ++------------ .../autopsy/datamodel/HashsetHits.java | 7 +- .../autopsy/datamodel/InterestingHits.java | 14 ++- .../autopsy/datamodel/KeywordHits.java | 4 +- .../sleuthkit/autopsy/datamodel/Results.java | 52 ---------- .../autopsy/datamodel/ResultsNode.java | 97 ------------------- .../datamodel/RootContentChildren.java | 13 --- .../autopsy/datamodel/accounts/Accounts.java | 1 - 14 files changed, 44 insertions(+), 293 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/Results.java delete mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java index ed6bd37319..b0f038ba4a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,7 @@ package org.sleuthkit.autopsy.datamodel; /** - * Analysis Results node support + * Analysis Results node support. */ public class AnalysisResults implements AutopsyVisitableItem { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java index ed719a341e..9791d0d5fd 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java @@ -53,8 +53,6 @@ public interface AutopsyItemVisitor { T visit(FileSize.FileSizeFilter fsf); - T visit(ExtractedContent ec); - T visit(KeywordHits kh); T visit(HashsetHits hh); @@ -63,8 +61,6 @@ public interface AutopsyItemVisitor { T visit(InterestingHits ih); - T visit(Results r); - T visit(Tags tagsNodeKey); T visit(Reports reportsItem); @@ -94,11 +90,6 @@ public interface AutopsyItemVisitor { protected abstract T defaultVisit(AutopsyVisitableItem ec); - @Override - public T visit(ExtractedContent ec) { - return defaultVisit(ec); - } - @Override public T visit(FileTypesByExtension sf) { return defaultVisit(sf); @@ -204,11 +195,6 @@ public interface AutopsyItemVisitor { return defaultVisit(personGrouping); } - @Override - public T visit(Results r) { - return defaultVisit(r); - } - @Override public T visit(FileTypes ft) { return defaultVisit(ft); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java index 9ebb44cb40..845591e261 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java @@ -92,7 +92,6 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable keys = new ArrayList<>(Arrays.asList( diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java index e273d8cf12..2c52278459 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,7 @@ package org.sleuthkit.autopsy.datamodel; /** - * Analysis Results node support + * Analysis Results node support. */ public class DataArtifacts implements AutopsyVisitableItem { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 61bc401ee5..4cdb32ff2c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -88,11 +88,6 @@ public interface DisplayableItemNodeVisitor { T visit(RecentFilesFilterNode rffn); - /* - * Extracted Results Area - */ - T visit(ResultsNode rn); - T visit(BlackboardArtifactNode ban); T visit(ExtractedContent.TypeNode atn); @@ -405,11 +400,6 @@ public interface DisplayableItemNodeVisitor { return defaultVisit(dataSourceGroupingNode); } - @Override - public T visit(ResultsNode rn) { - return defaultVisit(rn); - } - @Override public T visit(FileTypesNode ft) { return defaultVisit(ft); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 9e3555d438..d042573e53 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -91,7 +91,7 @@ public class EmailExtracted implements AutopsyVisitableItem { private SleuthkitCase skCase; private final EmailResults emailResults; private final long filteringDSObjId; // 0 if not filtering/grouping by data source - + /** * Constructor * @@ -147,7 +147,7 @@ public class EmailExtracted implements AutopsyVisitableItem { } @SuppressWarnings("deprecation") - public void update() { + public void update() { // clear cache if no case if (skCase == null) { synchronized (accounts) { @@ -159,20 +159,20 @@ public class EmailExtracted implements AutopsyVisitableItem { // get artifact id and path (if present) of all email artifacts int emailArtifactId = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(); int pathAttrId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID(); - - String query = "SELECT \n" + - " art.artifact_id AS artifact_id,\n" + - " (SELECT value_text FROM blackboard_attributes attr\n" + - " WHERE attr.artifact_id = art.artifact_id AND attr.attribute_type_id = " + pathAttrId + "\n" + - " LIMIT 1) AS value_text\n" + - "FROM \n" + - " blackboard_artifacts art\n" + - " WHERE art.artifact_type_id = " + emailArtifactId + "\n" + - ((filteringDSObjId > 0) ? " AND art.data_source_obj_id = " + filteringDSObjId : ""); - + + String query = "SELECT \n" + + " art.artifact_id AS artifact_id,\n" + + " (SELECT value_text FROM blackboard_attributes attr\n" + + " WHERE attr.artifact_id = art.artifact_id AND attr.attribute_type_id = " + pathAttrId + "\n" + + " LIMIT 1) AS value_text\n" + + "FROM \n" + + " blackboard_artifacts art\n" + + " WHERE art.artifact_type_id = " + emailArtifactId + "\n" + + ((filteringDSObjId > 0) ? " AND art.data_source_obj_id = " + filteringDSObjId : ""); + // form hierarchy of account -> folder -> account id Map>> newMapping = new HashMap<>(); - + try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { ResultSet resultSet = dbQuery.getResultSet(); while (resultSet.next()) { @@ -180,7 +180,7 @@ public class EmailExtracted implements AutopsyVisitableItem { Map accountFolderMap = parsePath(resultSet.getString("value_text")); String account = accountFolderMap.get(MAIL_ACCOUNT); String folder = accountFolderMap.get(MAIL_FOLDER); - + Map> folders = newMapping.computeIfAbsent(account, (str) -> new LinkedHashMap<>()); List messages = folders.computeIfAbsent(folder, (str) -> new ArrayList<>()); messages.add(artifactId); @@ -188,18 +188,16 @@ public class EmailExtracted implements AutopsyVisitableItem { } catch (TskCoreException | SQLException ex) { logger.log(Level.WARNING, "Cannot initialize email extraction: ", ex); //NON-NLS } - - + synchronized (accounts) { accounts.clear(); accounts.putAll(newMapping); } - + setChanged(); notifyObservers(); } } - /** * Mail root node grouping all mail accounts, supports account-> folder diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 48519061d0..ac9435cea0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -20,11 +20,9 @@ package org.sleuthkit.autopsy.datamodel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; @@ -66,61 +64,9 @@ import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWO * Parent of the "extracted content" artifacts to be displayed in the tree. * Other artifacts are displayed under other more specific parents. */ -public class ExtractedContent implements AutopsyVisitableItem { +public class ExtractedContent { private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); - public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text"); - private static final Category DEFAULT_CATEGORY = Category.DATA_ARTIFACT; - - private final long filteringDSObjId; // 0 if not filtering/grouping by data source - private SleuthkitCase skCase; // set to null after case has been closed - private final Category category; - - /** - * Constructs extracted content object - * - * @param skCase Case DB - */ - public ExtractedContent(SleuthkitCase skCase) { - this(skCase, 0, DEFAULT_CATEGORY); - } - - public ExtractedContent(SleuthkitCase skCase, Category category) { - this(skCase, 0, DEFAULT_CATEGORY); - } - - /** - * Constructs extracted content object - * - * @param skCase Case DB - * @param objId Object id of the parent datasource - */ - public ExtractedContent(SleuthkitCase skCase, long objId) { - this(skCase, objId, DEFAULT_CATEGORY); - } - - public ExtractedContent(SleuthkitCase skCase, long dataSourceObjId, Category category) { - this.skCase = skCase; - this.filteringDSObjId = dataSourceObjId; - this.category = category; - } - - @Override - public T accept(AutopsyItemVisitor visitor) { - return visitor.visit(this); - } - - public SleuthkitCase getSleuthkitCase() { - return skCase; - } - - long getFilteringDSObjId() { - return filteringDSObjId; - } - - Category getCategory() { - return category; - } @Messages({ "AnalysisResultsNode_name=Analysis Results",}) @@ -177,7 +123,7 @@ public class ExtractedContent implements AutopsyVisitableItem { sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.displayName"), NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.desc"), - NAME)); + super.getDisplayName())); return sheet; } @@ -211,11 +157,11 @@ public class ExtractedContent implements AutopsyVisitableItem { this(new TypeNode(type, dsObjId), type); } - private TypeNodeRecord(UpdatableTypeCountNode typeNode, BlackboardArtifact.Type...types) { + private TypeNodeRecord(UpdatableTypeCountNode typeNode, BlackboardArtifact.Type... types) { this(typeNode, typeNode::updateDisplayName, types); } - TypeNodeRecord(Node node, Runnable onUpdate, BlackboardArtifact.Type...types) { + TypeNodeRecord(Node node, Runnable onUpdate, BlackboardArtifact.Type... types) { this.node = node; this.onUpdate = onUpdate; this.applicableTypes = Stream.of(types) @@ -273,13 +219,13 @@ public class ExtractedContent implements AutopsyVisitableItem { KeywordHits.RootNode keywordsNode = new KeywordHits(skCase, dsObjId).new RootNode(); return new TypeNodeRecord(keywordsNode, new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); - } else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId || - TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) { - + } else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId + || TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) { + InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, dsObjId).new RootNode(); - return new TypeNodeRecord(interestingHitsNode, - new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), - new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT)); + return new TypeNodeRecord(interestingHitsNode, + new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), + new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT)); } else { return new TypeNodeRecord(type, dsObjId); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index c063081699..7a04d3cf33 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -48,14 +48,12 @@ import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; - /** * Hash set hits node support. Inner classes have all of the nodes in the tree. */ @@ -70,7 +68,6 @@ public class HashsetHits implements AutopsyVisitableItem { private final HashsetResults hashsetResults; private final long filteringDSObjId; // 0 if not filtering/grouping by data source - /** * Constructor * @@ -176,12 +173,12 @@ public class HashsetHits implements AutopsyVisitableItem { public class RootNode extends UpdatableTypeCountNode { public RootNode() { - super(Children.create(new HashsetNameFactory(), true), + super(Children.create(new HashsetNameFactory(), true), Lookups.singleton(DISPLAY_NAME), DISPLAY_NAME, filteringDSObjId, new BlackboardArtifact.Type(TSK_HASHSET_HIT)); - + super.setName(HASHSET_HITS); super.setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 93b6480c26..27d08f3781 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -51,8 +51,6 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; - public class InterestingHits implements AutopsyVisitableItem { @@ -171,7 +169,7 @@ public class InterestingHits implements AutopsyVisitableItem { public class RootNode extends UpdatableTypeCountNode { public RootNode() { - super(Children.create(new SetNameFactory(), true), + super(Children.create(new SetNameFactory(), true), Lookups.singleton(DISPLAY_NAME), DISPLAY_NAME, filteringDSObjId, @@ -407,8 +405,8 @@ public class InterestingHits implements AutopsyVisitableItem { this.typeName = typeName; this.setName = setName; /** - * We use the combination of setName and typeName as the name of - * the node to ensure that nodes have a unique name. This comes into + * We use the combination of setName and typeName as the name of the + * node to ensure that nodes have a unique name. This comes into * play when associating paging state with the node. */ super.setName(setName + "_" + typeName); @@ -469,9 +467,9 @@ public class InterestingHits implements AutopsyVisitableItem { private HitFactory(String setName, String typeName) { /** - * The node name passed to the parent constructor must be the - * same as the name set in the InterestingItemTypeNode constructor, - * i.e. setName underscore typeName + * The node name passed to the parent constructor must be the same + * as the name set in the InterestingItemTypeNode constructor, i.e. + * setName underscore typeName */ super(setName + "_" + typeName); this.setName = setName; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 82ea4263b1..6713a6722b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -105,7 +105,7 @@ public class KeywordHits implements AutopsyVisitableItem { static private boolean isOnlyDefaultInstance(List instances) { return (instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME)); } - + /** * Constructor * @@ -380,7 +380,7 @@ public class KeywordHits implements AutopsyVisitableItem { public class RootNode extends UpdatableTypeCountNode { public RootNode() { - super(Children.create(new ListFactory(), true), + super(Children.create(new ListFactory(), true), Lookups.singleton(KEYWORD_HITS), KEYWORD_HITS, filteringDSObjId, diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Results.java b/Core/src/org/sleuthkit/autopsy/datamodel/Results.java deleted file mode 100644 index b2d9f4799b..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Results.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.datamodel; - -import org.sleuthkit.datamodel.SleuthkitCase; - -/** - * Results node support - */ -public class Results implements AutopsyVisitableItem { - - private SleuthkitCase skCase; - private final long datasourceObjId; - - public Results(SleuthkitCase skCase) { - this(skCase, 0); - } - - public Results(SleuthkitCase skCase, long dsObjId) { - this.skCase = skCase; - this.datasourceObjId = dsObjId; - } - - @Override - public T accept(AutopsyItemVisitor visitor) { - return visitor.visit(this); - } - - public SleuthkitCase getSleuthkitCase() { - return skCase; - } - - long filteringDataSourceObjId() { - return datasourceObjId; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java deleted file mode 100644 index e9b2eba696..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2018 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.datamodel; - -import org.sleuthkit.autopsy.datamodel.accounts.Accounts; -import java.util.Arrays; -import org.openide.nodes.Sheet; -import org.openide.util.NbBundle; -import org.openide.util.lookup.Lookups; -import org.sleuthkit.datamodel.SleuthkitCase; - -/** - * Node for the results section of the tree. - */ -public class ResultsNode extends DisplayableItemNode { - - @NbBundle.Messages("ResultsNode.name.text=Results") - private static final String NAME = Bundle.ResultsNode_name_text(); - - public static String getNameIdentifier() { - return NAME; - } - - public ResultsNode(SleuthkitCase sleuthkitCase) { - this(sleuthkitCase, 0); - } - - public ResultsNode(SleuthkitCase sleuthkitCase, long dsObjId) { - super( - - new RootContentChildren(Arrays.asList( - new ExtractedContent(sleuthkitCase, dsObjId ), - new KeywordHits(sleuthkitCase, dsObjId), - new HashsetHits(sleuthkitCase, dsObjId), - new EmailExtracted(sleuthkitCase, dsObjId), - new InterestingHits(sleuthkitCase, dsObjId ), - new Accounts(sleuthkitCase, dsObjId), - new OsAccounts(sleuthkitCase, dsObjId)) - ), - Lookups.singleton(NAME)); - setName(NAME); - setDisplayName(NAME); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png"); //NON-NLS - } - - @Override - public boolean isLeafTypeNode() { - return false; - } - - @Override - public T accept(DisplayableItemNodeVisitor visitor) { - return visitor.visit(this); - } - - @Override - @NbBundle.Messages({ - "ResultsNode.createSheet.name.name=Name", - "ResultsNode.createSheet.name.displayName=Name", - "ResultsNode.createSheet.name.desc=no description"}) - protected Sheet createSheet() { - Sheet sheet = super.createSheet(); - Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); - if (sheetSet == null) { - sheetSet = Sheet.createPropertiesSet(); - sheet.put(sheetSet); - } - - sheetSet.put(new NodeProperty<>(Bundle.ResultsNode_createSheet_name_name(), - Bundle.ResultsNode_createSheet_name_displayName(), - Bundle.ResultsNode_createSheet_name_desc(), - NAME - )); - return sheet; - } - - @Override - public String getItemType() { - return getClass().getName(); - } -} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index 192a966490..ed1af75078 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -25,8 +25,6 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardArtifact.Category; import org.sleuthkit.datamodel.SleuthkitVisitableItem; /** @@ -84,12 +82,6 @@ public class RootContentChildren extends Children.Keys { * Set Hits, etc.). */ static class CreateAutopsyNodeVisitor extends AutopsyItemVisitor.Default { - - @Override - public ExtractedContent.RootNode visit(ExtractedContent ec) { - return new ExtractedContent.DataArtifactsNode(0); - } - @Override public AbstractNode visit(FileTypesByExtension sf) { return sf.new FileTypesByExtNode(sf.getSleuthkitCase(), null); @@ -150,11 +142,6 @@ public class RootContentChildren extends Children.Keys { return new ViewsNode(v.getSleuthkitCase(), v.filteringDataSourceObjId()); } - @Override - public AbstractNode visit(Results results) { - return new ResultsNode(results.getSleuthkitCase(), results.filteringDataSourceObjId()); - } - @Override public AbstractNode visit(FileTypes ft) { return ft.new FileTypesNode(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index 2eb2c6e021..e8ec4f42bc 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -69,7 +69,6 @@ import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; -import org.sleuthkit.autopsy.datamodel.ExtractedContent; import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; From 55abf89064fbc2ca3d26dab93fcc45fd7e93c09d Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 30 Apr 2021 14:54:32 -0400 Subject: [PATCH 14/21] cleanup, refactoring, and commenting --- .../{ExtractedContent.java => Artifacts.java} | 184 +++++++++++------- .../datamodel/DisplayableItemNodeVisitor.java | 8 +- .../autopsy/datamodel/EmailExtracted.java | 4 +- .../autopsy/datamodel/HashsetHits.java | 4 +- .../autopsy/datamodel/InterestingHits.java | 4 +- .../autopsy/datamodel/KeywordHits.java | 4 +- .../datamodel/RootContentChildren.java | 4 +- .../autopsy/datamodel/accounts/Accounts.java | 4 +- .../DirectoryTreeTopComponent.java | 4 +- 9 files changed, 137 insertions(+), 83 deletions(-) rename Core/src/org/sleuthkit/autopsy/datamodel/{ExtractedContent.java => Artifacts.java} (81%) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java similarity index 81% rename from Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java rename to Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index ac9435cea0..0becc89c10 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; @@ -61,40 +62,71 @@ import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTER import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; /** - * Parent of the "extracted content" artifacts to be displayed in the tree. - * Other artifacts are displayed under other more specific parents. + * Classes for creating nodes for BlackboardArtifacts. */ -public class ExtractedContent { +public class Artifacts { - private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); + private static final Set INGEST_JOB_EVENTS_OF_INTEREST + = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); + /** + * Parent node of all analysis results. + */ @Messages({ "AnalysisResultsNode_name=Analysis Results",}) - static class AnalysisResultsNode extends RootNode { + static class AnalysisResultsNode extends BaseArtifactNode { + /** + * Main constructor. + * + * @param filteringDSObjId The data source object id for which results + * should be filtered. If no filtering should + * occur, this number should be <= 0. + */ AnalysisResultsNode(long filteringDSObjId) { - super(Children.create(new AnalysisResultsTypeFactory(filteringDSObjId), true), + super(Children.create(new TypeFactory(Category.ANALYSIS_RESULT, filteringDSObjId), true), "org/sleuthkit/autopsy/images/analysis_result.png", Bundle.AnalysisResultsNode_name(), Bundle.AnalysisResultsNode_name()); } } + /** + * Parent node of all data artifacts. + */ @Messages({ "DataArtifactsNode_name=Data Artifacts",}) - static class DataArtifactsNode extends RootNode { + static class DataArtifactsNode extends BaseArtifactNode { + /** + * Main constructor. + * + * @param filteringDSObjId The data source object id for which results + * should be filtered. If no filtering should + * occur, this number should be <= 0. + */ DataArtifactsNode(long filteringDSObjId) { - super(Children.create(new DataArtifactsTypeFactory(filteringDSObjId), true), + super(Children.create(new TypeFactory(Category.DATA_ARTIFACT, filteringDSObjId), true), "org/sleuthkit/autopsy/images/extracted_content.png", Bundle.DataArtifactsNode_name(), Bundle.DataArtifactsNode_name()); } } - static class RootNode extends DisplayableItemNode { + /** + * Base class for a parent node of artifacts. + */ + private static class BaseArtifactNode extends DisplayableItemNode { - RootNode(Children children, String icon, String name, String displayName) { + /** + * Main constructor. + * + * @param children The children of the node. + * @param icon The icon for the node. + * @param name The name identifier of the node. + * @param displayName The display name for the node. + */ + BaseArtifactNode(Children children, String icon, String name, String displayName) { super(children, Lookups.singleton(name)); super.setName(name); super.setDisplayName(displayName); @@ -133,64 +165,87 @@ public class ExtractedContent { } } - private static class AnalysisResultsTypeFactory extends TypeFactory { + /** + * A key to be used with the type factory. + */ + private static class TypeNodeKey { - AnalysisResultsTypeFactory(long filteringDSObjId) { - super(Category.ANALYSIS_RESULT, filteringDSObjId); - } - } - - private static class DataArtifactsTypeFactory extends TypeFactory { - - DataArtifactsTypeFactory(long filteringDSObjId) { - super(Category.DATA_ARTIFACT, filteringDSObjId); - } - } - - private static class TypeNodeRecord { - - private final Node node; - private final Runnable onUpdate; + private final UpdatableCountTypeNode node; private final Set applicableTypes; - TypeNodeRecord(BlackboardArtifact.Type type, long dsObjId) { + /** + * Constructor generating a generic TypeNode for a given artifact type. + * + * @param type The type for the key. + * @param dsObjId The data source object id if filtering should occur. + * If no filtering should occur, this number should be <= + * 0. + */ + TypeNodeKey(BlackboardArtifact.Type type, long dsObjId) { this(new TypeNode(type, dsObjId), type); } - private TypeNodeRecord(UpdatableTypeCountNode typeNode, BlackboardArtifact.Type... types) { - this(typeNode, typeNode::updateDisplayName, types); - } - - TypeNodeRecord(Node node, Runnable onUpdate, BlackboardArtifact.Type... types) { - this.node = node; - this.onUpdate = onUpdate; + /** + * Constructor for any UpdatableCountTypeNode. + * + * @param typeNode The UpdatableCountTypeNode. + * @param types The blackboard artifact types corresponding to this + * node. + */ + TypeNodeKey(UpdatableCountTypeNode typeNode, BlackboardArtifact.Type... types) { + this.node = typeNode; this.applicableTypes = Stream.of(types) .filter(t -> t != null) .collect(Collectors.toSet()); } - Node getNode() { + /** + * Returns the node associated with this key. + * @return The node associated with this key. + */ + UpdatableCountTypeNode getNode() { return node; } - void update() { - if (onUpdate != null) { - onUpdate.run(); - } - } - + /** + * Returns the blackboard artifact types associated with this key. + * @return The blackboard artifact types associated with this key. + */ Set getApplicableTypes() { return applicableTypes; } + @Override + public int hashCode() { + int hash = 3; + hash = 61 * hash + Objects.hashCode(this.applicableTypes); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final TypeNodeKey other = (TypeNodeKey) obj; + if (!Objects.equals(this.applicableTypes, other.applicableTypes)) { + return false; + } + return true; + } + } /** - * Creates the children for the ExtractedContent area of the results tree. - * This area has all of the blackboard artifacts that are not displayed in a - * more specific form elsewhere in the tree. + * */ - private static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { + private static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); @@ -205,35 +260,36 @@ public class ExtractedContent { new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) ); - private static TypeNodeRecord getRecord(BlackboardArtifact.Type type, SleuthkitCase skCase, long dsObjId) { + + private static TypeNodeKey getRecord(BlackboardArtifact.Type type, SleuthkitCase skCase, long dsObjId) { int typeId = type.getTypeID(); if (TSK_EMAIL_MSG.getTypeID() == typeId) { EmailExtracted.RootNode emailNode = new EmailExtracted(skCase, dsObjId).new RootNode(); - return new TypeNodeRecord(emailNode, new BlackboardArtifact.Type(TSK_EMAIL_MSG)); + return new TypeNodeKey(emailNode, new BlackboardArtifact.Type(TSK_EMAIL_MSG)); } else if (TSK_ACCOUNT.getTypeID() == typeId) { Accounts.AccountsRootNode accountsNode = new Accounts(skCase, dsObjId).new AccountsRootNode(); - return new TypeNodeRecord(accountsNode, new BlackboardArtifact.Type(TSK_ACCOUNT)); + return new TypeNodeKey(accountsNode, new BlackboardArtifact.Type(TSK_ACCOUNT)); } else if (TSK_KEYWORD_HIT.getTypeID() == typeId) { KeywordHits.RootNode keywordsNode = new KeywordHits(skCase, dsObjId).new RootNode(); - return new TypeNodeRecord(keywordsNode, new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); + return new TypeNodeKey(keywordsNode, new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); } else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId || TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) { InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, dsObjId).new RootNode(); - return new TypeNodeRecord(interestingHitsNode, + return new TypeNodeKey(interestingHitsNode, new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT)); } else { - return new TypeNodeRecord(type, dsObjId); + return new TypeNodeKey(type, dsObjId); } } // maps the artifact type to its child node - private final HashMap typeNodeMap = new HashMap<>(); + private final HashMap typeNodeMap = new HashMap<>(); private final long filteringDSObjId; /** @@ -292,7 +348,7 @@ public class ExtractedContent { } @Override - protected boolean createKeys(List list) { + protected boolean createKeys(List list) { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); @@ -300,15 +356,15 @@ public class ExtractedContent { ? skCase.getBlackboard().getArtifactTypesInUse(this.filteringDSObjId) : skCase.getArtifactTypesInUse(); - List allKeysSorted = types.stream() + List allKeysSorted = types.stream() .filter(tp -> category.equals(tp.getCategory()) && !IGNORED_TYPES.contains(tp)) .map(tp -> { if (typeNodeMap.containsKey(tp)) { - TypeNodeRecord record = typeNodeMap.get(tp); - record.update(); + TypeNodeKey record = typeNodeMap.get(tp); + record.getNode().updateDisplayName(); return record; } else { - TypeNodeRecord newRecord = getRecord(tp, skCase, filteringDSObjId); + TypeNodeKey newRecord = getRecord(tp, skCase, filteringDSObjId); for (BlackboardArtifact.Type recordType : newRecord.getApplicableTypes()) { typeNodeMap.put(recordType, newRecord); } @@ -324,8 +380,6 @@ public class ExtractedContent { }) .collect(Collectors.toList()); - allKeysSorted.forEach(record -> record.update()); - list.addAll(allKeysSorted); } catch (NoCurrentCaseException ex) { @@ -337,7 +391,7 @@ public class ExtractedContent { } @Override - protected Node createNodeForKey(TypeNodeRecord key) { + protected Node createNodeForKey(TypeNodeKey key) { return key.getNode(); } @@ -377,9 +431,9 @@ public class ExtractedContent { } } - public static abstract class UpdatableTypeCountNode extends DisplayableItemNode { + public static abstract class UpdatableCountTypeNode extends DisplayableItemNode { - private static final Logger logger = Logger.getLogger(UpdatableTypeCountNode.class.getName()); + private static final Logger logger = Logger.getLogger(UpdatableCountTypeNode.class.getName()); private final Set types; private final long filteringDSObjId; @@ -397,7 +451,7 @@ public class ExtractedContent { * @param children The Children object for the node. * @param lookup The Lookup object for the node. */ - public UpdatableTypeCountNode(Children children, Lookup lookup, String baseName, long filteringDSObjId, BlackboardArtifact.Type... types) { + public UpdatableCountTypeNode(Children children, Lookup lookup, String baseName, long filteringDSObjId, BlackboardArtifact.Type... types) { super(children, lookup); this.types = Stream.of(types).collect(Collectors.toSet()); this.filteringDSObjId = filteringDSObjId; @@ -438,7 +492,7 @@ public class ExtractedContent { * the artifacts of a given type. Its children will be * BlackboardArtifactNode objects. */ - public static class TypeNode extends UpdatableTypeCountNode { + public static class TypeNode extends UpdatableCountTypeNode { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 4cdb32ff2c..715f9aecd9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -90,9 +90,9 @@ public interface DisplayableItemNodeVisitor { T visit(BlackboardArtifactNode ban); - T visit(ExtractedContent.TypeNode atn); + T visit(Artifacts.TypeNode atn); - T visit(ExtractedContent.RootNode ecn); + T visit(Artifacts.BaseArtifactNode ecn); T visit(KeywordHits.RootNode khrn); @@ -296,12 +296,12 @@ public interface DisplayableItemNodeVisitor { } @Override - public T visit(ExtractedContent.TypeNode atn) { + public T visit(Artifacts.TypeNode atn) { return defaultVisit(atn); } @Override - public T visit(ExtractedContent.RootNode ecn) { + public T visit(Artifacts.BaseArtifactNode ecn) { return defaultVisit(ecn); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index d042573e53..06ed408976 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -49,7 +49,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; +import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; /** * Support for TSK_EMAIL_MSG nodes and displaying emails in the directory tree. @@ -203,7 +203,7 @@ public class EmailExtracted implements AutopsyVisitableItem { * Mail root node grouping all mail accounts, supports account-> folder * structure */ - public class RootNode extends UpdatableTypeCountNode { + public class RootNode extends UpdatableCountTypeNode { public RootNode() { super(Children.create(new AccountFactory(), true), diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index 7a04d3cf33..150a52e3da 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -52,7 +52,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; +import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; /** * Hash set hits node support. Inner classes have all of the nodes in the tree. @@ -170,7 +170,7 @@ public class HashsetHits implements AutopsyVisitableItem { /** * Top-level node for all hash sets */ - public class RootNode extends UpdatableTypeCountNode { + public class RootNode extends UpdatableCountTypeNode { public RootNode() { super(Children.create(new HashsetNameFactory(), true), diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 27d08f3781..28bfb3e8dc 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -50,7 +50,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; +import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; public class InterestingHits implements AutopsyVisitableItem { @@ -166,7 +166,7 @@ public class InterestingHits implements AutopsyVisitableItem { /** * Node for the interesting items */ - public class RootNode extends UpdatableTypeCountNode { + public class RootNode extends UpdatableCountTypeNode { public RootNode() { super(Children.create(new SetNameFactory(), true), diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 6713a6722b..845c87d5ea 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -56,7 +56,7 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; -import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; +import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; /** * Keyword hits node support @@ -377,7 +377,7 @@ public class KeywordHits implements AutopsyVisitableItem { } // Created by CreateAutopsyNodeVisitor - public class RootNode extends UpdatableTypeCountNode { + public class RootNode extends UpdatableCountTypeNode { public RootNode() { super(Children.create(new ListFactory(), true), diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index ed1af75078..acb33129dd 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -196,13 +196,13 @@ public class RootContentChildren extends Children.Keys { @Override public AbstractNode visit(AnalysisResults analysisResults) { - return new ExtractedContent.AnalysisResultsNode( + return new Artifacts.AnalysisResultsNode( analysisResults.getFilteringDataSourceObjId()); } @Override public AbstractNode visit(DataArtifacts dataArtifacts) { - return new ExtractedContent.DataArtifactsNode( + return new Artifacts.DataArtifactsNode( dataArtifacts.getFilteringDataSourceObjId()); } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index e8ec4f42bc..aa6a53f8ec 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -69,7 +69,7 @@ import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; -import org.sleuthkit.autopsy.datamodel.ExtractedContent.UpdatableTypeCountNode; +import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -235,7 +235,7 @@ final public class Accounts implements AutopsyVisitableItem { * Top-level node for the accounts tree */ @NbBundle.Messages({"Accounts.RootNode.displayName=Accounts"}) - final public class AccountsRootNode extends UpdatableTypeCountNode { + final public class AccountsRootNode extends UpdatableCountTypeNode { public AccountsRootNode() { super(Children.create(new AccountTypeFactory(), true), diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index d2cd291de0..90245dfe4e 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -78,7 +78,7 @@ import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.EmailExtracted; import org.sleuthkit.autopsy.datamodel.EmptyNode; -import org.sleuthkit.autopsy.datamodel.ExtractedContent; +import org.sleuthkit.autopsy.datamodel.Artifacts; import org.sleuthkit.autopsy.datamodel.FileTypesByMimeType; import org.sleuthkit.autopsy.datamodel.InterestingHits; import org.sleuthkit.autopsy.datamodel.KeywordHits; @@ -1391,7 +1391,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS } } else { - Node extractedContent = resultsChilds.findChild(ExtractedContent.NAME); + Node extractedContent = resultsChilds.findChild(Artifacts.NAME); Children extractedChilds = extractedContent.getChildren(); if (extractedChilds == null) { return; From b566201f9123d3effcd9311acb6c3f16fa60d290 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 3 May 2021 08:37:10 -0400 Subject: [PATCH 15/21] commenting --- .../autopsy/datamodel/Artifacts.java | 103 +++++++++++++----- 1 file changed, 75 insertions(+), 28 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index 0becc89c10..fcea81513d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.logging.Level; @@ -81,7 +82,8 @@ public class Artifacts { * * @param filteringDSObjId The data source object id for which results * should be filtered. If no filtering should - * occur, this number should be <= 0. + * occur, this number should be less than or + * equal to 0. */ AnalysisResultsNode(long filteringDSObjId) { super(Children.create(new TypeFactory(Category.ANALYSIS_RESULT, filteringDSObjId), true), @@ -103,7 +105,8 @@ public class Artifacts { * * @param filteringDSObjId The data source object id for which results * should be filtered. If no filtering should - * occur, this number should be <= 0. + * occur, this number should be less than or + * equal to 0. */ DataArtifactsNode(long filteringDSObjId) { super(Children.create(new TypeFactory(Category.DATA_ARTIFACT, filteringDSObjId), true), @@ -178,8 +181,8 @@ public class Artifacts { * * @param type The type for the key. * @param dsObjId The data source object id if filtering should occur. - * If no filtering should occur, this number should be <= - * 0. + * If no filtering should occur, this number should be + * less than or equal to 0. */ TypeNodeKey(BlackboardArtifact.Type type, long dsObjId) { this(new TypeNode(type, dsObjId), type); @@ -201,6 +204,7 @@ public class Artifacts { /** * Returns the node associated with this key. + * * @return The node associated with this key. */ UpdatableCountTypeNode getNode() { @@ -209,6 +213,7 @@ public class Artifacts { /** * Returns the blackboard artifact types associated with this key. + * * @return The blackboard artifact types associated with this key. */ Set getApplicableTypes() { @@ -243,12 +248,16 @@ public class Artifacts { } /** - * + * Factory for showing a list of artifact types (i.e. all the data artifact + * types). */ private static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); + /** + * Types that should not be shown in the tree. + */ @SuppressWarnings("deprecation") private static final Set IGNORED_TYPES = Sets.newHashSet( // these are shown in other parts of the UI (and different node types) @@ -260,8 +269,18 @@ public class Artifacts { new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) ); - - private static TypeNodeKey getRecord(BlackboardArtifact.Type type, SleuthkitCase skCase, long dsObjId) { + /** + * Returns a Children key to be use for a particular artifact type. + * + * @param type The artifact type. + * @param skCase The relevant Sleuthkit case in order to create the + * node. + * @param dsObjId The data source object id to use for filtering. If id + * is less than or equal to 0, no filtering will occur. + * + * @return The generated key. + */ + private static TypeNodeKey getTypeKey(BlackboardArtifact.Type type, SleuthkitCase skCase, long dsObjId) { int typeId = type.getTypeID(); if (TSK_EMAIL_MSG.getTypeID() == typeId) { EmailExtracted.RootNode emailNode = new EmailExtracted(skCase, dsObjId).new RootNode(); @@ -289,7 +308,7 @@ public class Artifacts { } // maps the artifact type to its child node - private final HashMap typeNodeMap = new HashMap<>(); + private final Map typeNodeMap = new HashMap<>(); private final long filteringDSObjId; /** @@ -300,7 +319,14 @@ public class Artifacts { private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); private final Category category; - @SuppressWarnings("deprecation") + /** + * Main constructor. + * + * @param category The category of types to be displayed. + * @param filteringDSObjId The data source object id to use for + * filtering. If id is less than or equal to 0, + * no filtering will occur. + */ TypeFactory(Category category, long filteringDSObjId) { super(); this.filteringDSObjId = filteringDSObjId; @@ -350,29 +376,36 @@ public class Artifacts { @Override protected boolean createKeys(List list) { try { - + // Get all types in use SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); List types = (this.filteringDSObjId > 0) ? skCase.getBlackboard().getArtifactTypesInUse(this.filteringDSObjId) : skCase.getArtifactTypesInUse(); List allKeysSorted = types.stream() + // filter types by category and ensure they are not in the list of ignored types .filter(tp -> category.equals(tp.getCategory()) && !IGNORED_TYPES.contains(tp)) .map(tp -> { + // if typeNodeMap already contains key, update the relevant node and return the node if (typeNodeMap.containsKey(tp)) { - TypeNodeKey record = typeNodeMap.get(tp); - record.getNode().updateDisplayName(); - return record; + TypeNodeKey typeKey = typeNodeMap.get(tp); + typeKey.getNode().updateDisplayName(); + return typeKey; } else { - TypeNodeKey newRecord = getRecord(tp, skCase, filteringDSObjId); - for (BlackboardArtifact.Type recordType : newRecord.getApplicableTypes()) { - typeNodeMap.put(recordType, newRecord); + // if key is not in map, create the type key and add to map + TypeNodeKey newTypeKey = getTypeKey(tp, skCase, filteringDSObjId); + for (BlackboardArtifact.Type recordType : newTypeKey.getApplicableTypes()) { + typeNodeMap.put(recordType, newTypeKey); } - return newRecord; + return newTypeKey; } }) + // ensure record is returned .filter(record -> record != null) + // there are potentially multiple types that apply to the same node (i.e. Interesting Files / Artifacts) + // ensure the keys are distinct .distinct() + // sort by display name .sorted((a, b) -> { String aSafe = (a.getNode() == null || a.getNode().getDisplayName() == null) ? "" : a.getNode().getDisplayName(); String bSafe = (b.getNode() == null || b.getNode().getDisplayName() == null) ? "" : b.getNode().getDisplayName(); @@ -431,6 +464,10 @@ public class Artifacts { } } + /** + * Abstract class for type(s) nodes. This class allows for displaying a + * count artifacts with the type(s) associated with this node. + */ public static abstract class UpdatableCountTypeNode extends DisplayableItemNode { private static final Logger logger = Logger.getLogger(UpdatableCountTypeNode.class.getName()); @@ -441,17 +478,20 @@ public class Artifacts { private final String baseName; /** - * Constructs a node that is eligible for display in the tree view or - * results view. Capabilitites include accepting a - * DisplayableItemNodeVisitor, indicating whether or not the node is a - * leaf node, providing an item type string suitable for use as a key, - * and storing information about a child node that is to be selected if - * the node is selected in the tree view. + * Main constructor. * - * @param children The Children object for the node. - * @param lookup The Lookup object for the node. + * @param children The Children to associated with this node. + * @param lookup The Lookup to use with this name. + * @param baseName The display name. The Node.displayName will + * be of format "[baseName] ([count])". + * @param filteringDSObjId The data source object id to use for + * filtering. If id is less than or equal to 0, + * no filtering will occur. + * @param types The types associated with this type node. */ - public UpdatableCountTypeNode(Children children, Lookup lookup, String baseName, long filteringDSObjId, BlackboardArtifact.Type... types) { + public UpdatableCountTypeNode(Children children, Lookup lookup, String baseName, + long filteringDSObjId, BlackboardArtifact.Type... types) { + super(children, lookup); this.types = Stream.of(types).collect(Collectors.toSet()); this.filteringDSObjId = filteringDSObjId; @@ -459,10 +499,19 @@ public class Artifacts { updateDisplayName(); } + /** + * Returns the count of artifacts associated with these type(s). + * + * @return The count of artifacts associated with these type(s). + */ protected long getChildCount() { return this.childCount; } + /** + * When this method is called, the count to be displayed will be + * updated. + */ void updateDisplayName() { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); @@ -494,8 +543,6 @@ public class Artifacts { */ public static class TypeNode extends UpdatableCountTypeNode { - private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); - private final BlackboardArtifact.Type type; TypeNode(BlackboardArtifact.Type type, long filteringDSObjId) { From 8cd287e3ddfc8b4cf0d363cf7725fdd8b500815c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 3 May 2021 09:07:05 -0400 Subject: [PATCH 16/21] commenting --- .../autopsy/datamodel/Artifacts.java | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index fcea81513d..bdb88dfbf2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -536,15 +536,23 @@ public class Artifacts { } /** - * Node encapsulating blackboard artifact type. This is used on the - * left-hand navigation side of the Autopsy UI as the parent node for all of - * the artifacts of a given type. Its children will be + * Default node encapsulating a blackboard artifact type. This is used on + * the left-hand navigation side of the Autopsy UI as the parent node for + * all of the artifacts of a given type. Its children will be * BlackboardArtifactNode objects. */ public static class TypeNode extends UpdatableCountTypeNode { private final BlackboardArtifact.Type type; + /** + * Main constructor. + * + * @param type The blackboard artifact type for this node. + * @param filteringDSObjId The data source object id to use for + * filtering. If id is less than or equal to 0, + * no filtering will occur. + */ TypeNode(BlackboardArtifact.Type type, long filteringDSObjId) { super(Children.create(new ArtifactFactory(type, filteringDSObjId), true), Lookups.singleton(type.getDisplayName()), @@ -612,6 +620,14 @@ public class Artifacts { private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); private final long filteringDSObjId; + /** + * Main constructor. + * + * @param type The blackboard artifact type for this node. + * @param filteringDSObjId The data source object id to use for + * filtering. If id is less than or equal to 0, + * no filtering will occur. + */ ArtifactFactory(BlackboardArtifact.Type type, long filteringDSObjId) { super(type.getTypeName()); this.type = type; From 2c2a731341f0755515d2a04fa415d6496e142811 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 3 May 2021 13:01:21 -0400 Subject: [PATCH 17/21] worked through changes in tree for DirectoryTreeTopComponent --- .../autopsy/datamodel/AnalysisResults.java | 36 + .../autopsy/datamodel/Artifacts.java | 53 +- .../autopsy/datamodel/DataArtifacts.java | 36 + .../datamodel/RootContentChildren.java | 5 +- .../DirectoryTreeTopComponent.java | 642 +++++++++++------- 5 files changed, 470 insertions(+), 302 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java index b0f038ba4a..fc51d97cc9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResults.java @@ -18,11 +18,47 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.openide.nodes.Children; +import org.openide.util.NbBundle; +import org.sleuthkit.datamodel.BlackboardArtifact; + /** * Analysis Results node support. */ +@NbBundle.Messages({ + "AnalysisResults_name=Analysis Results",}) public class AnalysisResults implements AutopsyVisitableItem { + /** + * Returns the name of this node that is the key in the children object. + * + * @return The name of this node that is the key in the children object. + */ + public static String getName() { + return Bundle.AnalysisResults_name(); + } + + /** + * Parent node of all analysis results. + */ + static class RootNode extends Artifacts.BaseArtifactNode { + + /** + * Main constructor. + * + * @param filteringDSObjId The data source object id for which results + * should be filtered. If no filtering should + * occur, this number should be less than or + * equal to 0. + */ + RootNode(long filteringDSObjId) { + super(Children.create(new Artifacts.TypeFactory(BlackboardArtifact.Category.ANALYSIS_RESULT, filteringDSObjId), true), + "org/sleuthkit/autopsy/images/analysis_result.png", + AnalysisResults.getName(), + AnalysisResults.getName()); + } + } + private final long datasourceObjId; /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index bdb88dfbf2..2bce9cdc95 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -70,56 +70,11 @@ public class Artifacts { private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); - /** - * Parent node of all analysis results. - */ - @Messages({ - "AnalysisResultsNode_name=Analysis Results",}) - static class AnalysisResultsNode extends BaseArtifactNode { - - /** - * Main constructor. - * - * @param filteringDSObjId The data source object id for which results - * should be filtered. If no filtering should - * occur, this number should be less than or - * equal to 0. - */ - AnalysisResultsNode(long filteringDSObjId) { - super(Children.create(new TypeFactory(Category.ANALYSIS_RESULT, filteringDSObjId), true), - "org/sleuthkit/autopsy/images/analysis_result.png", - Bundle.AnalysisResultsNode_name(), - Bundle.AnalysisResultsNode_name()); - } - } - - /** - * Parent node of all data artifacts. - */ - @Messages({ - "DataArtifactsNode_name=Data Artifacts",}) - static class DataArtifactsNode extends BaseArtifactNode { - - /** - * Main constructor. - * - * @param filteringDSObjId The data source object id for which results - * should be filtered. If no filtering should - * occur, this number should be less than or - * equal to 0. - */ - DataArtifactsNode(long filteringDSObjId) { - super(Children.create(new TypeFactory(Category.DATA_ARTIFACT, filteringDSObjId), true), - "org/sleuthkit/autopsy/images/extracted_content.png", - Bundle.DataArtifactsNode_name(), - Bundle.DataArtifactsNode_name()); - } - } - + /** * Base class for a parent node of artifacts. */ - private static class BaseArtifactNode extends DisplayableItemNode { + static class BaseArtifactNode extends DisplayableItemNode { /** * Main constructor. @@ -251,7 +206,7 @@ public class Artifacts { * Factory for showing a list of artifact types (i.e. all the data artifact * types). */ - private static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { + static class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { private static final Logger logger = Logger.getLogger(TypeNode.class.getName()); @@ -541,7 +496,7 @@ public class Artifacts { * all of the artifacts of a given type. Its children will be * BlackboardArtifactNode objects. */ - public static class TypeNode extends UpdatableCountTypeNode { + static class TypeNode extends UpdatableCountTypeNode { private final BlackboardArtifact.Type type; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java index 2c52278459..54e9e5da0a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataArtifacts.java @@ -18,11 +18,47 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.openide.nodes.Children; +import org.openide.util.NbBundle; +import org.sleuthkit.datamodel.BlackboardArtifact; + /** * Analysis Results node support. */ +@NbBundle.Messages({ + "DataArtifacts_name=Data Artifacts",}) public class DataArtifacts implements AutopsyVisitableItem { + /** + * Returns the name of this node that is the key in the children object. + * + * @return The name of this node that is the key in the children object. + */ + public static String getName() { + return Bundle.DataArtifacts_name(); + } + + /** + * Parent node of all data artifacts. + */ + static class RootNode extends Artifacts.BaseArtifactNode { + + /** + * Main constructor. + * + * @param filteringDSObjId The data source object id for which results + * should be filtered. If no filtering should + * occur, this number should be less than or + * equal to 0. + */ + RootNode(long filteringDSObjId) { + super(Children.create(new Artifacts.TypeFactory(BlackboardArtifact.Category.DATA_ARTIFACT, filteringDSObjId), true), + "org/sleuthkit/autopsy/images/extracted_content.png", + DataArtifacts.getName(), + DataArtifacts.getName()); + } + } + private final long datasourceObjId; /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index acb33129dd..24d077b5fa 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -82,6 +82,7 @@ public class RootContentChildren extends Children.Keys { * Set Hits, etc.). */ static class CreateAutopsyNodeVisitor extends AutopsyItemVisitor.Default { + @Override public AbstractNode visit(FileTypesByExtension sf) { return sf.new FileTypesByExtNode(sf.getSleuthkitCase(), null); @@ -196,13 +197,13 @@ public class RootContentChildren extends Children.Keys { @Override public AbstractNode visit(AnalysisResults analysisResults) { - return new Artifacts.AnalysisResultsNode( + return new AnalysisResults.RootNode( analysisResults.getFilteringDataSourceObjId()); } @Override public AbstractNode visit(DataArtifacts dataArtifacts) { - return new Artifacts.DataArtifactsNode( + return new DataArtifacts.RootNode( dataArtifacts.getFilteringDataSourceObjId()); } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 90245dfe4e..6d90e9b821 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -32,6 +32,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.prefs.PreferenceChangeEvent; @@ -72,18 +73,18 @@ import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.corecomponents.ViewPreferencesPanel; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.datamodel.AnalysisResults; import org.sleuthkit.autopsy.datamodel.ArtifactNodeSelectionInfo; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.EmailExtracted; import org.sleuthkit.autopsy.datamodel.EmptyNode; -import org.sleuthkit.autopsy.datamodel.Artifacts; import org.sleuthkit.autopsy.datamodel.FileTypesByMimeType; import org.sleuthkit.autopsy.datamodel.InterestingHits; import org.sleuthkit.autopsy.datamodel.KeywordHits; -import org.sleuthkit.autopsy.datamodel.ResultsNode; import org.sleuthkit.autopsy.datamodel.AutopsyTreeChildFactory; +import org.sleuthkit.autopsy.datamodel.DataArtifacts; import org.sleuthkit.autopsy.datamodel.PersonGroupingNode; import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.autopsy.datamodel.ViewsNode; @@ -91,6 +92,7 @@ import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.autopsy.datamodel.accounts.BINRange; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardArtifact.Category; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DataSource; @@ -199,19 +201,21 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat */ private void preExpandNodes(Children rootChildren) { BeanTreeView tree = getTree(); + for (String categoryKey : new String[]{AnalysisResults.getName(), DataArtifacts.getName()}) { + Node categoryNode = rootChildren.findChild(categoryKey); - Node results = rootChildren.findChild(ResultsNode.getNameIdentifier()); - if (!Objects.isNull(results)) { - tree.expandNode(results); - Children resultsChildren = results.getChildren(); - Arrays.stream(resultsChildren.getNodes()).forEach(tree::expandNode); + if (!Objects.isNull(categoryNode)) { + tree.expandNode(categoryNode); + Children resultsChildren = categoryNode.getChildren(); + Arrays.stream(resultsChildren.getNodes()).forEach(tree::expandNode); + } } Node views = rootChildren.findChild(ViewsNode.NAME); if (!Objects.isNull(views)) { tree.expandNode(views); } - + // expand all nodes parents of and including hosts if group by host/person if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { Node[] rootNodes = rootChildren.getNodes(); @@ -223,11 +227,13 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } } } - - + /** - * Returns all nodes including provided node that are parents of or are hosts. + * Returns all nodes including provided node that are parents of or are + * hosts. + * * @param node The parent or possible host node. + * * @return The descendant host nodes. */ private List getHostNodesAndParents(Node node) { @@ -307,7 +313,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * Setter to determine if rejected results should be shown or not. * * @param showRejectedResults True if showing rejected results; otherwise - * false. + * false. */ public void setShowRejectedResults(boolean showRejectedResults) { this.showRejectedResults = showRejectedResults; @@ -1054,7 +1060,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * Set the selected node using a path to a previously selected node. * * @param previouslySelectedNodePath Path to a previously selected node. - * @param rootNodeName Name of the root node to match, may be null. + * @param rootNodeName Name of the root node to match, may be + * null. */ private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) { if (previouslySelectedNodePath == null) { @@ -1112,53 +1119,82 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } /** - * Does dfs search of node while nodes are Host, Person, or - * DataSourcesByType looking for the Results Node. + * Returns the node matching the given category that is an immediate child + * of the provided Children object or empty if no immediate child matches + * the given category. * - * @param node The node. - * @param dataSourceId The data source id. - * @return The child nodes that are at the data source level. + * @param children The children to search. + * @param category The category to find. + * + * @return The node matching the given category */ - private Node getResultsNodeSearch(Node node, long dataSourceId) { - if (node == null) { - return null; - } else if (node.getLookup().lookup(Host.class) != null - || node.getLookup().lookup(Person.class) != null - || PersonGroupingNode.getUnknownPersonId().equals(node.getLookup().lookup(String.class))) { - Children children = node.getChildren(); - Node[] childNodes = children == null ? null : children.getNodes(); - if (childNodes != null) { - for (Node child : childNodes) { - Node foundExtracted = getResultsNodeSearch(child, dataSourceId); - if (foundExtracted != null) { - return foundExtracted; - } - } - } - } else { - DataSource dataSource = node.getLookup().lookup(DataSource.class); - if (dataSource != null && dataSource.getId() == dataSourceId) { - Children dsChildren = node.getChildren(); - if (dsChildren != null) { - return dsChildren.findChild(ResultsNode.getNameIdentifier()); - } - } + private Optional getCategoryNodeChild(Children children, Category category) { + switch (category) { + case DATA_ARTIFACT: + return Optional.ofNullable(children.findChild(DataArtifacts.getName())); + case ANALYSIS_RESULT: + return Optional.ofNullable(children.findChild(AnalysisResults.getName())); + default: + LOGGER.log(Level.WARNING, "Unbale to find category of type: " + category.name()); + return Optional.empty(); } - return null; } /** - * Finds the results node for the specific artifact. + * Does depth first search of node while nodes are Host, Person, or + * DataSourcesByType looking for the appropriate category Node (i.e. the + * Data Artifacts or Analysis Results nodes). * - * @param art The artifact to find the relevant Results Node. - * @return THe Results Node or null. + * @param node The node. + * @param dataSourceId The data source id. + * @param category The artifact type category. + * + * @return The child nodes that are at the data source level. */ - private Node getResultsNode(final BlackboardArtifact art) { - Children rootChilds = em.getRootContext().getChildren(); + private Optional searchForCategoryNode(Node node, long dataSourceId, Category category) { + if (node == null) { + // if no node, no result + return Optional.empty(); + } else if (node.getLookup().lookup(Host.class) != null + || node.getLookup().lookup(Person.class) != null + || PersonGroupingNode.getUnknownPersonId().equals(node.getLookup().lookup(String.class))) { + // if host or person node, recurse until we find correct data source node. + Children children = node.getChildren(); - Node resultsNode = rootChilds.findChild(ResultsNode.getNameIdentifier()); - if (resultsNode != null) { - return resultsNode; + Stream childNodeStream = children == null ? Stream.empty() : Stream.of(children.getNodes()); + return childNodeStream + .map(childNode -> searchForCategoryNode(childNode, dataSourceId, category)) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst(); + } else { + DataSource dataSource = node.getLookup().lookup(DataSource.class); + // if data source node and the one we want, find the right category node. + if (dataSource != null && dataSource.getId() == dataSourceId) { + Children dsChildren = node.getChildren(); + if (dsChildren != null) { + return getCategoryNodeChild(dsChildren, category); + } + } + + return Optional.empty(); + } + } + + /** + * Finds the category node (i.e. Data Artifacts / Analysis Results) for the + * specific artifact and category. + * + * @param category The category of the artifact. + * @param art The artifact to find the relevant Results Node. + * + * @return The category node or empty. + */ + private Optional getCategoryNode(Category category, BlackboardArtifact art) { + Children rootChildren = em.getRootContext().getChildren(); + Optional categoryNode = getCategoryNodeChild(rootChildren, category); + if (categoryNode.isPresent()) { + return categoryNode; } long dataSourceId; @@ -1169,17 +1205,31 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat return null; } - Node[] rootNodes = rootChilds.getNodes(); - if (rootNodes != null) { - for (Node rootNode : rootNodes) { - resultsNode = getResultsNodeSearch(rootNode, dataSourceId); - if (resultsNode != null) { - return resultsNode; - } - } - } + Node[] rootNodes = rootChildren.getNodes(); + Stream rootNodesStream = rootNodes == null ? Stream.empty() : Stream.of(rootNodes); + return rootNodesStream + .map((rootNode) -> searchForCategoryNode(rootNode, dataSourceId, category)) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst(); + } - return null; + /** + * Attempts to retrieve the artifact type for the given artifact type id. + * + * @param artifactTypeId The artifact type id. + * + * @return The artifact type if present or empty if not found. + */ + private Optional getType(long artifactTypeId) { + try { + return Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactTypesInUse().stream() + .filter(type -> type.getTypeID() == artifactTypeId) + .findFirst(); + } catch (NoCurrentCaseException | TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error occurred while looking up blackboard artifact type for: " + artifactTypeId, ex); + return Optional.empty(); + } } /** @@ -1196,207 +1246,34 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat public void viewArtifact(final BlackboardArtifact art) { int typeID = art.getArtifactTypeID(); String typeName = art.getArtifactTypeName(); - Node treeNode = null; - Node resultsNode = getResultsNode(art); - if (resultsNode == null) { + Optional typeOpt = getType(typeID); + Optional categoryChildrenOpt = typeOpt + .flatMap(type -> getCategoryNode(type.getCategory(), art)) + .flatMap(categoryNode -> Optional.ofNullable(categoryNode.getChildren())); + + if (!categoryChildrenOpt.isPresent()) { + LOGGER.log(Level.WARNING, String.format("Category node children for artifact of typeID: %d and artifactID: %d not found.", + typeID, art.getArtifactID())); return; } - Children resultsChilds = resultsNode.getChildren(); + Children typesChildren = categoryChildrenOpt.get(); + + Node treeNode = null; if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { - Node hashsetRootNode = resultsChilds.findChild(typeName); - Children hashsetRootChilds = hashsetRootNode.getChildren(); - try { - String setName = null; - List attributes = art.getAttributes(); - for (BlackboardAttribute att : attributes) { - int typeId = att.getAttributeType().getTypeID(); - if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { - setName = att.getValueString(); - } - } - treeNode = hashsetRootChilds.findChild(setName); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS - } + treeNode = getHashsetNode(typesChildren, art); } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - Node keywordRootNode = resultsChilds.findChild(typeName); - Children keywordRootChilds = keywordRootNode.getChildren(); - try { - String listName = null; - String keywordName = null; - String regex = null; - List attributes = art.getAttributes(); - for (BlackboardAttribute att : attributes) { - int typeId = att.getAttributeType().getTypeID(); - if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { - listName = att.getValueString(); - } else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) { - keywordName = att.getValueString(); - } else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()) { - regex = att.getValueString(); - } - } - if (listName == null) { - if (regex == null) { //using same labels used for creation - listName = NbBundle.getMessage(KeywordHits.class, "KeywordHits.simpleLiteralSearch.text"); - } else { - listName = NbBundle.getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text"); - } - } - Node listNode = keywordRootChilds.findChild(listName); - if (listNode == null) { - return; - } - Children listChildren = listNode.getChildren(); - if (listChildren == null) { - return; - } - if (regex != null) { //For support of regex nodes such as URLs, IPs, Phone Numbers, and Email Addrs as they are down another level - Node regexNode = listChildren.findChild(regex); - if (regexNode == null) { - return; - } - listChildren = regexNode.getChildren(); - if (listChildren == null) { - return; - } - } - - treeNode = listChildren.findChild(keywordName); - - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS - } + treeNode = getKeywordHitNode(typesChildren, art); } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() || typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { - Node interestingItemsRootNode = resultsChilds.findChild(NbBundle - .getMessage(InterestingHits.class, "InterestingHits.interestingItems.text")); - Children interestingItemsRootChildren = interestingItemsRootNode.getChildren(); - try { - String setName = null; - List attributes = art.getAttributes(); - for (BlackboardAttribute att : attributes) { - int typeId = att.getAttributeType().getTypeID(); - if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { - setName = att.getValueString(); - } - } - Node setNode = interestingItemsRootChildren.findChild(setName); - if (setNode == null) { - return; - } - - Children fileArtifactChildren = setNode.getChildren(); - Node[] fileArtifactNodes = fileArtifactChildren == null ? null : fileArtifactChildren.getNodes(); - if (fileArtifactNodes == null || fileArtifactNodes.length != 2) { - return; - } - - treeNode = (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()) - ? fileArtifactNodes[0] - : fileArtifactNodes[1]; - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS - } + treeNode = getInterestingItemNode(typesChildren, art); } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) { - Node emailMsgRootNode = resultsChilds.findChild(typeName); - Children emailMsgRootChilds = emailMsgRootNode.getChildren(); - Map parsedPath = null; - try { - List attributes = art.getAttributes(); - for (BlackboardAttribute att : attributes) { - int typeId = att.getAttributeType().getTypeID(); - if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID()) { - parsedPath = EmailExtracted.parsePath(att.getValueString()); - break; - } - } - if (parsedPath == null) { - return; - } - Node defaultNode = emailMsgRootChilds.findChild(parsedPath.get(NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text"))); - Children defaultChildren = defaultNode.getChildren(); - treeNode = defaultChildren.findChild(parsedPath.get(NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text"))); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS - } - + treeNode = getEmailNode(typesChildren, art); } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { - Node accountRootNode = resultsChilds.findChild(art.getDisplayName()); - Children accountRootChilds = accountRootNode.getChildren(); - List attributes; - String accountType = null; - String ccNumberName = null; - try { - attributes = art.getAttributes(); - for (BlackboardAttribute att : attributes) { - int typeId = att.getAttributeType().getTypeID(); - if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()) { - accountType = att.getValueString(); - } - if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID()) { - ccNumberName = att.getValueString(); - } - } - if (accountType == null) { - return; - } - - if (accountType.equals(Account.Type.CREDIT_CARD.getTypeName())) { - Node accountNode = accountRootChilds.findChild(Account.Type.CREDIT_CARD.getDisplayName()); - if (accountNode == null) { - return; - } - Children accountChildren = accountNode.getChildren(); - if (accountChildren == null) { - return; - } - Node binNode = accountChildren.findChild(NbBundle.getMessage(Accounts.class, "Accounts.ByBINNode.name")); - if (binNode == null) { - return; - } - Children binChildren = binNode.getChildren(); - if (ccNumberName == null) { - return; - } - //right padded with 0s to 8 digits when single number - //when a range of numbers, the first 6 digits are rightpadded with 0s to 8 digits then a dash then 3 digits, the 6,7,8, digits of the end number right padded with 9s - String binName = StringUtils.rightPad(ccNumberName, 8, "0"); - binName = binName.substring(0, 8); - int bin; - try { - bin = Integer.parseInt(binName); - } catch (NumberFormatException ex) { - LOGGER.log(Level.WARNING, "Unable to parseInt a BIN for node selection from string binName=" + binName, ex); //NON-NLS - return; - } - CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin); - if (binInfo != null) { - int startBin = ((BINRange) binInfo).getBINstart(); - int endBin = ((BINRange) binInfo).getBINend(); - if (startBin != endBin) { - binName = Integer.toString(startBin) + "-" + Integer.toString(endBin).substring(5); //if there is a range re-construct the name it appears as - } - } - if (binName == null) { - return; - } - treeNode = binChildren.findChild(binName); - } else { //default account type - treeNode = accountRootChilds.findChild(accountType); - } - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS - } + treeNode = getAccountNode(typesChildren, art); } else { - Node extractedContent = resultsChilds.findChild(Artifacts.NAME); - Children extractedChilds = extractedContent.getChildren(); - if (extractedChilds == null) { - return; - } - treeNode = extractedChilds.findChild(typeName); + treeNode = typesChildren.findChild(typeName); } if (treeNode == null) { @@ -1419,6 +1296,269 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // Another thread is needed because we have to wait for dataResult to populate } + /** + * Returns the hashset hit artifact's parent node or null if cannot be + * found. + * + * @param typesChildren The children object of the same category as hashset + * hits. + * @param art The artifact. + * + * @return The hashset hit artifact's parent node or null if cannot be + * found. + */ + private Node getHashsetNode(Children typesChildren, final BlackboardArtifact art) { + Node hashsetRootNode = typesChildren.findChild(art.getArtifactTypeName()); + Children hashsetRootChilds = hashsetRootNode.getChildren(); + try { + String setName = null; + List attributes = art.getAttributes(); + for (BlackboardAttribute att : attributes) { + int typeId = att.getAttributeType().getTypeID(); + if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { + setName = att.getValueString(); + } + } + return hashsetRootChilds.findChild(setName); + } catch (TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS + return null; + } + } + + /** + * Returns the keyword hit artifact's parent node or null if cannot be + * found. + * + * @param typesChildren The children object of the same category as keyword + * hits. + * @param art The artifact. + * + * @return The keyword hit artifact's parent node or null if cannot be + * found. + */ + private Node getKeywordHitNode(Children typesChildren, BlackboardArtifact art) { + Node keywordRootNode = typesChildren.findChild(art.getArtifactTypeName()); + Children keywordRootChilds = keywordRootNode.getChildren(); + try { + String listName = null; + String keywordName = null; + String regex = null; + List attributes = art.getAttributes(); + for (BlackboardAttribute att : attributes) { + int typeId = att.getAttributeType().getTypeID(); + if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { + listName = att.getValueString(); + } else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) { + keywordName = att.getValueString(); + } else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()) { + regex = att.getValueString(); + } + } + if (listName == null) { + if (regex == null) { //using same labels used for creation + listName = NbBundle.getMessage(KeywordHits.class, "KeywordHits.simpleLiteralSearch.text"); + } else { + listName = NbBundle.getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text"); + } + } + Node listNode = keywordRootChilds.findChild(listName); + if (listNode == null) { + return null; + } + Children listChildren = listNode.getChildren(); + if (listChildren == null) { + return null; + } + if (regex != null) { //For support of regex nodes such as URLs, IPs, Phone Numbers, and Email Addrs as they are down another level + Node regexNode = listChildren.findChild(regex); + if (regexNode == null) { + return null; + } + listChildren = regexNode.getChildren(); + if (listChildren == null) { + return null; + } + } + + return listChildren.findChild(keywordName); + } catch (TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS + return null; + } + } + + /** + * Returns the interesting item artifact's parent node or null if cannot be + * found. + * + * @param typesChildren The children object of the same category as + * interesting item. + * @param art The artifact. + * + * @return The interesting item artifact's parent node or null if cannot be + * found. + */ + private Node getInterestingItemNode(Children typesChildren, BlackboardArtifact art) { + Node interestingItemsRootNode = typesChildren.findChild(NbBundle + .getMessage(InterestingHits.class, "InterestingHits.interestingItems.text")); + Children interestingItemsRootChildren = interestingItemsRootNode.getChildren(); + try { + String setName = null; + List attributes = art.getAttributes(); + for (BlackboardAttribute att : attributes) { + int typeId = att.getAttributeType().getTypeID(); + if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { + setName = att.getValueString(); + } + } + Node setNode = interestingItemsRootChildren.findChild(setName); + if (setNode == null) { + return null; + } + + Children fileArtifactChildren = setNode.getChildren(); + Node[] fileArtifactNodes = fileArtifactChildren == null ? null : fileArtifactChildren.getNodes(); + if (fileArtifactNodes == null || fileArtifactNodes.length != 2) { + return null; + } + + return (art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()) + ? fileArtifactNodes[0] + : fileArtifactNodes[1]; + } catch (TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS + return null; + } + } + + /** + * Returns the email artifact's parent node or null if cannot be found. + * + * @param typesChildren The children object of the same category as email. + * @param art The artifact. + * + * @return The email artifact's parent node or null if cannot be found. + */ + private Node getEmailNode(Children typesChildren, BlackboardArtifact art) { + Node emailMsgRootNode = typesChildren.findChild(art.getArtifactTypeName()); + Children emailMsgRootChilds = emailMsgRootNode.getChildren(); + Map parsedPath = null; + try { + List attributes = art.getAttributes(); + for (BlackboardAttribute att : attributes) { + int typeId = att.getAttributeType().getTypeID(); + if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID()) { + parsedPath = EmailExtracted.parsePath(att.getValueString()); + break; + } + } + if (parsedPath == null) { + return null; + } + Node defaultNode = emailMsgRootChilds.findChild(parsedPath.get(NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text"))); + Children defaultChildren = defaultNode.getChildren(); + return defaultChildren.findChild(parsedPath.get(NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text"))); + } catch (TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS + return null; + } + } + + /** + * Returns the account artifact's parent node or null if cannot be found. + * + * @param typesChildren The children object of the same category as the + * account. + * @param art The artifact. + * + * @return The account artifact's parent node or null if cannot be found. + */ + private Node getAccountNode(Children typesChildren, BlackboardArtifact art) { + Node accountRootNode = typesChildren.findChild(art.getDisplayName()); + Children accountRootChilds = accountRootNode.getChildren(); + List attributes; + String accountType = null; + String ccNumberName = null; + try { + attributes = art.getAttributes(); + for (BlackboardAttribute att : attributes) { + int typeId = att.getAttributeType().getTypeID(); + if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()) { + accountType = att.getValueString(); + } + if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID()) { + ccNumberName = att.getValueString(); + } + } + if (accountType == null) { + return null; + } + + if (accountType.equals(Account.Type.CREDIT_CARD.getTypeName())) { + return getCreditCardAccountNode(accountRootChilds, ccNumberName); + } else { //default account type + return accountRootChilds.findChild(accountType); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS + return null; + } + } + + /** + * Returns the credit card artifact's parent node or null if cannot be + * found. + * + * @param typesChildren The children object of the same category as credit + * card. + * @param art The artifact. + * + * @return The credit card artifact's parent node or null if cannot be + * found. + */ + private Node getCreditCardAccountNode(Children accountRootChildren, String ccNumberName) { + Node accountNode = accountRootChildren.findChild(Account.Type.CREDIT_CARD.getDisplayName()); + if (accountNode == null) { + return null; + } + Children accountChildren = accountNode.getChildren(); + if (accountChildren == null) { + return null; + } + Node binNode = accountChildren.findChild(NbBundle.getMessage(Accounts.class, "Accounts.ByBINNode.name")); + if (binNode == null) { + return null; + } + Children binChildren = binNode.getChildren(); + if (ccNumberName == null) { + return null; + } + //right padded with 0s to 8 digits when single number + //when a range of numbers, the first 6 digits are rightpadded with 0s to 8 digits then a dash then 3 digits, the 6,7,8, digits of the end number right padded with 9s + String binName = StringUtils.rightPad(ccNumberName, 8, "0"); + binName = binName.substring(0, 8); + int bin; + try { + bin = Integer.parseInt(binName); + } catch (NumberFormatException ex) { + LOGGER.log(Level.WARNING, "Unable to parseInt a BIN for node selection from string binName=" + binName, ex); //NON-NLS + return null; + } + CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin); + if (binInfo != null) { + int startBin = ((BINRange) binInfo).getBINstart(); + int endBin = ((BINRange) binInfo).getBINend(); + if (startBin != endBin) { + binName = Integer.toString(startBin) + "-" + Integer.toString(endBin).substring(5); //if there is a range re-construct the name it appears as + } + } + if (binName == null) { + return null; + } + return binChildren.findChild(binName); + } + public void viewArtifactContent(BlackboardArtifact art) { new ViewContextAction( NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.action.viewArtContent.text"), From 61ede44e7e1b54f839a7327fb4a4cb79a22c3317 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 3 May 2021 14:38:16 -0400 Subject: [PATCH 18/21] bug fixes --- .../autopsy/datamodel/Artifacts.java | 34 ++++--- .../datamodel/Bundle.properties-MERGED | 8 +- .../autopsy/datamodel/accounts/Accounts.java | 99 +++++++++++++------ 3 files changed, 92 insertions(+), 49 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index 2bce9cdc95..cc78991c95 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -70,7 +70,6 @@ public class Artifacts { private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); - /** * Base class for a parent node of artifacts. */ @@ -463,6 +462,27 @@ public class Artifacts { return this.childCount; } + /** + * Fetches the count to be displayed from the case. + * + * @param skCase The relevant SleuthkitCase. + * + * @return The count to be displayed. + * + * @throws TskCoreException + */ + protected long fetchChildCount(SleuthkitCase skCase) throws TskCoreException { + int count = 0; + for (BlackboardArtifact.Type type : this.types) { + if (filteringDSObjId > 0) { + count += skCase.getBlackboard().getArtifactsCount(type.getTypeID(), filteringDSObjId); + } else { + count += skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); + } + } + return count; + } + /** * When this method is called, the count to be displayed will be * updated. @@ -470,17 +490,7 @@ public class Artifacts { void updateDisplayName() { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - - int count = 0; - for (BlackboardArtifact.Type type : this.types) { - if (filteringDSObjId > 0) { - count += skCase.getBlackboard().getArtifactsCount(type.getTypeID(), filteringDSObjId); - } else { - count += skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); - } - } - - this.childCount = count; + this.childCount = fetchChildCount(skCase); } catch (NoCurrentCaseException ex) { logger.log(Level.WARNING, "Error fetching data when case closed.", ex); } catch (TskCoreException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED index aa955c23e8..2feefb56c7 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED @@ -39,7 +39,7 @@ AbstractAbstractFileNode.useridColLbl=UserID AbstractContentNode.nodescription=no description AbstractContentNode.valueLoading=value loading AbstractFsContentNode.noDesc.text=no description -AnalysisResultsNode_name=Analysis Results +AnalysisResults_name=Analysis Results ArtifactStringContent.attrsTableHeader.sources=Source(s) ArtifactStringContent.attrsTableHeader.type=Type ArtifactStringContent.attrsTableHeader.value=Value @@ -94,7 +94,7 @@ ContentTagNode.createSheet.artifactMD5.displayName=MD5 Hash ContentTagNode.createSheet.artifactMD5.name=MD5 Hash ContentTagNode.createSheet.origFileName=Original Name ContentTagNode.createSheet.userName.text=User Name -DataArtifactsNode_name=Data Artifacts +DataArtifacts_name=Data Artifacts DataSourcesHostsNode_name=Data Sources DeletedContent.allDelFilter.text=All DeletedContent.createSheet.filterType.desc=no description @@ -360,10 +360,6 @@ ReportNode.reportNameProperty.name=Report Name ReportNode.reportNameProperty.displayName=Report Name ReportNode.reportNameProperty.desc=Name of the report ReportsListNode.displayName=Reports -ResultsNode.createSheet.name.desc=no description -ResultsNode.createSheet.name.displayName=Name -ResultsNode.createSheet.name.name=Name -ResultsNode.name.text=Results SlackFileNode.getActions.viewInNewWin.text=View in New Window SlackFileNode.getActions.viewFileInDir.text=View File in Directory SpecialDirectoryNode.getActions.viewInNewWin.text=View in New Window diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index aa6a53f8ec..c453603874 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -96,7 +96,7 @@ final public class Accounts implements AutopsyVisitableItem { private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED); private static final String DISPLAY_NAME = Bundle.Accounts_RootNode_displayName(); - + @NbBundle.Messages("AccountsRootNode.name=Accounts") final public static String NAME = Bundle.AccountsRootNode_name(); @@ -112,11 +112,10 @@ final public class Accounts implements AutopsyVisitableItem { private final RejectAccounts rejectActionInstance; private final ApproveAccounts approveActionInstance; - + // tracks the number of each account type found private final AccountTypeResults accountTypeResults; - /** * Constructor * @@ -135,7 +134,7 @@ final public class Accounts implements AutopsyVisitableItem { public Accounts(SleuthkitCase skCase, long objId) { this.skCase = skCase; this.filteringDSObjId = objId; - + this.rejectActionInstance = new RejectAccounts(); this.approveActionInstance = new ApproveAccounts(); this.accountTypeResults = new AccountTypeResults(); @@ -238,12 +237,12 @@ final public class Accounts implements AutopsyVisitableItem { final public class AccountsRootNode extends UpdatableCountTypeNode { public AccountsRootNode() { - super(Children.create(new AccountTypeFactory(), true), + super(Children.create(new AccountTypeFactory(), true), Lookups.singleton(Accounts.this), DISPLAY_NAME, filteringDSObjId, new BlackboardArtifact.Type(TSK_ACCOUNT)); - + setName(Accounts.NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/accounts.png"); //NON-NLS } @@ -262,37 +261,71 @@ final public class Accounts implements AutopsyVisitableItem { public String getItemType() { return getClass().getName(); } + + @Override + protected long fetchChildCount(SleuthkitCase skCase) throws TskCoreException { + long count = 0; + String dataSourceFilterClause = (filteringDSObjId > 0) + ? " AND " + filteringDSObjId + " IN (SELECT art.data_source_obj_id FROM blackboard_artifacts art WHERE art.artifact_id = attr.artifact_id)" + : ""; + + String accountTypesInUseQuery + = "SELECT COUNT(attr.value_text) AS count" + + " FROM blackboard_attributes attr" + + " WHERE attr.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() + + " AND attr.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() + + dataSourceFilterClause + + " GROUP BY attr.value_text"; + + try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery); + ResultSet resultSet = executeQuery.getResultSet()) { + + if (resultSet.next()) { + count = resultSet.getLong("count"); + } + + } catch (TskCoreException | SQLException ex) { + LOGGER.log(Level.SEVERE, "Error querying for count of all account types", ex); + } + return count; + } + } - + /** * Tracks the account types and the number of account types found. */ private class AccountTypeResults { + private final Map counts = new HashMap<>(); - + AccountTypeResults() { update(); } - + /** - * Given the type name of the Account.Type, provides the count of those type. - * @param accountType The type name of the Account.Type. - * @return The number of results found for the given account type. + * Given the type name of the Account.Type, provides the count of those + * type. + * + * @param accountType The type name of the Account.Type. + * + * @return The number of results found for the given account type. */ Long getCount(String accountType) { return counts.get(accountType); } - + /** * Retrieves an alphabetically organized list of all the account types. - * @return An alphabetically organized list of all the account types. + * + * @return An alphabetically organized list of all the account types. */ List getTypes() { List types = new ArrayList<>(counts.keySet()); Collections.sort(types); return types; } - + /** * Queries the database and updates the counts for each account type. */ @@ -308,7 +341,7 @@ final public class Accounts implements AutopsyVisitableItem { try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery); ResultSet resultSet = executeQuery.getResultSet()) { - + counts.clear(); while (resultSet.next()) { String accountType = resultSet.getString("account_type"); @@ -325,7 +358,7 @@ final public class Accounts implements AutopsyVisitableItem { * Creates child nodes for each account type in the db. */ private class AccountTypeFactory extends ObservingChildren { - + /* * The pcl is in this class because it has the easiest mechanisms to add * and remove itself during its life cycles. @@ -399,12 +432,14 @@ final public class Accounts implements AutopsyVisitableItem { list.addAll(accountTypeResults.getTypes()); return true; } - + /** - * Registers the given node with the reviewStatusBus and returns - * the node wrapped in an array. - * @param node The node to be wrapped. - * @return The array containing this node. + * Registers the given node with the reviewStatusBus and returns the + * node wrapped in an array. + * + * @param node The node to be wrapped. + * + * @return The array containing this node. */ private Node[] getNodeArr(Node node) { reviewStatusBus.register(node); @@ -584,8 +619,9 @@ final public class Accounts implements AutopsyVisitableItem { * no special behavior. */ final public class DefaultAccountTypeNode extends DisplayableItemNode { + private final Account.Type accountType; - + private DefaultAccountTypeNode(Account.Type accountType) { super(Children.create(new DefaultAccountFactory(accountType), true), Lookups.singleton(accountType)); this.accountType = accountType; @@ -608,8 +644,7 @@ final public class Accounts implements AutopsyVisitableItem { public String getItemType() { return getClass().getName(); } - - + @Subscribe void handleReviewStatusChange(ReviewStatusChangeEvent event) { updateName(); @@ -619,12 +654,13 @@ final public class Accounts implements AutopsyVisitableItem { void handleDataAdded(ModuleDataEvent event) { updateName(); } - + /** - * Gets the latest counts for the account type and then updates the name. + * Gets the latest counts for the account type and then updates the + * name. */ public void updateName() { - setName(String.format("%s (%d)", accountType.getDisplayName(), accountTypeResults.getCount(accountType.getTypeName()))); + setDisplayName(String.format("%s (%d)", accountType.getDisplayName(), accountTypeResults.getCount(accountType.getTypeName()))); } } @@ -755,14 +791,15 @@ final public class Accounts implements AutopsyVisitableItem { setName(Account.Type.CREDIT_CARD.getDisplayName()); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS } - + /** - * Gets the latest counts for the account type and then updates the name. + * Gets the latest counts for the account type and then updates the + * name. */ public void updateName() { setName(String.format("%s (%d)", Account.Type.CREDIT_CARD.getDisplayName(), accountTypeResults.getCount(Account.Type.CREDIT_CARD.getTypeName()))); } - + @Subscribe void handleReviewStatusChange(ReviewStatusChangeEvent event) { updateName(); From 188d02809c5a97bc343393094862817fbc084f98 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 3 May 2021 14:55:07 -0400 Subject: [PATCH 19/21] bug fix --- Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index c453603874..8559d45d51 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -627,6 +627,7 @@ final public class Accounts implements AutopsyVisitableItem { this.accountType = accountType; String iconPath = getIconFilePath(accountType); this.setIconBaseWithExtension(iconPath != null && iconPath.charAt(0) == '/' ? iconPath.substring(1) : iconPath); //NON-NLS + setName(accountType.getTypeName()); updateName(); } From e9f9dd87d9d8c72e69dfbedda12815fc4985e8e2 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 3 May 2021 15:38:52 -0400 Subject: [PATCH 20/21] migration to blackboard artifact types --- .../autopsy/datamodel/Artifacts.java | 44 ++++++++++--------- .../autopsy/datamodel/EmailExtracted.java | 8 ++-- .../autopsy/datamodel/HashsetHits.java | 13 +++--- .../autopsy/datamodel/InterestingHits.java | 26 +++++------ .../autopsy/datamodel/KeywordHits.java | 10 ++--- .../autopsy/datamodel/accounts/Accounts.java | 30 ++++++------- .../DirectoryTreeTopComponent.java | 17 +++---- 7 files changed, 76 insertions(+), 72 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index cc78991c95..d39bef3ee9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -36,7 +36,6 @@ import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.Lookup; import org.openide.util.NbBundle; -import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -46,21 +45,22 @@ import org.sleuthkit.autopsy.datamodel.utils.IconsUtil; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_TL_EVENT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.guiutils.RefreshThrottler; import org.sleuthkit.datamodel.BlackboardArtifact.Category; import org.python.google.common.collect.Sets; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_ACCOUNT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_DATA_SOURCE_USAGE; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_EMAIL_MSG; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_HASHSET_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_GEN_INFO; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_TL_EVENT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_ASSOCIATED_OBJECT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_KEYWORD_HIT; /** * Classes for creating nodes for BlackboardArtifacts. @@ -215,12 +215,12 @@ public class Artifacts { @SuppressWarnings("deprecation") private static final Set IGNORED_TYPES = Sets.newHashSet( // these are shown in other parts of the UI (and different node types) - new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE), - new BlackboardArtifact.Type(TSK_GEN_INFO), + TSK_DATA_SOURCE_USAGE, + TSK_GEN_INFO, new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE), - new BlackboardArtifact.Type(TSK_TL_EVENT), + TSK_TL_EVENT, //This is not meant to be shown in the UI at all. It is more of a meta artifact. - new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT) + TSK_ASSOCIATED_OBJECT ); /** @@ -238,24 +238,28 @@ public class Artifacts { int typeId = type.getTypeID(); if (TSK_EMAIL_MSG.getTypeID() == typeId) { EmailExtracted.RootNode emailNode = new EmailExtracted(skCase, dsObjId).new RootNode(); - return new TypeNodeKey(emailNode, new BlackboardArtifact.Type(TSK_EMAIL_MSG)); + return new TypeNodeKey(emailNode, TSK_EMAIL_MSG); } else if (TSK_ACCOUNT.getTypeID() == typeId) { Accounts.AccountsRootNode accountsNode = new Accounts(skCase, dsObjId).new AccountsRootNode(); - return new TypeNodeKey(accountsNode, new BlackboardArtifact.Type(TSK_ACCOUNT)); + return new TypeNodeKey(accountsNode, TSK_ACCOUNT); } else if (TSK_KEYWORD_HIT.getTypeID() == typeId) { KeywordHits.RootNode keywordsNode = new KeywordHits(skCase, dsObjId).new RootNode(); - return new TypeNodeKey(keywordsNode, new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); + return new TypeNodeKey(keywordsNode, TSK_KEYWORD_HIT); } else if (TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == typeId || TSK_INTERESTING_FILE_HIT.getTypeID() == typeId) { InterestingHits.RootNode interestingHitsNode = new InterestingHits(skCase, dsObjId).new RootNode(); return new TypeNodeKey(interestingHitsNode, - new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT), - new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT)); + TSK_INTERESTING_ARTIFACT_HIT, + TSK_INTERESTING_FILE_HIT); + } else if (TSK_HASHSET_HIT.getTypeID() == typeId) { + HashsetHits.RootNode hashsetHits = new HashsetHits(skCase, dsObjId).new RootNode(); + return new TypeNodeKey(hashsetHits, TSK_HASHSET_HIT); + } else { return new TypeNodeKey(type, dsObjId); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 06ed408976..845fdf8798 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -44,7 +44,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_EMAIL_MSG; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; @@ -59,7 +59,7 @@ import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; */ public class EmailExtracted implements AutopsyVisitableItem { - private static final String LABEL_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getLabel(); + private static final String LABEL_NAME = BlackboardArtifact.Type.TSK_EMAIL_MSG.getLabel(); private static final Logger logger = Logger.getLogger(EmailExtracted.class.getName()); private static final String MAIL_ACCOUNT = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailAccount.text"); private static final String MAIL_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text"); @@ -157,7 +157,7 @@ public class EmailExtracted implements AutopsyVisitableItem { } // get artifact id and path (if present) of all email artifacts - int emailArtifactId = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(); + int emailArtifactId = BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeID(); int pathAttrId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID(); String query = "SELECT \n" @@ -279,7 +279,7 @@ public class EmailExtracted implements AutopsyVisitableItem { * for the event to have a null oldValue. */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); - if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) { + if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeID()) { emailResults.update(); } } catch (NoCurrentCaseException notUsed) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index 150a52e3da..5318a99a00 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -46,8 +46,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_HASHSET_HIT; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; @@ -59,8 +58,8 @@ import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; */ public class HashsetHits implements AutopsyVisitableItem { - private static final String HASHSET_HITS = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getLabel(); - private static final String DISPLAY_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(); + private static final String HASHSET_HITS = BlackboardArtifact.Type.TSK_HASHSET_HIT.getTypeName(); + private static final String DISPLAY_NAME = BlackboardArtifact.Type.TSK_HASHSET_HIT.getDisplayName(); private static final Logger logger = Logger.getLogger(HashsetHits.class.getName()); private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED); @@ -136,7 +135,7 @@ public class HashsetHits implements AutopsyVisitableItem { } int setNameId = ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(); - int artId = ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(); + int artId = TSK_HASHSET_HIT.getTypeID(); String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS + "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS + "attribute_type_id=" + setNameId //NON-NLS @@ -177,7 +176,7 @@ public class HashsetHits implements AutopsyVisitableItem { Lookups.singleton(DISPLAY_NAME), DISPLAY_NAME, filteringDSObjId, - new BlackboardArtifact.Type(TSK_HASHSET_HIT)); + TSK_HASHSET_HIT); super.setName(HASHSET_HITS); super.setDisplayName(DISPLAY_NAME); @@ -246,7 +245,7 @@ public class HashsetHits implements AutopsyVisitableItem { * oldValue if the event is a remote event. */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); - if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { + if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == TSK_HASHSET_HIT.getTypeID()) { hashsetResults.update(); } } catch (NoCurrentCaseException notUsed) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 28bfb3e8dc..22525854ca 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -111,8 +111,8 @@ public class InterestingHits implements AutopsyVisitableItem { synchronized (interestingItemsMap) { interestingItemsMap.clear(); } - loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); - loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); + loadArtifacts(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT); + loadArtifacts(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT); setChanged(); notifyObservers(); } @@ -122,7 +122,7 @@ public class InterestingHits implements AutopsyVisitableItem { * the interestingItemsMap */ @SuppressWarnings("deprecation") - private void loadArtifacts(BlackboardArtifact.ARTIFACT_TYPE artType) { + private void loadArtifacts(BlackboardArtifact.Type artType) { if (skCase == null) { return; } @@ -146,8 +146,8 @@ public class InterestingHits implements AutopsyVisitableItem { long artifactId = resultSet.getLong("artifact_id"); //NON-NLS if (!interestingItemsMap.containsKey(value)) { interestingItemsMap.put(value, new LinkedHashMap<>()); - interestingItemsMap.get(value).put(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getDisplayName(), new HashSet<>()); - interestingItemsMap.get(value).put(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName(), new HashSet<>()); + interestingItemsMap.get(value).put(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName(), new HashSet<>()); + interestingItemsMap.get(value).put(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName(), new HashSet<>()); } interestingItemsMap.get(value).get(artType.getDisplayName()).add(artifactId); } @@ -173,8 +173,8 @@ public class InterestingHits implements AutopsyVisitableItem { Lookups.singleton(DISPLAY_NAME), DISPLAY_NAME, filteringDSObjId, - new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT), - new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT)); + BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, + BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT); super.setName(INTERESTING_ITEMS); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS } @@ -237,8 +237,8 @@ public class InterestingHits implements AutopsyVisitableItem { * event to have a null oldValue. */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); - if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() - || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID())) { + if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() + || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID())) { interestingResults.update(); } } catch (NoCurrentCaseException notUsed) { @@ -319,8 +319,8 @@ public class InterestingHits implements AutopsyVisitableItem { } private void updateDisplayName() { - int sizeOfSet = interestingResults.getArtifactIds(setName, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()).size() - + interestingResults.getArtifactIds(setName, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getDisplayName()).size(); + int sizeOfSet = interestingResults.getArtifactIds(setName, BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()).size() + + interestingResults.getArtifactIds(setName, BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName()).size(); super.setDisplayName(setName + " (" + sizeOfSet + ")"); } @@ -379,8 +379,8 @@ public class InterestingHits implements AutopsyVisitableItem { @Override protected boolean createKeys(List list) { - list.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getDisplayName()); - list.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()); + list.add(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getDisplayName()); + list.add(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getDisplayName()); return true; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 845c87d5ea..396cbea57e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -55,7 +55,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_KEYWORD_HIT; import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; /** @@ -73,7 +73,7 @@ public class KeywordHits implements AutopsyVisitableItem { @NbBundle.Messages("KeywordHits.singleRegexSearch.text=Single Regular Expression Search") private static final String SIMPLE_REGEX_SEARCH = KeywordHits_singleRegexSearch_text(); - public static final String NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getLabel(); + public static final String NAME = BlackboardArtifact.Type.TSK_KEYWORD_HIT.getLabel(); private SleuthkitCase skCase; private final KeywordResults keywordResults; @@ -95,7 +95,7 @@ public class KeywordHits implements AutopsyVisitableItem { + "blackboard_attributes.attribute_type_id "//NON-NLS + "FROM blackboard_attributes, blackboard_artifacts "//NON-NLS + "WHERE blackboard_attributes.artifact_id = blackboard_artifacts.artifact_id "//NON-NLS - + " AND blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() //NON-NLS + + " AND blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeID() //NON-NLS + " AND (attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()//NON-NLS + " OR attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()//NON-NLS + " OR attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()//NON-NLS @@ -384,7 +384,7 @@ public class KeywordHits implements AutopsyVisitableItem { Lookups.singleton(KEYWORD_HITS), KEYWORD_HITS, filteringDSObjId, - new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); + TSK_KEYWORD_HIT); super.setName(NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS @@ -470,7 +470,7 @@ public class KeywordHits implements AutopsyVisitableItem { * for the event to have a null oldValue. */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); - if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { + if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeID()) { keywordResults.update(); } } catch (NoCurrentCaseException notUsed) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index 8559d45d51..18136db99e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -77,8 +77,8 @@ import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT; +import org.sleuthkit.datamodel.BlackboardArtifact.Type; +import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_ACCOUNT; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; @@ -241,7 +241,7 @@ final public class Accounts implements AutopsyVisitableItem { Lookups.singleton(Accounts.this), DISPLAY_NAME, filteringDSObjId, - new BlackboardArtifact.Type(TSK_ACCOUNT)); + TSK_ACCOUNT); setName(Accounts.NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/accounts.png"); //NON-NLS @@ -384,7 +384,7 @@ final public class Accounts implements AutopsyVisitableItem { */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); if (null != eventData - && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + && eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) { accountTypeResults.update(); reviewStatusBus.post(eventData); } @@ -519,7 +519,7 @@ final public class Accounts implements AutopsyVisitableItem { */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); if (null != eventData - && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + && eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) { reviewStatusBus.post(eventData); } } catch (NoCurrentCaseException notUsed) { @@ -572,7 +572,7 @@ final public class Accounts implements AutopsyVisitableItem { = "SELECT blackboard_artifacts.artifact_id " //NON-NLS + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + " AND blackboard_attributes.value_text = '" + accountType.getTypeName() + "'" //NON-NLS + getFilterByDataSourceClause() @@ -696,7 +696,7 @@ final public class Accounts implements AutopsyVisitableItem { */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); if (null != eventData - && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + && eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) { reviewStatusBus.post(eventData); } } catch (NoCurrentCaseException notUsed) { @@ -850,7 +850,7 @@ final public class Accounts implements AutopsyVisitableItem { */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); if (null != eventData - && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + && eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) { reviewStatusBus.post(eventData); } } catch (NoCurrentCaseException notUsed) { @@ -928,7 +928,7 @@ final public class Accounts implements AutopsyVisitableItem { + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS + getFilterByDataSourceClause() + getRejectedArtifactFilterClause() + " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS @@ -997,7 +997,7 @@ final public class Accounts implements AutopsyVisitableItem { + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS + getFilterByDataSourceClause() + getRejectedArtifactFilterClause() + " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo"; @@ -1065,7 +1065,7 @@ final public class Accounts implements AutopsyVisitableItem { */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); if (null != eventData - && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + && eventData.getBlackboardArtifactType().getTypeID() == Type.TSK_ACCOUNT.getTypeID()) { reviewStatusBus.post(eventData); } } catch (NoCurrentCaseException notUsed) { //NOPMD empy catch clause @@ -1133,7 +1133,7 @@ final public class Accounts implements AutopsyVisitableItem { + " COUNT(blackboard_artifacts.artifact_id) AS count " //NON-NLS + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + getFilterByDataSourceClause() + getRejectedArtifactFilterClause() @@ -1200,7 +1200,7 @@ final public class Accounts implements AutopsyVisitableItem { = "SELECT count(distinct SUBSTR(blackboard_attributes.value_text,1,8)) AS BINs " //NON-NLS + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + getFilterByDataSourceClause() + getRejectedArtifactFilterClause(); //NON-NLS @@ -1495,7 +1495,7 @@ final public class Accounts implements AutopsyVisitableItem { = "SELECT blackboard_artifacts.artifact_id " //NON-NLS + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS + getFilterByDataSourceClause() @@ -1569,7 +1569,7 @@ final public class Accounts implements AutopsyVisitableItem { = "SELECT count(blackboard_artifacts.artifact_id ) AS count" //NON-NLS + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS + getFilterByDataSourceClause() diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 6d90e9b821..d5fe55d358 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -1261,16 +1261,16 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat Children typesChildren = categoryChildrenOpt.get(); Node treeNode = null; - if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { + if (typeID == BlackboardArtifact.Type.TSK_HASHSET_HIT.getTypeID()) { treeNode = getHashsetNode(typesChildren, art); - } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { + } else if (typeID == BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeID()) { treeNode = getKeywordHitNode(typesChildren, art); - } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() - || typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { + } else if (typeID == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID() + || typeID == BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { treeNode = getInterestingItemNode(typesChildren, art); - } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) { + } else if (typeID == BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeID()) { treeNode = getEmailNode(typesChildren, art); - } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + } else if (typeID == BlackboardArtifact.Type.TSK_ACCOUNT.getTypeID()) { treeNode = getAccountNode(typesChildren, art); } else { treeNode = typesChildren.findChild(typeName); @@ -1371,7 +1371,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat return null; } if (regex != null) { //For support of regex nodes such as URLs, IPs, Phone Numbers, and Email Addrs as they are down another level - Node regexNode = listChildren.findChild(regex); + Node regexNode = listChildren.findChild(listName); + regexNode = (regexNode == null) ? listChildren.findChild(listName + "_" + regex) : regexNode; if (regexNode == null) { return null; } @@ -1423,7 +1424,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat return null; } - return (art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()) + return (art.getArtifactTypeID() == BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID()) ? fileArtifactNodes[0] : fileArtifactNodes[1]; } catch (TskCoreException ex) { From dae6b773b1c872721aabbd03baeac5364a99b1c0 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 3 May 2021 20:00:00 -0400 Subject: [PATCH 21/21] fixes --- Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java | 4 ++-- Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 845fdf8798..357f6ec153 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -59,7 +59,7 @@ import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode; */ public class EmailExtracted implements AutopsyVisitableItem { - private static final String LABEL_NAME = BlackboardArtifact.Type.TSK_EMAIL_MSG.getLabel(); + private static final String LABEL_NAME = BlackboardArtifact.Type.TSK_EMAIL_MSG.getTypeName(); private static final Logger logger = Logger.getLogger(EmailExtracted.class.getName()); private static final String MAIL_ACCOUNT = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailAccount.text"); private static final String MAIL_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text"); @@ -210,7 +210,7 @@ public class EmailExtracted implements AutopsyVisitableItem { Lookups.singleton(TSK_EMAIL_MSG.getDisplayName()), TSK_EMAIL_MSG.getDisplayName(), filteringDSObjId, - new BlackboardArtifact.Type(TSK_EMAIL_MSG)); + TSK_EMAIL_MSG); //super(Children.create(new AccountFactory(), true), Lookups.singleton(DISPLAY_NAME)); super.setName(LABEL_NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/mail-icon-16.png"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 396cbea57e..eab8a07d3a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -73,7 +73,7 @@ public class KeywordHits implements AutopsyVisitableItem { @NbBundle.Messages("KeywordHits.singleRegexSearch.text=Single Regular Expression Search") private static final String SIMPLE_REGEX_SEARCH = KeywordHits_singleRegexSearch_text(); - public static final String NAME = BlackboardArtifact.Type.TSK_KEYWORD_HIT.getLabel(); + public static final String NAME = BlackboardArtifact.Type.TSK_KEYWORD_HIT.getTypeName(); private SleuthkitCase skCase; private final KeywordResults keywordResults;