From 28a011c3e9cc396340a3c4d3f68c09398fa04d6c Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 27 Jul 2021 13:04:00 -0400 Subject: [PATCH 01/76] 3849 - select data source automatically when performing search from context menu --- .../autopsy/datamodel/ImageNode.java | 2 +- .../datamodel/SpecialDirectoryNode.java | 2 +- .../directorytree/FileSearchAction.java | 22 ++++++++++++++----- .../directorytree/FileSearchProvider.java | 4 +++- .../autopsy/filesearch/DataSourceFilter.java | 18 ++++++++++----- .../autopsy/filesearch/DataSourcePanel.java | 15 ++++++++++++- .../autopsy/filesearch/FileSearchAction.java | 14 +++++++++++- .../autopsy/filesearch/FileSearchDialog.java | 4 ++++ .../autopsy/filesearch/FileSearchPanel.java | 7 +++++- 9 files changed, 71 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index 5df888052b..feada332a5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -110,7 +110,7 @@ public class ImageNode extends AbstractContentNode { actionsList.add(a); } actionsList.addAll(ExplorerNodeActionVisitor.getActions(content)); - actionsList.add(new FileSearchAction(Bundle.ImageNode_getActions_openFileSearchByAttr_text())); + actionsList.add(new FileSearchAction(Bundle.ImageNode_getActions_openFileSearchByAttr_text(), content.getId())); actionsList.add(new ViewSummaryInformationAction(content.getId())); actionsList.add(new RunIngestModulesAction(Collections.singletonList(content))); actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "ImageNode.getActions.viewInNewWin.text"), this)); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java index a3c6691ba2..0cb1046d94 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java @@ -65,7 +65,7 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNodesingletonList(content))); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java index 9ec86b7900..0cc0bf237d 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java @@ -1,15 +1,15 @@ /* * 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. @@ -28,14 +28,26 @@ import org.openide.util.Lookup; */ public class FileSearchAction extends AbstractAction { + private final Long dataSourceId; + + public FileSearchAction(String title, long dataSourceID) { + super(title); + dataSourceId = dataSourceID; + } + public FileSearchAction(String title) { super(title); + dataSourceId = null; } @Override public void actionPerformed(ActionEvent e) { FileSearchProvider searcher = Lookup.getDefault().lookup(FileSearchProvider.class); - searcher.showDialog(); + if (dataSourceId == null) { + searcher.showDialog(); + } else { + searcher.showDialog(dataSourceId); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchProvider.java b/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchProvider.java index 991126e2c5..7b2b0cbeed 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchProvider.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchProvider.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"); @@ -23,5 +23,7 @@ package org.sleuthkit.autopsy.directorytree; */ public interface FileSearchProvider { + public void showDialog(long dataSourceID); + public void showDialog(); } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DataSourceFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DataSourceFilter.java index 4ef41b78d8..80f26103fd 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DataSourceFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DataSourceFilter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018 Basis Technology Corp. + * Copyright 2018-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,16 +28,18 @@ class DataSourceFilter extends AbstractFileSearchFilter { /** * Construct DataSourceFilter with the DataSourcePanel + * * @param component A DataSourcePanel */ - public DataSourceFilter(DataSourcePanel component) { + DataSourceFilter(DataSourcePanel component) { super(component); } /** - * Default constructor to construct a new DataSourceFilter with a new DataSourcePanel + * Default constructor to construct a new DataSourceFilter with a new + * DataSourcePanel */ - public DataSourceFilter() { + DataSourceFilter() { this(new DataSourcePanel()); } @@ -46,6 +48,10 @@ class DataSourceFilter extends AbstractFileSearchFilter { return this.getComponent().isSelected(); } + void setSelectedDataSource(long dataSourceId) { + this.getComponent().setDataSourceSelected(dataSourceId); + } + @Override public String getPredicate() throws FilterValidationException { String predicate = ""; @@ -64,11 +70,11 @@ class DataSourceFilter extends AbstractFileSearchFilter { } @Override - @Messages ({ + @Messages({ "DataSourceFilter.errorMessage.emptyDataSource=At least one data source must be selected." }) public boolean isValid() { - if(this.getComponent().getDataSourcesSelected().isEmpty()){ + if (this.getComponent().getDataSourcesSelected().isEmpty()) { setLastError(Bundle.DataSourceFilter_errorMessage_emptyDataSource()); return false; } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DataSourcePanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/DataSourcePanel.java index 28fae71c5b..3bc4df940d 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DataSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DataSourcePanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018 Basis Technology Corp. + * Copyright 2018-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -128,6 +128,19 @@ public class DataSourcePanel extends javax.swing.JPanel { this.dataSourceNoteLabel.setEnabled(enabled); } + /** + * Set the data source initially selected in this filter. + * + * @param dataSourceId - The object ID of the data source which will be + * selected. + */ + void setDataSourceSelected(long dataSourceId) { + this.dataSourceCheckBox.setSelected(true); + setComponentsEnabled(); + String dataSourceName = dataSourceMap.get(dataSourceId); + dataSourceList.setSelectedValue(dataSourceName, true); + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchAction.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchAction.java index da89cea697..bdbcf8a919 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchAction.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchAction.java @@ -32,6 +32,7 @@ final class FileSearchAction extends CallableSystemAction implements FileSearchP private static final long serialVersionUID = 1L; private static FileSearchAction instance = null; private static FileSearchDialog searchDialog; + private static Long selectedDataSourceId; FileSearchAction() { super(); @@ -54,8 +55,9 @@ final class FileSearchAction extends CallableSystemAction implements FileSearchP public void actionPerformed(ActionEvent e) { if (searchDialog == null) { searchDialog = new FileSearchDialog(); - } + //Preserve whatever the previously selected data source was + selectedDataSourceId = null; searchDialog.setVisible(true); } @@ -64,6 +66,8 @@ final class FileSearchAction extends CallableSystemAction implements FileSearchP if (searchDialog == null) { searchDialog = new FileSearchDialog(); } + // + searchDialog.setSelectedDataSourceFilter(selectedDataSourceId); searchDialog.setVisible(true); } @@ -82,8 +86,16 @@ final class FileSearchAction extends CallableSystemAction implements FileSearchP return false; } + @Override + public void showDialog(long dataSourceId) { + selectedDataSourceId = dataSourceId; + performAction(); + + } + @Override public void showDialog() { + selectedDataSourceId = null; performAction(); } } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchDialog.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchDialog.java index de5642496e..5c5f4003f1 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchDialog.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchDialog.java @@ -48,6 +48,10 @@ final class FileSearchDialog extends javax.swing.JDialog { }); } + void setSelectedDataSourceFilter(long dataSourceId){ + fileSearchPanel1.setDataSourceFilter(dataSourceId); + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java index 4801227416..c7d840ee7c 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java @@ -59,6 +59,7 @@ class FileSearchPanel extends javax.swing.JPanel { private final List filters = new ArrayList<>(); private static int resultWindowCount = 0; //keep track of result windows so they get unique names private static final String EMPTY_WHERE_CLAUSE = NbBundle.getMessage(DateSearchFilter.class, "FileSearchPanel.emptyWhereClause.text"); + private static DataSourceFilter dataSourceFilter; enum EVENT { CHECKED @@ -101,7 +102,7 @@ class FileSearchPanel extends javax.swing.JPanel { KnownStatusSearchFilter knowStatusFilter = new KnownStatusSearchFilter(); HashSearchFilter hashFilter = new HashSearchFilter(); MimeTypeFilter mimeTypeFilter = new MimeTypeFilter(); - DataSourceFilter dataSourceFilter = new DataSourceFilter(); + dataSourceFilter = new DataSourceFilter(); panel2.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.name"),nameFilter)); @@ -145,6 +146,10 @@ class FileSearchPanel extends javax.swing.JPanel { searchButton.setEnabled(isValidSearch()); } + void setDataSourceFilter(long dataSourceId){ + dataSourceFilter.setSelectedDataSource(dataSourceId); + } + /** * @return true if any of the filters in the panel are enabled (checked) */ From 8d70a5531506ac4d523011c7fc9ae56a274792e5 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 27 Jul 2021 13:09:42 -0400 Subject: [PATCH 02/76] 3849 update copyright and comments --- .../autopsy/datamodel/ImageNode.java | 2 +- .../datamodel/SpecialDirectoryNode.java | 2 +- .../directorytree/FileSearchAction.java | 2 +- .../autopsy/filesearch/DataSourceFilter.java | 5 ++ .../autopsy/filesearch/FileSearchDialog.java | 20 ++++--- .../autopsy/filesearch/FileSearchPanel.java | 59 ++++++++++--------- 6 files changed, 52 insertions(+), 38 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index feada332a5..f5eed043fa 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012-2019 Basis Technology Corp. + * Copyright 2012-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java index 0cb1046d94..244f9ece70 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017-2019 Basis Technology Corp. + * Copyright 2017-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java index 0cc0bf237d..a3f64f1e13 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchAction.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"); diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DataSourceFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DataSourceFilter.java index 80f26103fd..cb711ca1b0 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DataSourceFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DataSourceFilter.java @@ -48,6 +48,11 @@ class DataSourceFilter extends AbstractFileSearchFilter { return this.getComponent().isSelected(); } + /** + * Set the data source filter to select the specified data source initially. + * + * @param dataSourceId - The data source to select. + */ void setSelectedDataSource(long dataSourceId) { this.getComponent().setDataSourceSelected(dataSourceId); } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchDialog.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchDialog.java index 5c5f4003f1..eb77c7f245 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchDialog.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchDialog.java @@ -1,15 +1,15 @@ /* * 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"); * 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. @@ -48,10 +48,15 @@ final class FileSearchDialog extends javax.swing.JDialog { }); } - void setSelectedDataSourceFilter(long dataSourceId){ + /** + * Set the data source filter to select the specified data source initially. + * + * @param dataSourceId - The data source to select. + */ + void setSelectedDataSourceFilter(long dataSourceId) { fileSearchPanel1.setDataSourceFilter(dataSourceId); } - + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -83,4 +88,3 @@ final class FileSearchDialog extends javax.swing.JDialog { private org.sleuthkit.autopsy.filesearch.FileSearchPanel fileSearchPanel1; // End of variables declaration//GEN-END:variables } - diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java index c7d840ee7c..e1e716269a 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * - * Copyright 2011-2019 Basis Technology Corp. + * + * Copyright 2011-2021 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. @@ -78,39 +78,39 @@ class FileSearchPanel extends javax.swing.JPanel { * This method is called from within the constructor to initialize the form. */ private void customizeComponents() { - + JLabel label = new JLabel(NbBundle.getMessage(this.getClass(), "FileSearchPanel.custComp.label.text")); label.setAlignmentX(Component.LEFT_ALIGNMENT); label.setBorder(new EmptyBorder(0, 0, 10, 0)); - + JPanel panel1 = new JPanel(); - panel1.setLayout(new GridLayout(1,2)); + panel1.setLayout(new GridLayout(1, 2)); panel1.add(new JLabel("")); JPanel panel2 = new JPanel(); - panel2.setLayout(new GridLayout(1,2, 20, 0)); + panel2.setLayout(new GridLayout(1, 2, 20, 0)); JPanel panel3 = new JPanel(); - panel3.setLayout(new GridLayout(1,2, 20, 0)); + panel3.setLayout(new GridLayout(1, 2, 20, 0)); JPanel panel4 = new JPanel(); - panel4.setLayout(new GridLayout(1,2, 20, 0)); + panel4.setLayout(new GridLayout(1, 2, 20, 0)); JPanel panel5 = new JPanel(); - panel5.setLayout(new GridLayout(1,2, 20, 0)); + panel5.setLayout(new GridLayout(1, 2, 20, 0)); // Create and add filter areas - NameSearchFilter nameFilter = new NameSearchFilter(); + NameSearchFilter nameFilter = new NameSearchFilter(); SizeSearchFilter sizeFilter = new SizeSearchFilter(); DateSearchFilter dateFilter = new DateSearchFilter(); KnownStatusSearchFilter knowStatusFilter = new KnownStatusSearchFilter(); HashSearchFilter hashFilter = new HashSearchFilter(); MimeTypeFilter mimeTypeFilter = new MimeTypeFilter(); dataSourceFilter = new DataSourceFilter(); - - panel2.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.name"),nameFilter)); - - panel3.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.metadata"),sizeFilter)); - - panel2.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.metadata"), dateFilter)); + + panel2.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.name"), nameFilter)); + + panel3.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.metadata"), sizeFilter)); + + panel2.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.metadata"), dateFilter)); panel3.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.knownStatus"), knowStatusFilter)); - + panel5.add(new FilterArea(NbBundle.getMessage(this.getClass(), "HashSearchPanel.md5CheckBox.text"), hashFilter)); panel5.add(new JLabel("")); panel4.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.metadata"), mimeTypeFilter)); @@ -120,7 +120,7 @@ class FileSearchPanel extends javax.swing.JPanel { filterPanel.add(panel3); filterPanel.add(panel4); filterPanel.add(panel5); - + filters.add(nameFilter); filters.add(sizeFilter); filters.add(dateFilter); @@ -128,7 +128,7 @@ class FileSearchPanel extends javax.swing.JPanel { filters.add(hashFilter); filters.add(mimeTypeFilter); filters.add(dataSourceFilter); - + for (FileSearchFilter filter : this.getFilters()) { filter.addPropertyChangeListener(new PropertyChangeListener() { @Override @@ -142,14 +142,19 @@ class FileSearchPanel extends javax.swing.JPanel { public void actionPerformed(ActionEvent e) { search(); } - }); + }); searchButton.setEnabled(isValidSearch()); } - void setDataSourceFilter(long dataSourceId){ + /** + * Set the data source filter to select the specified data source initially. + * + * @param dataSourceId - The data source to select. + */ + void setDataSourceFilter(long dataSourceId) { dataSourceFilter.setSelectedDataSource(dataSourceId); } - + /** * @return true if any of the filters in the panel are enabled (checked) */ @@ -205,10 +210,10 @@ class FileSearchPanel extends javax.swing.JPanel { if (contentList.isEmpty()) { Node emptyNode = new TableFilterNode(new EmptyNode(Bundle.FileSearchPanel_emptyNode_display_text()), true); searchResultWin = DataResultTopComponent.createInstance(title, pathText, - emptyNode, 0); + emptyNode, 0); } else { searchResultWin = DataResultTopComponent.createInstance(title, pathText, - tableFilterNode, contentList.size()); + tableFilterNode, contentList.size()); } searchResultWin.requestActive(); // make it the active top component From 9b232ca9f9f0f9bb60eb90b916271c3d11b44e04 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 30 Jul 2021 15:33:00 -0400 Subject: [PATCH 03/76] 3849 address duplicate method comment on github --- .../autopsy/directorytree/FileSearchProvider.java | 13 +++++++------ .../autopsy/filesearch/FileSearchAction.java | 6 +++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchProvider.java b/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchProvider.java index 7b2b0cbeed..523a4a69bd 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchProvider.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/FileSearchProvider.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * + * * Copyright 2011-2021 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. @@ -23,7 +23,8 @@ package org.sleuthkit.autopsy.directorytree; */ public interface FileSearchProvider { - public void showDialog(long dataSourceID); - + public void showDialog(Long dataSourceID); + + @Deprecated public void showDialog(); } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchAction.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchAction.java index d8ba8bdbc5..11d8f94561 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchAction.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchAction.java @@ -90,15 +90,15 @@ final class FileSearchAction extends CallableSystemAction implements FileSearchP } @Override - public void showDialog(long dataSourceId) { + public void showDialog(Long dataSourceId) { selectedDataSourceId = dataSourceId; performAction(); } @Override + @Deprecated public void showDialog() { - selectedDataSourceId = null; - performAction(); + showDialog(null); } } From 22041a8ca6a79c48fb4ee626def3182e989d4bf8 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 4 Aug 2021 15:43:49 -0400 Subject: [PATCH 04/76] Moved RecentFilesSummary into contentutils package --- .../DataSourceInfoUtilities.java | 32 ++--- .../RecentFilesSummary.java | 63 ++++------ .../datamodel/AnalysisSummary.java | 1 + .../datamodel/ContainerSummary.java | 1 + .../datamodel/MimeTypeSummary.java | 1 + .../datamodel/PastCasesSummary.java | 1 + .../datamodel/RecentFilesGetter.java | 113 ++++++++++++++++++ .../datamodel/TypesSummary.java | 1 + .../datamodel/UserActivitySummary.java | 3 +- .../ui/RecentFilesPanel.java | 14 +-- .../DataSourceInfoUtilitiesTest.java | 3 +- .../datamodel/RecentFilesSummaryTest.java | 40 +++---- 12 files changed, 188 insertions(+), 85 deletions(-) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/datamodel => contentutils}/DataSourceInfoUtilities.java (90%) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/datamodel => contentutils}/RecentFilesSummary.java (85%) create mode 100755 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java b/Core/src/org/sleuthkit/autopsy/contentutils/DataSourceInfoUtilities.java similarity index 90% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java rename to Core/src/org/sleuthkit/autopsy/contentutils/DataSourceInfoUtilities.java index c711f3c9a0..8fef1c54f0 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/DataSourceInfoUtilities.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 - 2020 Basis Technology Corp. + * Copyright 2019 - 2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.contentutils; import java.sql.ResultSet; import java.sql.SQLException; @@ -41,7 +41,7 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_META_TYPE_ENUM; * Utilities for getting information about a data source or all data sources * from the case database. */ -final class DataSourceInfoUtilities { +public final class DataSourceInfoUtilities { /** * Gets a count of tsk_files for a particular datasource. @@ -55,7 +55,7 @@ final class DataSourceInfoUtilities { * @throws TskCoreException * @throws SQLException */ - static Long getCountOfTskFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) + public static Long getCountOfTskFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) throws TskCoreException, SQLException { if (currentDataSource != null) { return skCase.countFilesWhere( @@ -77,7 +77,7 @@ final class DataSourceInfoUtilities { * @throws TskCoreException * @throws SQLException */ - static Long getCountOfRegularFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) + public static Long getCountOfRegularFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) throws TskCoreException, SQLException { String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue(); @@ -100,7 +100,7 @@ final class DataSourceInfoUtilities { * @throws TskCoreException * @throws SQLException */ - static Long getCountOfRegNonSlackFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) + public static Long getCountOfRegNonSlackFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) throws TskCoreException, SQLException { String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue() + " AND type<>" + TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType(); @@ -115,7 +115,7 @@ final class DataSourceInfoUtilities { /** * An interface for handling a result set and returning a value. */ - interface ResultSetHandler { + public interface ResultSetHandler { T process(ResultSet resultset) throws SQLException; } @@ -133,7 +133,7 @@ final class DataSourceInfoUtilities { * @throws TskCoreException * @throws SQLException */ - static T getBaseQueryResult(SleuthkitCase skCase, String query, ResultSetHandler processor) + public static T getBaseQueryResult(SleuthkitCase skCase, String query, ResultSetHandler processor) throws TskCoreException, SQLException { try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(query)) { ResultSet resultSet = dbQuery.getResultSet(); @@ -149,14 +149,14 @@ final class DataSourceInfoUtilities { * * @return The clause. */ - static String getMetaFlagsContainsStatement(TSK_FS_META_FLAG_ENUM flag) { + public static String getMetaFlagsContainsStatement(TSK_FS_META_FLAG_ENUM flag) { return "meta_flags & " + flag.getValue() + " > 0"; } /** * Enum for specifying the sort order for getAttributes. */ - enum SortOrder { + public enum SortOrder { DESCENDING, ASCENDING } @@ -181,7 +181,7 @@ final class DataSourceInfoUtilities { * * @throws TskCoreException */ - static List getArtifacts(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, DataSource dataSource, BlackboardAttribute.Type attributeType, SortOrder sortOrder) throws TskCoreException { + public static List getArtifacts(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, DataSource dataSource, BlackboardAttribute.Type attributeType, SortOrder sortOrder) throws TskCoreException { return getArtifacts(skCase, artifactType, dataSource, attributeType, sortOrder, 0); } @@ -207,7 +207,7 @@ final class DataSourceInfoUtilities { * * @throws TskCoreException */ - static List getArtifacts(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, DataSource dataSource, BlackboardAttribute.Type attributeType, SortOrder sortOrder, int maxCount) throws TskCoreException { + public static List getArtifacts(SleuthkitCase skCase, BlackboardArtifact.Type artifactType, DataSource dataSource, BlackboardAttribute.Type attributeType, SortOrder sortOrder, int maxCount) throws TskCoreException { if (maxCount < 0) { throw new IllegalArgumentException("Invalid maxCount passed to getArtifacts, value must be equal to or greater than 0"); } @@ -380,7 +380,7 @@ final class DataSourceInfoUtilities { * @return The 'getValueString()' value or null if the attribute or String * could not be retrieved. */ - static String getStringOrNull(BlackboardArtifact artifact, Type attributeType) { + public static String getStringOrNull(BlackboardArtifact artifact, Type attributeType) { BlackboardAttribute attr = getAttributeOrNull(artifact, attributeType); return (attr == null) ? null : attr.getValueString(); } @@ -394,7 +394,7 @@ final class DataSourceInfoUtilities { * @return The 'getValueLong()' value or null if the attribute could not be * retrieved. */ - static Long getLongOrNull(BlackboardArtifact artifact, Type attributeType) { + public static Long getLongOrNull(BlackboardArtifact artifact, Type attributeType) { BlackboardAttribute attr = getAttributeOrNull(artifact, attributeType); return (attr == null) ? null : attr.getValueLong(); } @@ -408,7 +408,7 @@ final class DataSourceInfoUtilities { * @return The 'getValueInt()' value or null if the attribute could not be * retrieved. */ - static Integer getIntOrNull(BlackboardArtifact artifact, Type attributeType) { + public static Integer getIntOrNull(BlackboardArtifact artifact, Type attributeType) { BlackboardAttribute attr = getAttributeOrNull(artifact, attributeType); return (attr == null) ? null : attr.getValueInt(); } @@ -423,7 +423,7 @@ final class DataSourceInfoUtilities { * @return The date determined from the 'getValueLong()' as seconds from * epoch or null if the attribute could not be retrieved or is 0. */ - static Date getDateOrNull(BlackboardArtifact artifact, Type attributeType) { + public static Date getDateOrNull(BlackboardArtifact artifact, Type attributeType) { Long longVal = getLongOrNull(artifact, attributeType); return (longVal == null || longVal == 0) ? null : new Date(longVal * 1000); } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java similarity index 85% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java rename to Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java index 4f1a34fa73..62b80516cd 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,9 +16,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.contentutils; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; import java.nio.file.Paths; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -33,6 +32,8 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.lang.StringUtils; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -40,13 +41,12 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; /** - * Helper class for getting data for the Recent Files Data Summary tab. + * Helper class for getting Recent Activity data. */ -public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { +public class RecentFilesSummary { private final static BlackboardAttribute.Type DATETIME_ACCESSED_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED); private final static BlackboardAttribute.Type DOMAIN_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN); @@ -66,30 +66,13 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() )); - private final SleuthkitCaseProvider provider; - /** * Default constructor. */ - public RecentFilesSummary() { - this(SleuthkitCaseProvider.DEFAULT); + private RecentFilesSummary() { } - /** - * Construct object with given SleuthkitCaseProvider - * - * @param provider SleuthkitCaseProvider provider, cannot be null. - */ - public RecentFilesSummary(SleuthkitCaseProvider provider) { - if (provider == null) { - throw new IllegalArgumentException("Unable to construct RecentFileSummary object. SleuthkitCaseProvider cannot be null"); - } - - this.provider = provider; - } - - @Override - public Set getArtifactTypeIdsForRefresh() { + public static Set getArtifactTypeIdsForRefresh() { return ARTIFACT_UPDATE_TYPE_IDS; } @@ -101,7 +84,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * @param limit The maximum number of entries to return. * @return The sorted limited list with unique paths. */ - private List getSortedLimited(List fileDetails, int limit) { + private static List getSortedLimited(List fileDetails, int limit) { Map fileDetailsMap = fileDetails.stream() .filter(details -> details != null) .collect(Collectors.toMap( @@ -122,7 +105,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * @param artifact The artifact. * @return The derived object or null if artifact is invalid. */ - private RecentFileDetails getRecentlyOpenedDocument(BlackboardArtifact artifact) { + private static RecentFileDetails getRecentlyOpenedDocument(BlackboardArtifact artifact) { String path = DataSourceInfoUtilities.getStringOrNull(artifact, PATH_ATT); Long lastOpened = DataSourceInfoUtilities.getLongOrNull(artifact, DATETIME_ACCESSED_ATT); @@ -144,17 +127,17 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * @return A list RecentFileDetails representing the most recently opened * documents or an empty list if none were found. * - * @throws SleuthkitCaseProviderException + * @throws NoCurrentCaseException * @throws TskCoreException */ - public List getRecentlyOpenedDocuments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException { + public static List getRecentlyOpenedDocuments(DataSource dataSource, int maxCount) throws TskCoreException, NoCurrentCaseException { if (dataSource == null) { return Collections.emptyList(); } throwOnNonPositiveCount(maxCount); - List details = provider.get().getBlackboard() + List details = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard() .getArtifacts(ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID(), dataSource.getId()).stream() .map(art -> getRecentlyOpenedDocument(art)) .filter(d -> d != null) @@ -170,7 +153,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * @param artifact The artifact. * @return The derived object or null if artifact is invalid. */ - private RecentDownloadDetails getRecentDownload(BlackboardArtifact artifact) { + private static RecentDownloadDetails getRecentDownload(BlackboardArtifact artifact) { Long accessedTime = DataSourceInfoUtilities.getLongOrNull(artifact, DATETIME_ACCESSED_ATT); String domain = DataSourceInfoUtilities.getStringOrNull(artifact, DOMAIN_ATT); String path = DataSourceInfoUtilities.getStringOrNull(artifact, PATH_ATT); @@ -187,7 +170,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * * @param count The count. */ - private void throwOnNonPositiveCount(int count) { + private static void throwOnNonPositiveCount(int count) { if (count < 1) { throw new IllegalArgumentException("Invalid count: value must be greater than 0."); } @@ -205,16 +188,16 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * found. * * @throws TskCoreException - * @throws SleuthkitCaseProviderException + * @throws NoCurrentCaseException */ - public List getRecentDownloads(DataSource dataSource, int maxCount) throws TskCoreException, SleuthkitCaseProviderException { + public static List getRecentDownloads(DataSource dataSource, int maxCount) throws TskCoreException, NoCurrentCaseException { if (dataSource == null) { return Collections.emptyList(); } throwOnNonPositiveCount(maxCount); - List details = provider.get().getBlackboard() + List details = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard() .getArtifacts(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID(), dataSource.getId()).stream() .map(art -> getRecentDownload(art)) .filter(d -> d != null) @@ -232,17 +215,17 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * * @return A list of RecentFileDetails of the most recent attachments. * - * @throws SleuthkitCaseProviderException + * @throws NoCurrentCaseException * @throws TskCoreException */ - public List getRecentAttachments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException { + public static List getRecentAttachments(DataSource dataSource, int maxCount) throws NoCurrentCaseException, TskCoreException { if (dataSource == null) { return Collections.emptyList(); } throwOnNonPositiveCount(maxCount); - SleuthkitCase skCase = provider.get(); + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); List associatedArtifacts = skCase.getBlackboard() .getArtifacts(ASSOCATED_OBJ_ART.getTypeID(), dataSource.getId()); @@ -268,7 +251,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * @return The derived object or null. * @throws TskCoreException */ - private RecentAttachmentDetails getRecentAttachment(BlackboardArtifact artifact, SleuthkitCase skCase) throws TskCoreException { + private static RecentAttachmentDetails getRecentAttachment(BlackboardArtifact artifact, SleuthkitCase skCase) throws TskCoreException { // get associated artifact or return no result BlackboardAttribute attribute = artifact.getAttribute(ASSOCATED_ATT); if (attribute == null) { @@ -309,7 +292,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor { * * @return True if the given artifact is a message artifact */ - private boolean isMessageArtifact(BlackboardArtifact nodeArtifact) { + private static boolean isMessageArtifact(BlackboardArtifact nodeArtifact) { final int artifactTypeID = nodeArtifact.getArtifactTypeID(); return artifactTypeID == ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java index 5fff3eac6c..db9bc067c2 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java @@ -30,6 +30,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; +import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java index 8129911500..eb11b99b2a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java @@ -24,6 +24,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java index e753a44a76..1b8ac3fc1c 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java index ea6c089fca..e7776fbf62 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java @@ -32,6 +32,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; +import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java new file mode 100755 index 0000000000..446659ebef --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java @@ -0,0 +1,113 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020-2021 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.datasourcesummary.datamodel; + +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; +import java.util.List; +import java.util.Set; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.contentutils.RecentFilesSummary; +import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentAttachmentDetails; +import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentDownloadDetails; +import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentFileDetails; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; + +/** + * Wrapper class for converting org.sleuthkit.autopsy.contentutils.RecentFilesSummary functionality into + * a DefaultArtifactUpdateGovernor used by Recent Files Data Summary tab. + */ +public class RecentFilesGetter implements DefaultArtifactUpdateGovernor { + + /** + * Default constructor. + */ + public RecentFilesGetter() { + } + + @Override + public Set getArtifactTypeIdsForRefresh() { + return RecentFilesSummary.getArtifactTypeIdsForRefresh(); + } + + /** + * Return a list of the most recently opened documents based on the + * TSK_RECENT_OBJECT artifact. + * + * @param dataSource The data source to query. + * @param maxCount The maximum number of results to return, pass 0 to get a + * list of all results. + * + * @return A list RecentFileDetails representing the most recently opened + * documents or an empty list if none were found. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + */ + public List getRecentlyOpenedDocuments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException { + try { + return RecentFilesSummary.getRecentlyOpenedDocuments(dataSource, maxCount); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } + + /** + * Return a list of the most recent downloads based on the value of the the + * artifact TSK_DATETIME_ACCESSED attribute. + * + * @param dataSource Data source to query. + * @param maxCount Maximum number of results to return, passing 0 will + * return all results. + * + * @return A list of RecentFileDetails objects or empty list if none were + * found. + * + * @throws TskCoreException + * @throws SleuthkitCaseProviderException + */ + public List getRecentDownloads(DataSource dataSource, int maxCount) throws TskCoreException, SleuthkitCaseProviderException { + try { + return RecentFilesSummary.getRecentDownloads(dataSource, maxCount); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } + + /** + * Returns a list of the most recent message attachments. + * + * @param dataSource Data source to query. + * @param maxCount Maximum number of results to return, passing 0 will + * return all results. + * + * @return A list of RecentFileDetails of the most recent attachments. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + */ + public List getRecentAttachments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException { + try { + return RecentFilesSummary.getRecentAttachments(dataSource, maxCount); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java index ff4bcae0a0..3b21654c14 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java @@ -23,6 +23,7 @@ import java.sql.SQLException; import java.util.Arrays; import java.util.HashSet; import java.util.Set; +import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java index 10f700d51f..5151617775 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,6 +39,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.DataSource; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index f89651072c..44d916992f 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,10 +30,10 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesGetter; +import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentAttachmentDetails; +import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentDownloadDetails; +import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentFileDetails; import static org.sleuthkit.autopsy.datasourcesummary.ui.BaseDataSourceSummaryPanel.getTableExport; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; @@ -120,13 +120,13 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { "RecentFilePanel_emailParserModuleName=Email Parser" }) public RecentFilesPanel() { - this(new RecentFilesSummary()); + this(new RecentFilesGetter()); } /** * Creates new form RecentFilesPanel */ - public RecentFilesPanel(RecentFilesSummary dataHandler) { + public RecentFilesPanel(RecentFilesGetter dataHandler) { super(dataHandler); docsFetcher = (dataSource) -> dataHandler.getRecentlyOpenedDocuments(dataSource, 10); downloadsFetcher = (dataSource) -> dataHandler.getRecentDownloads(dataSource, 10); diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilitiesTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilitiesTest.java index 1b5d809b1f..5179b4a509 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilitiesTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilitiesTest.java @@ -27,7 +27,7 @@ import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceInfoUtilities.SortOrder; +import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities.SortOrder; import org.sleuthkit.datamodel.Blackboard; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -36,6 +36,7 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.testutils.TskMockUtils; import static org.mockito.Mockito.*; +import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; import org.sleuthkit.autopsy.testutils.RandomizationUtils; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java index 0acda3954a..302223a234 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java @@ -40,9 +40,9 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails; +import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentAttachmentDetails; +import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentDownloadDetails; +import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentFileDetails; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.testutils.RandomizationUtils; import org.sleuthkit.autopsy.testutils.TskMockUtils; @@ -62,15 +62,15 @@ import org.sleuthkit.datamodel.TskCoreException; public class RecentFilesSummaryTest { /** - * An interface for calling methods in RecentFilesSummary in a uniform - * manner. + * An interface for calling methods in RecentFilesGetter in a uniform + manner. */ private interface RecentFilesMethod { /** - * Means of acquiring data from a method in RecentFilesSummary. + * Means of acquiring data from a method in RecentFilesGetter. * - * @param recentFilesSummary The RecentFilesSummary object. + * @param recentFilesSummary The RecentFilesGetter object. * @param dataSource The datasource. * @param count The number of items to retrieve. * @@ -79,7 +79,7 @@ public class RecentFilesSummaryTest { * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - List fetch(RecentFilesSummary recentFilesSummary, DataSource dataSource, int count) + List fetch(RecentFilesGetter recentFilesSummary, DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException; } @@ -105,7 +105,7 @@ public class RecentFilesSummaryTest { throws TskCoreException, SleuthkitCaseProviderException { Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(null); DataSource dataSource = TskMockUtils.getDataSource(1); - RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); + RecentFilesGetter summary = new RecentFilesGetter(); try { method.fetch(summary, dataSource, -1); @@ -146,7 +146,7 @@ public class RecentFilesSummaryTest { throws SleuthkitCaseProviderException, TskCoreException { Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(null); - RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); + RecentFilesGetter summary = new RecentFilesGetter(); List items = recentFilesMethod.fetch(summary, null, 10); Assert.assertNotNull("Expected method " + methodName + " to return an empty list.", items); @@ -184,7 +184,7 @@ public class RecentFilesSummaryTest { throws SleuthkitCaseProviderException, TskCoreException { Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(Collections.emptyList()); - RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); + RecentFilesGetter summary = new RecentFilesGetter(); DataSource dataSource = TskMockUtils.getDataSource(1); List items = recentFilesMethod.fetch(summary, dataSource, 10); Assert.assertNotNull("Expected method " + methodName + " to return an empty list.", items); @@ -278,7 +278,7 @@ public class RecentFilesSummaryTest { // run through method Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(RandomizationUtils.getMixedUp(artifacts)); - RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); + RecentFilesGetter summary = new RecentFilesGetter(); List results = summary.getRecentlyOpenedDocuments(dataSource, countRequest); // verify results @@ -302,7 +302,7 @@ public class RecentFilesSummaryTest { List artifacts = Arrays.asList(item2, item3, item1); Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(RandomizationUtils.getMixedUp(artifacts)); - RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); + RecentFilesGetter summary = new RecentFilesGetter(); List results = summary.getRecentlyOpenedDocuments(dataSource, 10); // verify results (only successItem) @@ -322,7 +322,7 @@ public class RecentFilesSummaryTest { List artifacts = Arrays.asList(nullTime, zeroTime, successItem); Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(RandomizationUtils.getMixedUp(artifacts)); - RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); + RecentFilesGetter summary = new RecentFilesGetter(); List results = summary.getRecentlyOpenedDocuments(dataSource, 10); // verify results (only successItem) @@ -373,7 +373,7 @@ public class RecentFilesSummaryTest { // call method Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(RandomizationUtils.getMixedUp(artifacts)); - RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); + RecentFilesGetter summary = new RecentFilesGetter(); List results = summary.getRecentDownloads(dataSource, countRequest); // verify results @@ -399,7 +399,7 @@ public class RecentFilesSummaryTest { List artifacts = Arrays.asList(item2, item3, item1); Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(RandomizationUtils.getMixedUp(artifacts)); - RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); + RecentFilesGetter summary = new RecentFilesGetter(); // call method List results = summary.getRecentDownloads(dataSource, 10); @@ -422,7 +422,7 @@ public class RecentFilesSummaryTest { List artifacts = Arrays.asList(nullTime, zeroTime, successItem); Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(RandomizationUtils.getMixedUp(artifacts)); - RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); + RecentFilesGetter summary = new RecentFilesGetter(); // call method List results = summary.getRecentDownloads(dataSource, 10); @@ -651,7 +651,7 @@ public class RecentFilesSummaryTest { List mixedUpItems = RandomizationUtils.getMixedUp(items); Pair casePair = getRecentAttachmentArtifactCase(mixedUpItems); - RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); + RecentFilesGetter summary = new RecentFilesGetter(); // retrieve results List results = summary.getRecentAttachments(dataSource, countRequest); @@ -698,7 +698,7 @@ public class RecentFilesSummaryTest { noParentFile, noAssocAttr, missingAssocArt); Pair casePair = getRecentAttachmentArtifactCase(items); - RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); + RecentFilesGetter summary = new RecentFilesGetter(); // get data List results = summary.getRecentAttachments(dataSource, 10); @@ -735,7 +735,7 @@ public class RecentFilesSummaryTest { List items = Arrays.asList(item1, item2, item3); Pair casePair = getRecentAttachmentArtifactCase(items); - RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); + RecentFilesGetter summary = new RecentFilesGetter(); // get data List results = summary.getRecentAttachments(dataSource, 10); From d1605852d94d53e7fc3779790169a8a02a7f3fb2 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 4 Aug 2021 19:00:54 -0400 Subject: [PATCH 05/76] Moved Excel export functionality and classes into report module --- .../datasourcesummary/ui/AnalysisPanel.java | 6 +- .../ui/BaseDataSourceSummaryPanel.java | 30 ++-- .../ui/Bundle.properties-MERGED | 33 ---- .../datasourcesummary/ui/ContainerPanel.java | 15 +- .../ui/DataSourceSummaryTabbedPane.java | 40 +---- .../ui/GeolocationPanel.java | 4 +- .../ui/IngestJobExcelExport.java | 5 +- .../datasourcesummary/ui/PastCasesPanel.java | 7 +- .../ui/RecentFilesPanel.java | 7 +- .../datasourcesummary/ui/TimelinePanel.java | 8 +- .../datasourcesummary/ui/TypesPanel.java | 12 +- .../ui/UserActivityPanel.java | 7 +- .../uiutils/Bundle.properties-MERGED | 2 - .../uiutils/DefaultCellModel.java | 7 +- .../uiutils/ExcelCellModel.java | 32 ---- .../BarChartExport.java | 14 +- .../BarChartSeries.java | 101 ++++++++++++ .../datasourcesummaryexport/Bundle.properties | 3 + .../Bundle.properties-MERGED | 18 +++ .../datasourcesummaryexport/ColumnModel.java | 80 ++++++++++ .../DataSourceSummaryReport.java | 117 ++++++++++++++ .../DefaultCellModel.java | 149 ++++++++++++++++++ .../datasourcesummaryexport}/ExcelExport.java | 6 +- .../ExcelExportAction.java | 7 +- .../ExcelExportDialog.form | 3 - .../ExcelExportDialog.java | 2 +- .../ExcelSpecialFormatExport.java | 16 +- .../ExcelTableExport.java | 18 +-- .../datasourcesummaryexport}/ExportPanel.form | 0 .../datasourcesummaryexport}/ExportPanel.java | 2 +- .../PieChartExport.java | 12 +- .../datasourcesummaryexport/PieChartItem.java | 67 ++++++++ 32 files changed, 612 insertions(+), 218 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ExcelCellModel.java rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/uiutils => report/modules/datasourcesummaryexport}/BarChartExport.java (95%) create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartSeries.java create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ColumnModel.java create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DefaultCellModel.java rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/uiutils => report/modules/datasourcesummaryexport}/ExcelExport.java (98%) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/ui => report/modules/datasourcesummaryexport}/ExcelExportAction.java (97%) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/ui => report/modules/datasourcesummaryexport}/ExcelExportDialog.form (97%) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/ui => report/modules/datasourcesummaryexport}/ExcelExportDialog.java (98%) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/uiutils => report/modules/datasourcesummaryexport}/ExcelSpecialFormatExport.java (93%) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/uiutils => report/modules/datasourcesummaryexport}/ExcelTableExport.java (84%) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/ui => report/modules/datasourcesummaryexport}/ExportPanel.form (100%) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/ui => report/modules/datasourcesummaryexport}/ExportPanel.java (98%) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/uiutils => report/modules/datasourcesummaryexport}/PieChartExport.java (93%) create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartItem.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index 736dce7f3c..99da8fbd5a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -21,8 +21,6 @@ package org.sleuthkit.autopsy.datasourcesummary.ui; import java.util.Arrays; import java.util.List; import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummary; @@ -30,7 +28,6 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; import org.sleuthkit.datamodel.DataSource; @@ -229,6 +226,7 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { ); }// //GEN-END:initComponents + /* ELODO @Override List getExports(DataSource dataSource) { return Stream.of( @@ -237,7 +235,7 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { getTableExport(interestingItemsFetcher, DEFAULT_COLUMNS, Bundle.AnalysisPanel_interestingItemHits_tabName(), dataSource)) .filter(sheet -> sheet != null) .collect(Collectors.toList()); - } + }*/ // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index 01773e5626..97965ec9e8 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -44,10 +44,6 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.EventUpdateHandler; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelExportException; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelTableExport; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelCellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.DefaultMenuItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.MenuItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; @@ -453,14 +449,6 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { */ protected abstract void onNewDataSource(DataSource dataSource); - /** - * Returns all the excel exportable items associated with the tab. - * - * @param dataSource The data source that results should be filtered. - * @return The excel exportable objects. - */ - abstract List getExports(DataSource dataSource); - /** * Runs a data fetcher and returns the result handling any possible errors * with a log message. @@ -488,7 +476,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { /** * Function that converts data into a excel sheet data. */ - protected interface ExcelExportFunction { + // ELTODO protected interface ExcelExportFunction { /** * Function that converts data into an excel sheet. @@ -497,8 +485,8 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * @return The excel sheet export. * @throws ExcelExportException */ - ExcelSheetExport convert(T data) throws ExcelExportException; - } + // ExcelSheetExport convert(T data) throws ExcelExportException; + //} /** * Helper method that converts data into an excel sheet export handling @@ -510,6 +498,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * message). * @return The excel sheet export. */ + /* ELTODO protected static ExcelSheetExport convertToExcel(ExcelExportFunction excelConverter, T data, String sheetName) { if (data == null) { return null; @@ -523,7 +512,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { sheetName == null ? "" : sheetName), ex); return null; } - } + }*/ /** * Returns an excel sheet export given the fetching of data or null if no @@ -535,13 +524,14 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * @param ds The data source to use for fetching data. * @return The excel sheet export or null if no export could be generated. */ + /* ELTODO protected static ExcelSheetExport getExport( DataFetcher dataFetcher, ExcelExportFunction excelConverter, String sheetName, DataSource ds) { T data = getFetchResult(dataFetcher, sheetName, ds); return convertToExcel(excelConverter, data, sheetName); - } + }*/ /** * Returns an excel table export of the data or null if no export created. @@ -551,13 +541,14 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * @param data The data to be exported. * @return The excel table export or null if no export could be generated. */ + /* ELTODO protected static ExcelSheetExport getTableExport(List> columnsModel, String sheetName, List data) { return convertToExcel((dataList) -> new ExcelTableExport(sheetName, columnsModel, dataList), data, sheetName); - } + }*/ /** * Returns an excel table export of the data or null if no export created. @@ -569,6 +560,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { * @param ds The data source. * @return The excel export or null if no export created. */ + /* ELTODO protected static ExcelSheetExport getTableExport( DataFetcher> dataFetcher, List> columnsModel, String sheetName, DataSource ds) { @@ -577,7 +569,7 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { (dataList) -> new ExcelTableExport(sheetName, columnsModel, dataList), sheetName, ds); - } + }*/ /** * Utility method that shows a loading screen with loadable components, diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED index a7b3c8870c..2f5056ae25 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -6,19 +6,6 @@ AnalysisPanel_keywordHits_tabName=Keyword Hits AnalysisPanel_keywordSearchModuleName=Keyword Search BaseDataSourceSummaryPanel_goToArtifact=View Source Result BaseDataSourceSummaryPanel_goToFile=View Source File in Directory -ContainerPanel_export_acquisitionDetails=Acquisition Details: -ContainerPanel_export_deviceId=Device ID: -ContainerPanel_export_displayName=Display Name: -ContainerPanel_export_filePaths=File Paths: -ContainerPanel_export_imageType=Image Type: -ContainerPanel_export_md5=MD5: -ContainerPanel_export_originalName=Name: -ContainerPanel_export_sectorSize=Sector Size: -ContainerPanel_export_sha1=SHA1: -ContainerPanel_export_sha256=SHA256: -ContainerPanel_export_size=Size: -ContainerPanel_export_timeZone=Time Zone: -ContainerPanel_export_unallocatedSize=Unallocated Space: ContainerPanel_setFieldsForNonImageDataSource_na=N/A ContainerPanel_tabName=Container CTL_DataSourceSummaryAction=Data Source Summary @@ -62,7 +49,6 @@ DataSourceSummaryNode.column.type.header=Type DataSourceSummaryNode.viewDataSourceAction.text=Go to Data Source DataSourceSummaryTabbedPane_analysisTab_title=Analysis DataSourceSummaryTabbedPane_detailsTab_title=Container -DataSourceSummaryTabbedPane_exportTab_title=Export DataSourceSummaryTabbedPane_geolocationTab_title=Geolocation DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History DataSourceSummaryTabbedPane_pastCasesTab_title=Past Cases @@ -70,19 +56,6 @@ DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files DataSourceSummaryTabbedPane_timelineTab_title=Timeline DataSourceSummaryTabbedPane_typesTab_title=Types DataSourceSummaryTabbedPane_userActivityTab_title=User Activity -ExcelExportAction_exportToXLSX_beginExport=Beginning Export... -# {0} - tabName -ExcelExportAction_exportToXLSX_gatheringTabData=Fetching Data for {0} Tab... -ExcelExportAction_exportToXLSX_writingToFile=Writing to File... -ExcelExportAction_getXLSXPath_directory=DataSourceSummary -ExcelExportAction_moduleName=Data Source Summary -ExcelExportAction_runXLSXExport_errorMessage=There was an error while exporting. -ExcelExportAction_runXLSXExport_errorTitle=Error While Exporting -ExcelExportAction_runXLSXExport_progressCancelActionTitle=Cancelling... -ExcelExportAction_runXLSXExport_progressCancelTitle=Cancel -# {0} - dataSource -ExcelExportAction_runXLSXExport_progressTitle=Exporting {0} to XLSX -ExcelExportDialog_title=Data Source Summary Exported GeolocationPanel_cityColumn_title=Closest City GeolocationPanel_countColumn_title=Count GeolocationPanel_mostCommon_tabName=Most Common Cities @@ -116,12 +89,6 @@ SizeRepresentationUtil_units_megabytes=MB SizeRepresentationUtil_units_petabytes=PB SizeRepresentationUtil_units_terabytes=TB TimelinePanel_earliestLabel_title=Earliest -TimelinePanel_getExports_activityRange=Activity Range -TimelinePanel_getExports_chartName=Last 30 Days -TimelinePanel_getExports_dateColumnHeader=Date -TimelinePanel_getExports_earliest=Earliest: -TimelinePanel_getExports_latest=Latest: -TimelinePanel_getExports_sheetName=Timeline TimelinePanel_latestLabel_title=Latest TimlinePanel_last30DaysChart_artifactEvts_title=Result Events TimlinePanel_last30DaysChart_fileEvts_title=File Events diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java index a8e5fef64e..0fc66a4c72 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java @@ -36,18 +36,10 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import static org.sleuthkit.autopsy.datasourcesummary.ui.BaseDataSourceSummaryPanel.getFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ExcelItemExportable; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.KeyValueItemExportable; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.SingleCellExportable; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.TitledExportable; import org.sleuthkit.autopsy.datasourcesummary.uiutils.UpdateGovernor; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.Image; @@ -488,6 +480,7 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { * @return The list of key value pairs that can be incorporated into the * excel export. */ + /* ELODO private static List getAcquisitionDetails(String acquisitionDetails) { if (StringUtils.isBlank(acquisitionDetails)) { return Collections.emptyList(); @@ -497,9 +490,9 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { .filter(item -> item != null) .collect(Collectors.toList()); } - } + }*/ - @Override + /* ELODO @Messages({ "ContainerPanel_export_displayName=Display Name:", "ContainerPanel_export_originalName=Name:", @@ -556,7 +549,7 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { new TitledExportable(Bundle.ContainerPanel_export_filePaths(), cellPaths) ))); - } + }*/ /** * This method is called from within the constructor to initialize the form. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java index 146863b58e..af53ab9260 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java @@ -25,12 +25,9 @@ import java.util.Arrays; import java.util.EnumSet; import java.util.List; import java.util.function.Consumer; -import java.util.function.Function; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.IngestJobInfoPanel; -import org.sleuthkit.autopsy.datasourcesummary.ui.ExcelExportAction.ExportableTab; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport; import org.sleuthkit.datamodel.DataSource; /** @@ -46,8 +43,7 @@ import org.sleuthkit.datamodel.DataSource; "DataSourceSummaryTabbedPane_pastCasesTab_title=Past Cases", "DataSourceSummaryTabbedPane_analysisTab_title=Analysis", "DataSourceSummaryTabbedPane_geolocationTab_title=Geolocation", - "DataSourceSummaryTabbedPane_timelineTab_title=Timeline", - "DataSourceSummaryTabbedPane_exportTab_title=Export" + "DataSourceSummaryTabbedPane_timelineTab_title=Timeline" }) public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { @@ -55,12 +51,11 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { * Records of tab information (i.e. title, component, function to call on * new data source). */ - private class DataSourceTab implements ExportableTab { + private class DataSourceTab { private final String tabTitle; private final Component component; private final Consumer onDataSource; - private final Function> excelExporter; private final Runnable onClose; private final Runnable onInit; @@ -71,7 +66,7 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { * @param panel The component to be displayed in the tab. */ DataSourceTab(String tabTitle, BaseDataSourceSummaryPanel panel) { - this(tabTitle, panel, panel::setDataSource, panel::getExports, panel::close, panel::init); + this(tabTitle, panel, panel::setDataSource, panel::close, panel::init); panel.setParentCloseListener(() -> notifyParentClose()); } @@ -90,12 +85,10 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { * added to the tabbed pane. */ DataSourceTab(String tabTitle, Component component, Consumer onDataSource, - Function> excelExporter, Runnable onClose, - Runnable onInit) { + Runnable onClose, Runnable onInit) { this.tabTitle = tabTitle; this.component = component; this.onDataSource = onDataSource; - this.excelExporter = excelExporter; this.onClose = onClose; this.onInit = onInit; } @@ -103,7 +96,6 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { /** * @return The title for the tab. */ - @Override public String getTabTitle() { return tabTitle; } @@ -122,11 +114,6 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { return onDataSource; } - @Override - public List getExcelExports(DataSource dataSource) { - return excelExporter == null ? null : excelExporter.apply(dataSource); - } - /** * @return The action for closing resources in the tab. */ @@ -152,9 +139,6 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { private Runnable notifyParentClose = null; private final IngestJobInfoPanel ingestHistoryPanel = new IngestJobInfoPanel(); - // create an export panel whose button triggers the export to XLSX action - private final ExportPanel exportPanel = new ExportPanel(); - private final List tabs = Arrays.asList( new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_typesTab_title(), new TypesPanel()), new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_userActivityTab_title(), new UserActivityPanel()), @@ -168,22 +152,11 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { Bundle.DataSourceSummaryTabbedPane_ingestHistoryTab_title(), ingestHistoryPanel, ingestHistoryPanel::setDataSource, - IngestJobExcelExport::getExports, null, null), - new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new ContainerPanel()), - new DataSourceTab( - Bundle.DataSourceSummaryTabbedPane_exportTab_title(), - exportPanel, - null, - null, - null, - null) + new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new ContainerPanel()) ); - // the action that does the export - private final ExcelExportAction exportAction = new ExcelExportAction(tabs); - private DataSource dataSource = null; private CardLayout cardLayout; @@ -243,9 +216,6 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel { // set this to no datasource initially cardLayout.show(this, NO_DATASOURCE_PANE); - - // set action for when user requests xlsx export - exportPanel.setXlsxExportAction(() -> exportAction.accept(getDataSource())); } /** diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java index be7279afca..fd3ad98dcc 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java @@ -45,7 +45,6 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; import org.sleuthkit.autopsy.geolocation.GeoFilter; @@ -349,6 +348,7 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel { onNewDataSource(dataFetchComponents, tables, dataSource); } + /* ELODO @Override List getExports(DataSource dataSource) { GeolocationViewModel model = getFetchResult(geolocationFetcher, "Geolocation sheets", dataSource); @@ -360,7 +360,7 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel { getTableExport(DEFAULT_TEMPLATE, Bundle.GeolocationPanel_mostRecent_tabName(), model.getMostRecentData()), getTableExport(DEFAULT_TEMPLATE, Bundle.GeolocationPanel_mostCommon_tabName(), model.getMostCommonData()) ); - } + }*/ @Override public void close() { diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/IngestJobExcelExport.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/IngestJobExcelExport.java index 3ad757e7be..07d789c0fa 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/IngestJobExcelExport.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/IngestJobExcelExport.java @@ -36,8 +36,6 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelTableExport; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; import org.sleuthkit.datamodel.IngestModuleInfo; @@ -211,6 +209,7 @@ class IngestJobExcelExport { * @param dataSource The data source. * @return The list of sheets to be included in an export. */ + /* ELODO static List getExports(DataSource dataSource) { if (dataSource == null) { return Collections.emptyList(); @@ -246,7 +245,7 @@ class IngestJobExcelExport { .collect(Collectors.toList()); return Arrays.asList(new ExcelTableExport<>(Bundle.IngestJobExcelExport_sheetName(), COLUMNS, toDisplay)); - } + }*/ private IngestJobExcelExport() { } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index a3169db375..d49bcfdff0 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -19,21 +19,17 @@ package org.sleuthkit.autopsy.datasourcesummary.ui; import java.util.Arrays; -import java.util.Collections; import java.util.List; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.PastCasesResult; -import static org.sleuthkit.autopsy.datasourcesummary.ui.BaseDataSourceSummaryPanel.getFetchResult; -import static org.sleuthkit.autopsy.datasourcesummary.ui.BaseDataSourceSummaryPanel.getTableExport; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; import org.sleuthkit.datamodel.DataSource; @@ -128,6 +124,7 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { onNewDataSource(dataFetchComponents, tables, dataSource); } + /* ELODO @Override List getExports(DataSource dataSource) { PastCasesResult result = getFetchResult(pastCasesFetcher, "Past cases sheets", dataSource); @@ -139,7 +136,7 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { getTableExport(DEFAULT_TEMPLATE, Bundle.PastCasesPanel_notableFileTable_tabName(), result.getTaggedNotable()), getTableExport(DEFAULT_TEMPLATE, Bundle.PastCasesPanel_sameIdsTable_tabName(), result.getSameIdsResults()) ); - } + }*/ @Override public void close() { diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index 44d916992f..6bb0ba78af 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -27,20 +27,16 @@ import java.util.List; import java.util.Locale; import java.util.function.Function; import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesGetter; import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentAttachmentDetails; import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentDownloadDetails; import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentFileDetails; -import static org.sleuthkit.autopsy.datasourcesummary.ui.BaseDataSourceSummaryPanel.getTableExport; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport; import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.MenuItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; @@ -190,6 +186,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { onNewDataSource(dataFetchComponents, tablePanelList, dataSource); } + /* ELODO @Override List getExports(DataSource dataSource) { return Stream.of( @@ -198,7 +195,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { getTableExport(attachmentsFetcher, attachmentsTemplate, Bundle.RecentFilesPanel_attachmentsTable_tabName(), dataSource)) .filter(sheet -> sheet != null) .collect(Collectors.toList()); - } + }*/ @Override public void close() { diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java index 94af4b7545..d2dfb8d261 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java @@ -39,7 +39,6 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineDataSourceUtils import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartExport; import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries; import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.OrderedKey; @@ -49,10 +48,6 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.KeyValueItemExportable; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.TitledExportable; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel; @@ -304,6 +299,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { return new DefaultCellModel<>(date, (dt) -> dt == null ? "" : EARLIEST_LATEST_FORMAT.format(dt), EARLIEST_LATEST_FORMAT_STR); } + /* ELODO @Messages({ "TimelinePanel_getExports_sheetName=Timeline", "TimelinePanel_getExports_activityRange=Activity Range", @@ -328,7 +324,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { "#,###", Bundle.TimelinePanel_getExports_chartName(), parseChartData(summaryData.getMostRecentDaysActivity(), true))))); - } + }*/ /** * This method is called from within the constructor to initialize the form. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index e11e638459..3f1b19e1a4 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -40,14 +40,9 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultTyp import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.KeyValueItemExportable; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartExport; import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartPanel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartItem; @@ -421,7 +416,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { * @param dataSource The data source containing the data. * @return The key value pair to be exported. */ - private static KeyValueItemExportable getStrExportable(DataFetcher fetcher, String key, DataSource dataSource) { + /* ELODO private static KeyValueItemExportable getStrExportable(DataFetcher fetcher, String key, DataSource dataSource) { String result = getFetchResult(fetcher, "Types", dataSource); return (result == null) ? null : new KeyValueItemExportable(key, new DefaultCellModel<>(result)); } @@ -435,12 +430,13 @@ class TypesPanel extends BaseDataSourceSummaryPanel { * @param dataSource The data source. * @return The key value pair. */ - private static KeyValueItemExportable getCountExportable(DataFetcher fetcher, String key, DataSource dataSource) { + /* ELODOprivate static KeyValueItemExportable getCountExportable(DataFetcher fetcher, String key, DataSource dataSource) { Long count = getFetchResult(fetcher, "Types", dataSource); return (count == null) ? null : new KeyValueItemExportable(key, new DefaultCellModel(count, COMMA_FORMATTER::format, COMMA_FORMAT_STR)); } + /* ELODO @Override List getExports(DataSource dataSource) { if (dataSource == null) { @@ -471,7 +467,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { .filter(sheet -> sheet != null) .collect(Collectors.toList()) )); - } + }*/ /** * This method is called from within the constructor to initialize the form. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index 2cde769403..72f19ada78 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -26,8 +26,6 @@ import java.util.Date; import java.util.List; import java.util.Locale; import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary; @@ -37,12 +35,10 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.Top import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopWebSearchResult; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopProgramsResult; -import static org.sleuthkit.autopsy.datasourcesummary.ui.BaseDataSourceSummaryPanel.getTableExport; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport; import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.MenuItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; @@ -366,6 +362,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { super.close(); } + /* ELODO @Override List getExports(DataSource dataSource) { return Stream.of( @@ -376,7 +373,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { getTableExport(topAccountsFetcher, topAccountsTemplate, Bundle.UserActivityPanel_TopAccountTableModel_tabName(), dataSource)) .filter(sheet -> sheet != null) .collect(Collectors.toList()); - } + }*/ /** * This method is called from within the constructor to initialize the form. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/Bundle.properties-MERGED index ad10f70c22..c06bc6850a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/Bundle.properties-MERGED @@ -1,7 +1,5 @@ AbstractLoadableComponent_errorMessage_defaultText=There was an error loading results. AbstractLoadableComponent_loadingMessage_defaultText=Loading results... AbstractLoadableComponent_noDataExists_defaultText=No data exists. -# {0} - sheetNumber -ExcelExport_writeExcel_noSheetName=Sheet {0} IngestRunningLabel_defaultMessage=Ingest is currently running. PieChartPanel_noDataLabel=No Data diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultCellModel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultCellModel.java index 215f71469e..de0319ebf8 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultCellModel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultCellModel.java @@ -27,7 +27,7 @@ import java.util.function.Supplier; /** * The default cell model. */ -public class DefaultCellModel implements GuiCellModel, ExcelCellModel { +public class DefaultCellModel implements GuiCellModel { private final T data; private final String text; @@ -86,11 +86,6 @@ public class DefaultCellModel implements GuiCellModel, ExcelCellModel { return this.data; } - @Override - public String getExcelFormatString() { - return this.excelFormatString; - } - @Override public String getText() { return text; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ExcelCellModel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ExcelCellModel.java deleted file mode 100644 index 0ca52f12e4..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ExcelCellModel.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2021 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.datasourcesummary.uiutils; - -/** - * Basic interface for a cell model. - */ -public interface ExcelCellModel extends CellModel { - - /** - * @return The format string to be used with Apache POI during excel - * export or null if none necessary. - */ - String getExcelFormatString(); - -} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartExport.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartExport.java rename to Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartExport.java index 15a93092cc..edb71c21a9 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartExport.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.uiutils; +package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport; import java.awt.Color; import java.nio.ByteBuffer; @@ -49,10 +49,10 @@ import org.apache.poi.xssf.usermodel.XSSFChart; import org.apache.poi.xssf.usermodel.XSSFClientAnchor; import org.apache.poi.xssf.usermodel.XSSFDrawing; import org.apache.poi.xssf.usermodel.XSSFSheet; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelExportException; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ExcelItemExportable; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ItemDimensions; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelExportException; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelSheetExport; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.ExcelItemExportable; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.ItemDimensions; /** * Class that creates an excel stacked bar chart along with data table. @@ -70,7 +70,7 @@ public class BarChartExport implements ExcelItemExportable, ExcelSheetExport { * @return An excel table export to be used as the data source for the chart * in the excel document. */ - private static ExcelTableExport>, ? extends ExcelCellModel> getTableModel( + private static ExcelTableExport>, ? extends DefaultCellModel> getTableModel( List categories, String keyColumnHeader, String chartTitle) { // get the row keys by finding the series with the largest set of bar items @@ -134,7 +134,7 @@ public class BarChartExport implements ExcelItemExportable, ExcelSheetExport { private static final int DEFAULT_ROW_PADDING = 1; private static final int DEFAULT_COL_OFFSET = 1; - private final ExcelTableExport>, ? extends ExcelCellModel> tableExport; + private final ExcelTableExport>, ? extends DefaultCellModel> tableExport; private final int colOffset; private final int rowPadding; private final int colSize; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartSeries.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartSeries.java new file mode 100755 index 0000000000..f7c48a2f30 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartSeries.java @@ -0,0 +1,101 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.report.modules.datasourcesummaryexport; + +import java.awt.Color; +import java.util.Collections; +import java.util.List; + +/** + * Represents a series in a bar chart where all items pertain to one category. + */ +public class BarChartSeries { + + /** + * An individual bar to be displayed in the bar chart. + */ + public static class BarChartItem { + + private final Comparable key; + private final double value; + + /** + * Main constructor. + * + * @param key The key. + * @param value The value for this item. + */ + public BarChartItem(Comparable key, double value) { + this.key = key; + this.value = value; + } + + /** + * @return The key for this item. + */ + public Comparable getKey() { + return key; + } + + /** + * @return The value for this item. + */ + public double getValue() { + return value; + } + } + private final Comparable key; + private final Color color; + private final List items; + + /** + * Main constructor. + * + * @param key The key. + * @param color The color for this series. + * @param items The bars to be displayed for this series. + */ + public BarChartSeries(Comparable key, Color color, List items) { + this.key = key; + this.color = color; + this.items = (items == null) ? Collections.emptyList() : Collections.unmodifiableList(items); + } + + /** + * @return The color for this series. + */ + public Color getColor() { + return color; + } + + /** + * @return The bars to be displayed for this series. + */ + public List getItems() { + return items; + } + + /** + * @return The key for this item. + */ + public Comparable getKey() { + return key; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties new file mode 100755 index 0000000000..6c86626cdb --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties @@ -0,0 +1,3 @@ +DataSourceSummaryReport.getName.text=Data Source Summary Report +DataSourceSummaryReport.getDesc.text=Data source summary report in Excel (XLS) format. +DataSourceSummaryReport.endReport.srcModuleName.text=Excel Report \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED new file mode 100755 index 0000000000..bb28c7960e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -0,0 +1,18 @@ +DataSourceSummaryReport.getName.text=Data Source Summary Report +DataSourceSummaryReport.getDesc.text=Data source summary report in Excel (XLS) format. +DataSourceSummaryReport.endReport.srcModuleName.text=Excel Report +# {0} - sheetNumber +ExcelExport_writeExcel_noSheetName=Sheet {0} +ExcelExportAction_exportToXLSX_beginExport=Beginning Export... +# {0} - tabName +ExcelExportAction_exportToXLSX_gatheringTabData=Fetching Data for {0} Tab... +ExcelExportAction_exportToXLSX_writingToFile=Writing to File... +ExcelExportAction_getXLSXPath_directory=DataSourceSummary +ExcelExportAction_moduleName=Data Source Summary +ExcelExportAction_runXLSXExport_errorMessage=There was an error while exporting. +ExcelExportAction_runXLSXExport_errorTitle=Error While Exporting +ExcelExportAction_runXLSXExport_progressCancelActionTitle=Cancelling... +ExcelExportAction_runXLSXExport_progressCancelTitle=Cancel +# {0} - dataSource +ExcelExportAction_runXLSXExport_progressTitle=Exporting {0} to XLSX +ExcelExportDialog_title=Data Source Summary Exported diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ColumnModel.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ColumnModel.java new file mode 100755 index 0000000000..134f86f174 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ColumnModel.java @@ -0,0 +1,80 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.report.modules.datasourcesummaryexport; + +import java.util.function.Function; + +/** + * Describes aspects of a column which can be used with getTableModel or + * getJTablePanel. 'T' represents the object that will represent rows in the + * table. + */ +public class ColumnModel { + + private final String headerTitle; + private final Function cellRenderer; + private final Integer width; + + /** + * Constructor for a DataResultColumnModel. + * + * @param headerTitle The title for the column. + * @param cellRenderer The method that generates a CellModel for the column + * based on the data. + */ + public ColumnModel(String headerTitle, Function cellRenderer) { + this(headerTitle, cellRenderer, null); + } + + /** + * Constructor for a DataResultColumnModel. + * + * @param headerTitle The title for the column. + * @param cellRenderer The method that generates a CellModel for the column + * based on the data. + * @param width The preferred width of the column. + */ + public ColumnModel(String headerTitle, Function cellRenderer, Integer width) { + this.headerTitle = headerTitle; + this.cellRenderer = cellRenderer; + this.width = width; + } + + /** + * @return The title for the column. + */ + public String getHeaderTitle() { + return headerTitle; + } + + /** + * @return The method that generates a CellModel for the column based on the + * data. + */ + public Function getCellRenderer() { + return cellRenderer; + } + + /** + * @return The preferred width of the column (can be null). + */ + public Integer getWidth() { + return width; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java new file mode 100755 index 0000000000..e4b4483675 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java @@ -0,0 +1,117 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.report.modules.datasourcesummaryexport; + +import java.util.List; +import java.util.logging.Level; +import java.util.stream.Collectors; +import javax.swing.JPanel; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.report.GeneralReportModule; +import org.sleuthkit.autopsy.report.GeneralReportSettings; +import org.sleuthkit.autopsy.report.ReportProgressPanel; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; + +class DataSourceSummaryReport implements GeneralReportModule { + + private static final Logger logger = Logger.getLogger(DataSourceSummaryReport.class.getName()); + private static DataSourceSummaryReport instance; + + // Get the default instance of this report + public static synchronized DataSourceSummaryReport getDefault() { + if (instance == null) { + instance = new DataSourceSummaryReport(); + } + return instance; + } + + // Hidden constructor + private DataSourceSummaryReport() { + } + + + @Override + public String getName() { + String name = NbBundle.getMessage(this.getClass(), "DataSourceSummaryReport.getName.text"); + return name; + } + + @Override + public String getRelativeFilePath() { + return "DataSourceSummaryReport.xlsx"; //NON-NLS + } + + @Override + public String getDescription() { + String desc = NbBundle.getMessage(this.getClass(), "DataSourceSummaryReport.getDesc.text"); + return desc; + } + + @Override + public JPanel getConfigurationPanel() { + return null; // No configuration panel + } + + @Override + public boolean supportsDataSourceSelection() { + return true; + } + + @Override + public void generateReport(GeneralReportSettings settings, ReportProgressPanel progressPanel) { + Case currentCase = null; + try { + currentCase = Case.getCurrentCaseThrows(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return; + } + + if(settings.getSelectedDataSources() == null) { + // Process all data sources if the list is null. + try { + List selectedDataSources = currentCase.getDataSources() + .stream() + .map(Content::getId) + .collect(Collectors.toList()); + settings.setSelectedDataSources(selectedDataSources); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Could not get the datasources from the case", ex); + return; + } + } + + String baseReportDir = settings.getReportDirectoryPath(); + // Start the progress bar and setup the report + progressPanel.setIndeterminate(true); + progressPanel.start(); + //progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.querying")); + String reportFullPath = baseReportDir + getRelativeFilePath(); //NON-NLS + String errorMessage = ""; + + //progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.loading")); + + ReportProgressPanel.ReportStatus result = ReportProgressPanel.ReportStatus.COMPLETE; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DefaultCellModel.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DefaultCellModel.java new file mode 100755 index 0000000000..5553aa6d73 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DefaultCellModel.java @@ -0,0 +1,149 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.report.modules.datasourcesummaryexport; + +import java.util.function.Function; +import javax.swing.JLabel; +import org.apache.poi.ss.usermodel.HorizontalAlignment; + +/** + * The default cell model. + */ +class DefaultCellModel { + + private final T data; + private final String text; + private HorizontalAlign horizontalAlignment; + private final String excelFormatString; + + /** + * Describes the horizontal alignment. + */ + enum HorizontalAlign { + LEFT(JLabel.LEFT, HorizontalAlignment.LEFT), + CENTER(JLabel.CENTER, HorizontalAlignment.CENTER), + RIGHT(JLabel.RIGHT, HorizontalAlignment.RIGHT); + + private final int jlabelAlignment; + private final HorizontalAlignment poiAlignment; + + /** + * Constructor for a HorizontalAlign enum. + * + * @param jlabelAlignment The corresponding JLabel horizontal alignment + * number. + * @param poiAlignment Horizontal alignment for Apache POI. + */ + HorizontalAlign(int jlabelAlignment, HorizontalAlignment poiAlignment) { + this.jlabelAlignment = jlabelAlignment; + this.poiAlignment = poiAlignment; + } + + /** + * @return The corresponding JLabel horizontal alignment (i.e. + * JLabel.LEFT). + */ + int getJLabelAlignment() { + return this.jlabelAlignment; + } + + /** + * @return Horizontal alignment for Apache POI. + */ + HorizontalAlignment getPoiAlignment() { + return poiAlignment; + } + } + + /** + * Main constructor. + * + * @param data The data to be displayed in the cell. + */ + public DefaultCellModel(T data) { + this(data, null, null); + } + + /** + * Constructor. + * + * @param data The data to be displayed in the cell. + * @param stringConverter The means of converting that data to a string or + * null to use .toString method on object. + */ + public DefaultCellModel(T data, Function stringConverter) { + this(data, stringConverter, null); + } + + /** + * Constructor. + * + * @param data The data to be displayed in the cell. + * @param stringConverter The means of converting that data to a string or + * null to use .toString method on object. + * @param excelFormatString The apache poi excel format string to use with + * the data. + * + * NOTE: Only certain data types can be exported. See + * ExcelTableExport.createCell() for types. + */ + public DefaultCellModel(T data, Function stringConverter, String excelFormatString) { + this.data = data; + this.excelFormatString = excelFormatString; + + if (stringConverter == null) { + text = this.data == null ? "" : this.data.toString(); + } else { + text = stringConverter.apply(this.data); + } + } + + public T getData() { + return this.data; + } + + public String getExcelFormatString() { + return this.excelFormatString; + } + + public String getText() { + return text; + } + + public HorizontalAlign getHorizontalAlignment() { + return horizontalAlignment; + } + + /** + * Sets the horizontal alignment for this cell model. + * + * @param alignment The horizontal alignment for the cell model. + * + * @return As a utility, returns this. + */ + public DefaultCellModel setHorizontalAlignment(HorizontalAlign alignment) { + this.horizontalAlignment = alignment; + return this; + } + + @Override + public String toString() { + return getText(); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ExcelExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ExcelExport.java rename to Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java index fab6558c4a..b7e2c04fec 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ExcelExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.uiutils; +package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport; import java.io.File; import java.io.FileOutputStream; @@ -37,7 +37,7 @@ import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModel.HorizontalAlign; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.DefaultCellModel.HorizontalAlign; /** * Class for handling Excel exporting. @@ -337,7 +337,7 @@ public class ExcelExport { * @param cellStyle The style to use. * @return The created cell. */ - static Cell createCell(WorksheetEnv env, Row row, int colNum, ExcelCellModel cellModel, Optional cellStyle) { + static Cell createCell(WorksheetEnv env, Row row, int colNum, DefaultCellModel cellModel, Optional cellStyle) { CellStyle cellStyleToUse = cellStyle.orElse(env.getDefaultCellStyle()); if (cellModel.getExcelFormatString() != null || cellModel.getHorizontalAlignment() != null) { diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ExcelExportAction.java rename to Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index 22e06c07ed..1c8e6fb6cb 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.ui; +package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -43,9 +43,8 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelExportException; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelExportException; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelSheetExport; import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator; import org.sleuthkit.autopsy.progress.ProgressIndicator; import org.sleuthkit.datamodel.DataSource; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ExcelExportDialog.form b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportDialog.form similarity index 97% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ExcelExportDialog.form rename to Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportDialog.form index 8342ce5326..7bc59aa544 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ExcelExportDialog.form +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportDialog.form @@ -92,9 +92,6 @@ - - - diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ExcelExportDialog.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportDialog.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ExcelExportDialog.java rename to Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportDialog.java index ec16d08e46..448566b6af 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ExcelExportDialog.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportDialog.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.ui; +package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport; import java.awt.Cursor; import java.awt.Desktop; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ExcelSpecialFormatExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelSpecialFormatExport.java similarity index 93% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ExcelSpecialFormatExport.java rename to Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelSpecialFormatExport.java index f9c46fa5e2..71683d1d26 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ExcelSpecialFormatExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelSpecialFormatExport.java @@ -16,14 +16,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.uiutils; +package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport; import java.util.Collections; import java.util.List; import java.util.Optional; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelExportException; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelExportException; /** * An excel export that has special row-by-row formatting. @@ -108,7 +108,7 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { */ public static class SingleCellExportable implements ExcelItemExportable { - private final ExcelCellModel item; + private final DefaultCellModel item; /** * Main constructor. @@ -124,7 +124,7 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { * * @param item The cell model to be written. */ - public SingleCellExportable(ExcelCellModel item) { + public SingleCellExportable(DefaultCellModel item) { this.item = item; } @@ -142,8 +142,8 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { */ public static class KeyValueItemExportable implements ExcelItemExportable { - private final ExcelCellModel key; - private final ExcelCellModel value; + private final DefaultCellModel key; + private final DefaultCellModel value; /** * Main constructor. @@ -151,7 +151,7 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { * @param key The string key to be exported. * @param value The cell model to be exported. */ - public KeyValueItemExportable(String key, ExcelCellModel value) { + public KeyValueItemExportable(String key, DefaultCellModel value) { this(new DefaultCellModel<>(key), value); } @@ -161,7 +161,7 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { * @param key The cell key to be exported. * @param value The cell model to be exported. */ - public KeyValueItemExportable(ExcelCellModel key, ExcelCellModel value) { + public KeyValueItemExportable(DefaultCellModel key, DefaultCellModel value) { this.key = key; this.value = value; } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ExcelTableExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelTableExport.java similarity index 84% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ExcelTableExport.java rename to Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelTableExport.java index c79cb381aa..c861d5d174 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/ExcelTableExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelTableExport.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.uiutils; +package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport; import java.util.Collections; import java.util.List; @@ -24,15 +24,15 @@ import java.util.Optional; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelExportException; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ExcelItemExportable; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ItemDimensions; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelExportException; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelSheetExport; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.ExcelItemExportable; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.ItemDimensions; /** * An excel sheet export of table data. */ -public class ExcelTableExport implements ExcelSheetExport, ExcelItemExportable { +public class ExcelTableExport implements ExcelSheetExport, ExcelItemExportable { private final String sheetName; private final List> columns; @@ -104,7 +104,7 @@ public class ExcelTableExport implements ExcelSheet * @throws ExcelExportException * @return The number of rows (including the header) written. */ - private static int renderSheet( + private static int renderSheet( Sheet sheet, ExcelExport.WorksheetEnv worksheetEnv, int rowStart, @@ -127,8 +127,8 @@ public class ExcelTableExport implements ExcelSheet T rowData = safeData.get(rowNum); Row row = sheet.createRow(rowNum + rowStart + 1); for (int colNum = 0; colNum < columns.size(); colNum++) { - ColumnModel colModel = columns.get(colNum); - ExcelCellModel cellModel = colModel.getCellRenderer().apply(rowData); + ColumnModel colModel = columns.get(colNum); + DefaultCellModel cellModel = colModel.getCellRenderer().apply(rowData); ExcelExport.createCell(worksheetEnv, row, colNum + colStart, cellModel, Optional.empty()); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ExportPanel.form b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPanel.form similarity index 100% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ExportPanel.form rename to Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPanel.form diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ExportPanel.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPanel.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ExportPanel.java rename to Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPanel.java index 7e635c3f64..8e2ea7989b 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ExportPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPanel.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.ui; +package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport; /** * The panel that provides options for exporting data source summary data. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartExport.java similarity index 93% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartExport.java rename to Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartExport.java index 4005a34ebc..cf37119996 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/PieChartExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartExport.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.uiutils; +package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -35,10 +35,10 @@ import org.apache.poi.xssf.usermodel.XSSFClientAnchor; import org.apache.poi.xssf.usermodel.XSSFDrawing; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.openxmlformats.schemas.drawingml.x2006.chart.CTPieChart; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelExportException; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ExcelItemExportable; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ItemDimensions; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelExportException; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelSheetExport; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.ExcelItemExportable; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.ItemDimensions; /** * @@ -51,7 +51,7 @@ public class PieChartExport implements ExcelItemExportable, ExcelSheetExport { private static final int DEFAULT_ROW_PADDING = 1; private static final int DEFAULT_COL_OFFSET = 1; - private final ExcelTableExport tableExport; + private final ExcelTableExport tableExport; private final int colOffset; private final int rowPadding; private final int colSize; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartItem.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartItem.java new file mode 100755 index 0000000000..3b18a8c41c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartItem.java @@ -0,0 +1,67 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.report.modules.datasourcesummaryexport; + +import java.awt.Color; + +/** + * An individual pie chart slice in the pie chart. + */ +public class PieChartItem { + + private final String label; + private final double value; + private final Color color; + + /** + * Main constructor. + * + * @param label The label for this pie slice. + * @param value The value for this item. + * @param color The color for the pie slice. Can be null for + * auto-determined. + */ + public PieChartItem(String label, double value, Color color) { + this.label = label; + this.value = value; + this.color = color; + } + + /** + * @return The label for this item. + */ + public String getLabel() { + return label; + } + + /** + * @return The value for this item. + */ + public double getValue() { + return value; + } + + /** + * @return The color for the pie slice or null for auto-determined. + */ + public Color getColor() { + return color; + } + +} From e87c91a40dafcd4f90bd417e9096e7e9e59bc8d2 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 5 Aug 2021 10:08:44 -0400 Subject: [PATCH 06/76] More refacturing --- .../Bundle.properties-MERGED | 1 - .../datasourcesummaryexport/CellModel.java | 85 +++++++++++ .../datasourcesummaryexport/ColumnModel.java | 12 +- .../DefaultCellModel.java | 63 ++------ .../datasourcesummaryexport/ExcelExport.java | 8 +- .../ExcelExportAction.java | 4 +- .../ExcelExportDialog.form | 111 -------------- .../ExcelExportDialog.java | 143 ------------------ .../ExcelTableExport.java | 12 +- .../datasourcesummaryexport/ExportPanel.form | 68 --------- .../datasourcesummaryexport/ExportPanel.java | 105 ------------- 11 files changed, 112 insertions(+), 500 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/CellModel.java delete mode 100644 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportDialog.form delete mode 100644 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportDialog.java delete mode 100644 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPanel.form delete mode 100644 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index bb28c7960e..4388aad3e7 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -15,4 +15,3 @@ ExcelExportAction_runXLSXExport_progressCancelActionTitle=Cancelling... ExcelExportAction_runXLSXExport_progressCancelTitle=Cancel # {0} - dataSource ExcelExportAction_runXLSXExport_progressTitle=Exporting {0} to XLSX -ExcelExportDialog_title=Data Source Summary Exported diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/CellModel.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/CellModel.java new file mode 100755 index 0000000000..bae7d770b7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/CellModel.java @@ -0,0 +1,85 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.report.modules.datasourcesummaryexport; + +import javax.swing.JLabel; +import org.apache.poi.ss.usermodel.HorizontalAlignment; + +/** + * Basic interface for a cell model. + */ +interface CellModel { + + /** + * Describes the horizontal alignment. + */ + enum HorizontalAlign { + LEFT(JLabel.LEFT, HorizontalAlignment.LEFT), + CENTER(JLabel.CENTER, HorizontalAlignment.CENTER), + RIGHT(JLabel.RIGHT, HorizontalAlignment.RIGHT); + + private final int jlabelAlignment; + private final HorizontalAlignment poiAlignment; + + /** + * Constructor for a HorizontalAlign enum. + * + * @param jlabelAlignment The corresponding JLabel horizontal alignment + * number. + * @param poiAlignment Horizontal alignment for Apache POI. + */ + HorizontalAlign(int jlabelAlignment, HorizontalAlignment poiAlignment) { + this.jlabelAlignment = jlabelAlignment; + this.poiAlignment = poiAlignment; + } + + /** + * @return The corresponding JLabel horizontal alignment (i.e. + * JLabel.LEFT). + */ + int getJLabelAlignment() { + return this.jlabelAlignment; + } + + /** + * @return Horizontal alignment for Apache POI. + */ + HorizontalAlignment getPoiAlignment() { + return poiAlignment; + } + } + + /** + * @return The root data object. + */ + Object getData(); + + /** + * @return The text to be shown in the cell. + */ + default String getText() { + Object data = getData(); + return (data == null) ? null : data.toString(); + } + + /** + * @return The horizontal alignment for the text in the cell. + */ + HorizontalAlign getHorizontalAlignment(); +} diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ColumnModel.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ColumnModel.java index 134f86f174..9c68de3992 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ColumnModel.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ColumnModel.java @@ -25,7 +25,7 @@ import java.util.function.Function; * getJTablePanel. 'T' represents the object that will represent rows in the * table. */ -public class ColumnModel { +class ColumnModel { private final String headerTitle; private final Function cellRenderer; @@ -38,7 +38,7 @@ public class ColumnModel { * @param cellRenderer The method that generates a CellModel for the column * based on the data. */ - public ColumnModel(String headerTitle, Function cellRenderer) { + ColumnModel(String headerTitle, Function cellRenderer) { this(headerTitle, cellRenderer, null); } @@ -50,7 +50,7 @@ public class ColumnModel { * based on the data. * @param width The preferred width of the column. */ - public ColumnModel(String headerTitle, Function cellRenderer, Integer width) { + ColumnModel(String headerTitle, Function cellRenderer, Integer width) { this.headerTitle = headerTitle; this.cellRenderer = cellRenderer; this.width = width; @@ -59,7 +59,7 @@ public class ColumnModel { /** * @return The title for the column. */ - public String getHeaderTitle() { + String getHeaderTitle() { return headerTitle; } @@ -67,14 +67,14 @@ public class ColumnModel { * @return The method that generates a CellModel for the column based on the * data. */ - public Function getCellRenderer() { + Function getCellRenderer() { return cellRenderer; } /** * @return The preferred width of the column (can be null). */ - public Integer getWidth() { + Integer getWidth() { return width; } } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DefaultCellModel.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DefaultCellModel.java index 5553aa6d73..149d3413f6 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DefaultCellModel.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DefaultCellModel.java @@ -19,64 +19,21 @@ package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport; import java.util.function.Function; -import javax.swing.JLabel; -import org.apache.poi.ss.usermodel.HorizontalAlignment; - /** * The default cell model. */ -class DefaultCellModel { +class DefaultCellModel implements CellModel { private final T data; private final String text; - private HorizontalAlign horizontalAlignment; - private final String excelFormatString; - - /** - * Describes the horizontal alignment. - */ - enum HorizontalAlign { - LEFT(JLabel.LEFT, HorizontalAlignment.LEFT), - CENTER(JLabel.CENTER, HorizontalAlignment.CENTER), - RIGHT(JLabel.RIGHT, HorizontalAlignment.RIGHT); - - private final int jlabelAlignment; - private final HorizontalAlignment poiAlignment; - - /** - * Constructor for a HorizontalAlign enum. - * - * @param jlabelAlignment The corresponding JLabel horizontal alignment - * number. - * @param poiAlignment Horizontal alignment for Apache POI. - */ - HorizontalAlign(int jlabelAlignment, HorizontalAlignment poiAlignment) { - this.jlabelAlignment = jlabelAlignment; - this.poiAlignment = poiAlignment; - } - - /** - * @return The corresponding JLabel horizontal alignment (i.e. - * JLabel.LEFT). - */ - int getJLabelAlignment() { - return this.jlabelAlignment; - } - - /** - * @return Horizontal alignment for Apache POI. - */ - HorizontalAlignment getPoiAlignment() { - return poiAlignment; - } - } + private CellModel.HorizontalAlign horizontalAlignment; /** * Main constructor. * * @param data The data to be displayed in the cell. */ - public DefaultCellModel(T data) { + DefaultCellModel(T data) { this(data, null, null); } @@ -87,7 +44,7 @@ class DefaultCellModel { * @param stringConverter The means of converting that data to a string or * null to use .toString method on object. */ - public DefaultCellModel(T data, Function stringConverter) { + DefaultCellModel(T data, Function stringConverter) { this(data, stringConverter, null); } @@ -103,9 +60,8 @@ class DefaultCellModel { * NOTE: Only certain data types can be exported. See * ExcelTableExport.createCell() for types. */ - public DefaultCellModel(T data, Function stringConverter, String excelFormatString) { + DefaultCellModel(T data, Function stringConverter, String excelFormatString) { this.data = data; - this.excelFormatString = excelFormatString; if (stringConverter == null) { text = this.data == null ? "" : this.data.toString(); @@ -114,18 +70,17 @@ class DefaultCellModel { } } + @Override public T getData() { return this.data; } - public String getExcelFormatString() { - return this.excelFormatString; - } - + @Override public String getText() { return text; } + @Override public HorizontalAlign getHorizontalAlignment() { return horizontalAlignment; } @@ -137,7 +92,7 @@ class DefaultCellModel { * * @return As a utility, returns this. */ - public DefaultCellModel setHorizontalAlignment(HorizontalAlign alignment) { + DefaultCellModel setHorizontalAlignment(CellModel.HorizontalAlign alignment) { this.horizontalAlignment = alignment; return this; } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java index b7e2c04fec..1e7a7d9a89 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java @@ -37,7 +37,7 @@ import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.DefaultCellModel.HorizontalAlign; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.CellModel.HorizontalAlign; /** * Class for handling Excel exporting. @@ -337,11 +337,11 @@ public class ExcelExport { * @param cellStyle The style to use. * @return The created cell. */ - static Cell createCell(WorksheetEnv env, Row row, int colNum, DefaultCellModel cellModel, Optional cellStyle) { + static Cell createCell(WorksheetEnv env, Row row, int colNum, CellModel cellModel, Optional cellStyle) { CellStyle cellStyleToUse = cellStyle.orElse(env.getDefaultCellStyle()); - if (cellModel.getExcelFormatString() != null || cellModel.getHorizontalAlignment() != null) { - cellStyleToUse = env.getCellStyle(new CellStyleKey(cellModel.getExcelFormatString(), cellStyleToUse, cellModel.getHorizontalAlignment())); + if (cellModel.getText() != null || cellModel.getHorizontalAlignment() != null) { + cellStyleToUse = env.getCellStyle(new CellStyleKey(cellModel.getText(), cellStyleToUse, cellModel.getHorizontalAlignment())); } Object cellData = cellModel.getData(); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index 1c8e6fb6cb..b839fe8aac 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -285,13 +285,13 @@ class ExcelExportAction implements Consumer { dataSource); // and show finished dialog - SwingUtilities.invokeLater(() -> { + /* ELTODO SwingUtilities.invokeLater(() -> { ExcelExportDialog dialog = new ExcelExportDialog(WindowManager.getDefault().getMainWindow(), path); dialog.setResizable(false); dialog.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); dialog.setVisible(true); dialog.toFront(); - }); + });*/ } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.WARNING, "There was an error attaching report to case.", ex); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportDialog.form b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportDialog.form deleted file mode 100644 index 7bc59aa544..0000000000 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportDialog.form +++ /dev/null @@ -1,111 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportDialog.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportDialog.java deleted file mode 100644 index 448566b6af..0000000000 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportDialog.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2021 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.report.modules.datasourcesummaryexport; - -import java.awt.Cursor; -import java.awt.Desktop; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.io.File; -import java.io.IOException; -import java.util.logging.Level; -import javax.swing.SwingUtilities; -import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.coreutils.Logger; - -/** - * Dialog showing where the data source summary excel export can be located. - */ -@Messages({ - "ExcelExportDialog_title=Data Source Summary Exported" -}) -public class ExcelExportDialog extends javax.swing.JDialog { - - private static final Logger logger = Logger.getLogger(ExcelExportDialog.class.getName()); - - /** - * Creates new form ExcelExportDialog - */ - public ExcelExportDialog(java.awt.Frame parent, File filePath) { - super(parent, true); - - initComponents(); - setTitle(Bundle.ExcelExportDialog_title()); - - this.linkText.setText(filePath.getAbsolutePath()); - this.linkText.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - SwingUtilities.invokeLater(() -> { - try { - Desktop.getDesktop().open(filePath); - } catch (IOException ex) { - logger.log(Level.WARNING, "Unable to open: " + filePath.getAbsolutePath(), ex); - } - }); - } - - }); - this.linkText.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - javax.swing.JLabel titleLabel = new javax.swing.JLabel(); - javax.swing.JButton okButton = new javax.swing.JButton(); - javax.swing.JScrollPane linkTextScrollPane = new javax.swing.JScrollPane(); - linkText = new javax.swing.JTextArea(); - - setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - - org.openide.awt.Mnemonics.setLocalizedText(titleLabel, org.openide.util.NbBundle.getMessage(ExcelExportDialog.class, "ExcelExportDialog.titleLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(ExcelExportDialog.class, "ExcelExportDialog.okButton.text")); // NOI18N - okButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - okButtonActionPerformed(evt); - } - }); - - linkText.setEditable(false); - linkText.setBackground(null); - linkText.setColumns(20); - linkText.setForeground(java.awt.Color.BLUE); - linkText.setLineWrap(true); - linkText.setRows(1); - linkText.setWrapStyleWord(true); - linkText.setBorder(null); - linkText.setOpaque(false); - linkTextScrollPane.setViewportView(linkText); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); - getContentPane().setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(linkTextScrollPane) - .addGroup(layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(okButton)) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(titleLabel) - .addGap(0, 116, Short.MAX_VALUE))) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(titleLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(linkTextScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 39, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(okButton) - .addContainerGap()) - ); - - pack(); - }// //GEN-END:initComponents - - private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - dispose(); - }//GEN-LAST:event_okButtonActionPerformed - - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JTextArea linkText; - // End of variables declaration//GEN-END:variables -} diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelTableExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelTableExport.java index c861d5d174..b31c7da507 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelTableExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelTableExport.java @@ -32,7 +32,7 @@ import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecial /** * An excel sheet export of table data. */ -public class ExcelTableExport implements ExcelSheetExport, ExcelItemExportable { +class ExcelTableExport implements ExcelSheetExport, ExcelItemExportable { private final String sheetName; private final List> columns; @@ -47,7 +47,7 @@ public class ExcelTableExport implements ExcelShe * @param columns The columns of the table. * @param data The data to export. */ - public ExcelTableExport(String sheetName, List> columns, List data) { + ExcelTableExport(String sheetName, List> columns, List data) { this(sheetName, columns, data, 0); } @@ -60,7 +60,7 @@ public class ExcelTableExport implements ExcelShe * @param data The data to export. * @param columnIndent The column indent. */ - public ExcelTableExport(String sheetName, List> columns, List data, int columnIndent) { + ExcelTableExport(String sheetName, List> columns, List data, int columnIndent) { this.sheetName = sheetName; this.columns = columns; this.data = data; @@ -104,7 +104,7 @@ public class ExcelTableExport implements ExcelShe * @throws ExcelExportException * @return The number of rows (including the header) written. */ - private static int renderSheet( + private static int renderSheet( Sheet sheet, ExcelExport.WorksheetEnv worksheetEnv, int rowStart, @@ -127,8 +127,8 @@ public class ExcelTableExport implements ExcelShe T rowData = safeData.get(rowNum); Row row = sheet.createRow(rowNum + rowStart + 1); for (int colNum = 0; colNum < columns.size(); colNum++) { - ColumnModel colModel = columns.get(colNum); - DefaultCellModel cellModel = colModel.getCellRenderer().apply(rowData); + ColumnModel colModel = columns.get(colNum); + CellModel cellModel = colModel.getCellRenderer().apply(rowData); ExcelExport.createCell(worksheetEnv, row, colNum + colStart, cellModel, Optional.empty()); } } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPanel.form b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPanel.form deleted file mode 100644 index 908facb8d6..0000000000 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPanel.form +++ /dev/null @@ -1,68 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPanel.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPanel.java deleted file mode 100644 index 8e2ea7989b..0000000000 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPanel.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2021 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.report.modules.datasourcesummaryexport; - -/** - * The panel that provides options for exporting data source summary data. - */ -public class ExportPanel extends javax.swing.JPanel { - - private Runnable xlsxExportAction; - - /** - * Creates new form ExportPanel - */ - public ExportPanel() { - initComponents(); - } - - /** - * Returns the action that handles exporting to excel. - * - * @return The action that handles exporting to excel. - */ - public Runnable getXlsxExportAction() { - return xlsxExportAction; - } - - /** - * Sets the action that handles exporting to excel. - * - * @param onXlsxExport The action that handles exporting to excel. - */ - public void setXlsxExportAction(Runnable onXlsxExport) { - this.xlsxExportAction = onXlsxExport; - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - javax.swing.JButton xlsxExportButton = new javax.swing.JButton(); - javax.swing.JLabel xlsxExportMessage = new javax.swing.JLabel(); - - org.openide.awt.Mnemonics.setLocalizedText(xlsxExportButton, org.openide.util.NbBundle.getMessage(ExportPanel.class, "ExportPanel.xlsxExportButton.text")); // NOI18N - xlsxExportButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - xlsxExportButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(xlsxExportMessage, org.openide.util.NbBundle.getMessage(ExportPanel.class, "ExportPanel.xlsxExportMessage.text")); // NOI18N - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(xlsxExportMessage) - .addComponent(xlsxExportButton)) - .addContainerGap(62, Short.MAX_VALUE)) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(xlsxExportMessage) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(xlsxExportButton) - .addContainerGap(250, Short.MAX_VALUE)) - ); - }// //GEN-END:initComponents - - private void xlsxExportButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_xlsxExportButtonActionPerformed - if (this.xlsxExportAction != null) { - xlsxExportAction.run(); - } - }//GEN-LAST:event_xlsxExportButtonActionPerformed - - - // Variables declaration - do not modify//GEN-BEGIN:variables - // End of variables declaration//GEN-END:variables -} From 71206158efd9c0de2ba81d32debb2a6b644dc449 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 5 Aug 2021 10:34:16 -0400 Subject: [PATCH 07/76] Refactoring --- .../datasourcesummary/ui/AnalysisPanel.java | 2 +- .../datasourcesummary/ui/ContainerPanel.java | 4 +- .../ui/GeolocationPanel.java | 2 +- .../ui/IngestJobExcelExport.java | 4 +- .../datasourcesummary/ui/PastCasesPanel.java | 2 +- .../ui/RecentFilesPanel.java | 2 +- .../datasourcesummary/ui/TimelinePanel.java | 2 +- .../datasourcesummary/ui/TypesPanel.java | 6 +-- .../ui/UserActivityPanel.java | 2 +- .../uiutils/DefaultCellModel.java | 2 +- .../BarChartExport.java | 10 ++--- .../DataSourceSummaryReport.java | 2 +- .../datasourcesummaryexport/ExcelExport.java | 25 ++++++------ .../ExcelSpecialFormatExport.java | 40 +++++++++---------- .../PieChartExport.java | 8 ++-- 15 files changed, 56 insertions(+), 57 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index 99da8fbd5a..10f0df97dd 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -226,7 +226,7 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { ); }// //GEN-END:initComponents - /* ELODO + /* ELTODO @Override List getExports(DataSource dataSource) { return Stream.of( diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java index 0fc66a4c72..1f46f48d48 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java @@ -480,7 +480,7 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { * @return The list of key value pairs that can be incorporated into the * excel export. */ - /* ELODO + /* ELTODO private static List getAcquisitionDetails(String acquisitionDetails) { if (StringUtils.isBlank(acquisitionDetails)) { return Collections.emptyList(); @@ -492,7 +492,7 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { } }*/ - /* ELODO + /* ELTODO @Messages({ "ContainerPanel_export_displayName=Display Name:", "ContainerPanel_export_originalName=Name:", diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java index fd3ad98dcc..595209f064 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java @@ -348,7 +348,7 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel { onNewDataSource(dataFetchComponents, tables, dataSource); } - /* ELODO + /* ELTODO @Override List getExports(DataSource dataSource) { GeolocationViewModel model = getFetchResult(geolocationFetcher, "Geolocation sheets", dataSource); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/IngestJobExcelExport.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/IngestJobExcelExport.java index 07d789c0fa..5ec92353e2 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/IngestJobExcelExport.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/IngestJobExcelExport.java @@ -52,7 +52,7 @@ import org.sleuthkit.datamodel.TskCoreException; "IngestJobExcelExport_versionColumn=Module Version", "IngestJobExcelExport_sheetName=Ingest History" }) -class IngestJobExcelExport { +class IngestJobExcelExport { // ELTODO remove this class /** * An entry to display in an excel export. @@ -209,7 +209,7 @@ class IngestJobExcelExport { * @param dataSource The data source. * @return The list of sheets to be included in an export. */ - /* ELODO + /* ELTODO static List getExports(DataSource dataSource) { if (dataSource == null) { return Collections.emptyList(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index d49bcfdff0..cdce933a1c 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -124,7 +124,7 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { onNewDataSource(dataFetchComponents, tables, dataSource); } - /* ELODO + /* ELTODO @Override List getExports(DataSource dataSource) { PastCasesResult result = getFetchResult(pastCasesFetcher, "Past cases sheets", dataSource); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index 6bb0ba78af..52e0721cc8 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -186,7 +186,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { onNewDataSource(dataFetchComponents, tablePanelList, dataSource); } - /* ELODO + /* ELTODO @Override List getExports(DataSource dataSource) { return Stream.of( diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java index d2dfb8d261..318da42943 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java @@ -299,7 +299,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { return new DefaultCellModel<>(date, (dt) -> dt == null ? "" : EARLIEST_LATEST_FORMAT.format(dt), EARLIEST_LATEST_FORMAT_STR); } - /* ELODO + /* ELTODO @Messages({ "TimelinePanel_getExports_sheetName=Timeline", "TimelinePanel_getExports_activityRange=Activity Range", diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index 3f1b19e1a4..3e9ec03ea0 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -416,7 +416,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { * @param dataSource The data source containing the data. * @return The key value pair to be exported. */ - /* ELODO private static KeyValueItemExportable getStrExportable(DataFetcher fetcher, String key, DataSource dataSource) { + /* ELTODO private static KeyValueItemExportable getStrExportable(DataFetcher fetcher, String key, DataSource dataSource) { String result = getFetchResult(fetcher, "Types", dataSource); return (result == null) ? null : new KeyValueItemExportable(key, new DefaultCellModel<>(result)); } @@ -430,13 +430,13 @@ class TypesPanel extends BaseDataSourceSummaryPanel { * @param dataSource The data source. * @return The key value pair. */ - /* ELODOprivate static KeyValueItemExportable getCountExportable(DataFetcher fetcher, String key, DataSource dataSource) { + /* ELTODOprivate static KeyValueItemExportable getCountExportable(DataFetcher fetcher, String key, DataSource dataSource) { Long count = getFetchResult(fetcher, "Types", dataSource); return (count == null) ? null : new KeyValueItemExportable(key, new DefaultCellModel(count, COMMA_FORMATTER::format, COMMA_FORMAT_STR)); } - /* ELODO + /* ELTODO @Override List getExports(DataSource dataSource) { if (dataSource == null) { diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index 72f19ada78..2d58c09742 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -362,7 +362,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { super.close(); } - /* ELODO + /* ELTODO @Override List getExports(DataSource dataSource) { return Stream.of( diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultCellModel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultCellModel.java index de0319ebf8..3d2e4e6a5a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultCellModel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultCellModel.java @@ -35,7 +35,7 @@ public class DefaultCellModel implements GuiCellModel { private CellModel.HorizontalAlign horizontalAlignment; private List popupMenu; private Supplier> menuItemSupplier; - private final String excelFormatString; + private final String excelFormatString; // ELTODO /** * Main constructor. diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartExport.java index edb71c21a9..8ff16075e3 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartExport.java @@ -57,7 +57,7 @@ import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecial /** * Class that creates an excel stacked bar chart along with data table. */ -public class BarChartExport implements ExcelItemExportable, ExcelSheetExport { +class BarChartExport implements ExcelItemExportable, ExcelSheetExport { /** * Creates an excel table model to be written to an excel sheet and used as @@ -70,7 +70,7 @@ public class BarChartExport implements ExcelItemExportable, ExcelSheetExport { * @return An excel table export to be used as the data source for the chart * in the excel document. */ - private static ExcelTableExport>, ? extends DefaultCellModel> getTableModel( + private static ExcelTableExport>, ? extends CellModel> getTableModel( List categories, String keyColumnHeader, String chartTitle) { // get the row keys by finding the series with the largest set of bar items @@ -134,7 +134,7 @@ public class BarChartExport implements ExcelItemExportable, ExcelSheetExport { private static final int DEFAULT_ROW_PADDING = 1; private static final int DEFAULT_COL_OFFSET = 1; - private final ExcelTableExport>, ? extends DefaultCellModel> tableExport; + private final ExcelTableExport>, ? extends CellModel> tableExport; private final int colOffset; private final int rowPadding; private final int colSize; @@ -154,7 +154,7 @@ public class BarChartExport implements ExcelItemExportable, ExcelSheetExport { * @param chartTitle The title for the chart. * @param categories The categories along with data. */ - public BarChartExport(String keyColumnHeader, + BarChartExport(String keyColumnHeader, String valueFormatString, String chartTitle, List categories) { @@ -177,7 +177,7 @@ public class BarChartExport implements ExcelItemExportable, ExcelSheetExport { * @param colSize The column size of the chart. * @param rowSize The row size of the chart. */ - public BarChartExport(String keyColumnHeader, String valueFormatString, + BarChartExport(String keyColumnHeader, String valueFormatString, String chartTitle, String sheetName, List categories, int colOffset, int rowPadding, int colSize, int rowSize) { diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java index e4b4483675..4713fa8f0e 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java @@ -69,7 +69,7 @@ class DataSourceSummaryReport implements GeneralReportModule { @Override public JPanel getConfigurationPanel() { - return null; // No configuration panel + return null; // ELTODO } @Override diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java index 1e7a7d9a89..434ab34e96 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java @@ -42,19 +42,19 @@ import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.CellModel.Ho /** * Class for handling Excel exporting. */ -public class ExcelExport { +class ExcelExport { /** * Exception thrown in the event of an excel export issue. */ - public static class ExcelExportException extends Exception { + static class ExcelExportException extends Exception { /** * Constructor. * * @param string The message. */ - public ExcelExportException(String string) { + ExcelExportException(String string) { super(string); } @@ -64,7 +64,7 @@ public class ExcelExport { * @param string The message. * @param thrwbl The inner exception. */ - public ExcelExportException(String string, Throwable thrwbl) { + ExcelExportException(String string, Throwable thrwbl) { super(string, thrwbl); } } @@ -153,7 +153,7 @@ public class ExcelExport { /** * Class detailing aspects of the worksheet. */ - public static class WorksheetEnv { + static class WorksheetEnv { private final CellStyle headerStyle; private final Workbook parentWorkbook; @@ -182,7 +182,7 @@ public class ExcelExport { * @param cellStyleKey The key. * @return The cell style representing this key. */ - public CellStyle getCellStyle(CellStyleKey cellStyleKey) { + CellStyle getCellStyle(CellStyleKey cellStyleKey) { return cellStyleCache.computeIfAbsent(cellStyleKey, (pair) -> { CellStyle computed = this.parentWorkbook.createCellStyle(); computed.cloneStyleFrom(cellStyleKey.getCellStyle() == null ? defaultStyle : cellStyleKey.getCellStyle()); @@ -203,7 +203,7 @@ public class ExcelExport { * * @return The cell style to use for headers. */ - public CellStyle getHeaderStyle() { + CellStyle getHeaderStyle() { return headerStyle; } @@ -212,7 +212,7 @@ public class ExcelExport { * * @return The cell style for default items. */ - public CellStyle getDefaultCellStyle() { + CellStyle getDefaultCellStyle() { return defaultStyle; } @@ -221,7 +221,7 @@ public class ExcelExport { * * @return The parent workbook. */ - public Workbook getParentWorkbook() { + Workbook getParentWorkbook() { return parentWorkbook; } } @@ -229,7 +229,7 @@ public class ExcelExport { /** * An item to be exported as a sheet during export. */ - public static interface ExcelSheetExport { + static interface ExcelSheetExport { /** * Returns the name of the sheet to use with this item. @@ -257,7 +257,7 @@ public class ExcelExport { * * @return The instance. */ - public static ExcelExport getInstance() { + static ExcelExport getInstance() { if (instance == null) { instance = new ExcelExport(); } @@ -266,7 +266,6 @@ public class ExcelExport { } private ExcelExport() { - } /** @@ -281,7 +280,7 @@ public class ExcelExport { "# {0} - sheetNumber", "ExcelExport_writeExcel_noSheetName=Sheet {0}" }) - public void writeExcel(List exports, File path) throws IOException, ExcelExportException { + void writeExcel(List exports, File path) throws IOException, ExcelExportException { // Create a Workbook Workbook workbook = new XSSFWorkbook(); // new HSSFWorkbook() for generating `.xls` file diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelSpecialFormatExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelSpecialFormatExport.java index 71683d1d26..cd30e7d816 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelSpecialFormatExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelSpecialFormatExport.java @@ -28,13 +28,13 @@ import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport. /** * An excel export that has special row-by-row formatting. */ -public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { +class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { /** * The dimensions consumed by an item in an ExcelSpecialFormatExport list of * items to be rendered. */ - public static class ItemDimensions { + static class ItemDimensions { private final int rowStart; private final int rowEnd; @@ -49,7 +49,7 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { * @param rowEnd The last excel row of the the item. * @param colEnd The last excel column of the item. */ - public ItemDimensions(int rowStart, int colStart, int rowEnd, int colEnd) { + ItemDimensions(int rowStart, int colStart, int rowEnd, int colEnd) { this.rowStart = rowStart; this.colStart = colStart; this.rowEnd = rowEnd; @@ -59,28 +59,28 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { /** * @return The starting excel row of the item. */ - public int getRowStart() { + int getRowStart() { return rowStart; } /** * @return The last excel row of the the item. */ - public int getRowEnd() { + int getRowEnd() { return rowEnd; } /** * @return The starting excel column of the item. */ - public int getColStart() { + int getColStart() { return colStart; } /** * @return The last excel column of the item. */ - public int getColEnd() { + int getColEnd() { return colEnd; } } @@ -88,7 +88,7 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { /** * An item to be exported in a specially formatted excel export. */ - public interface ExcelItemExportable { + interface ExcelItemExportable { /** * Writes the item to the sheet in the special format export sheet. @@ -106,16 +106,16 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { /** * Writes a string to a single cell in a specially formatted excel export. */ - public static class SingleCellExportable implements ExcelItemExportable { + static class SingleCellExportable implements ExcelItemExportable { - private final DefaultCellModel item; + private final CellModel item; /** * Main constructor. * * @param key The text to be written. */ - public SingleCellExportable(String key) { + SingleCellExportable(String key) { this(new DefaultCellModel<>(key)); } @@ -124,7 +124,7 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { * * @param item The cell model to be written. */ - public SingleCellExportable(DefaultCellModel item) { + SingleCellExportable(CellModel item) { this.item = item; } @@ -140,10 +140,10 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { * Writes a row consisting of first column as a key and second column as a * value. */ - public static class KeyValueItemExportable implements ExcelItemExportable { + static class KeyValueItemExportable implements ExcelItemExportable { - private final DefaultCellModel key; - private final DefaultCellModel value; + private final CellModel key; + private final CellModel value; /** * Main constructor. @@ -151,7 +151,7 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { * @param key The string key to be exported. * @param value The cell model to be exported. */ - public KeyValueItemExportable(String key, DefaultCellModel value) { + KeyValueItemExportable(String key, CellModel value) { this(new DefaultCellModel<>(key), value); } @@ -161,7 +161,7 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { * @param key The cell key to be exported. * @param value The cell model to be exported. */ - public KeyValueItemExportable(DefaultCellModel key, DefaultCellModel value) { + KeyValueItemExportable(CellModel key, CellModel value) { this.key = key; this.value = value; } @@ -186,7 +186,7 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { * item 2 * */ - public static class TitledExportable implements ExcelItemExportable { + static class TitledExportable implements ExcelItemExportable { private static final int DEFAULT_INDENT = 1; @@ -199,7 +199,7 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { * @param title The title for the export. * @param children The children to be indented and enumerated. */ - public TitledExportable(String title, List children) { + TitledExportable(String title, List children) { this.title = title; this.children = children; } @@ -232,7 +232,7 @@ public class ExcelSpecialFormatExport implements ExcelExport.ExcelSheetExport { * @param sheetName The name of the sheet. * @param exports The row-by-row items to be exported. */ - public ExcelSpecialFormatExport(String sheetName, List exports) { + ExcelSpecialFormatExport(String sheetName, List exports) { this.sheetName = sheetName; this.exports = exports == null ? Collections.emptyList() : exports; } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartExport.java index cf37119996..33ed70cb21 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartExport.java @@ -44,14 +44,14 @@ import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecial * * Class that creates an excel pie chart along with data table. */ -public class PieChartExport implements ExcelItemExportable, ExcelSheetExport { +class PieChartExport implements ExcelItemExportable, ExcelSheetExport { private static final int DEFAULT_ROW_SIZE = 20; private static final int DEFAULT_COL_SIZE = 10; private static final int DEFAULT_ROW_PADDING = 1; private static final int DEFAULT_COL_OFFSET = 1; - private final ExcelTableExport tableExport; + private final ExcelTableExport tableExport; private final int colOffset; private final int rowPadding; private final int colSize; @@ -69,7 +69,7 @@ public class PieChartExport implements ExcelItemExportable, ExcelSheetExport { * @param chartTitle The title for the chart. * @param slices The values for the pie slices. */ - public PieChartExport(String keyColumnHeader, + PieChartExport(String keyColumnHeader, String valueColumnHeader, String valueFormatString, String chartTitle, List slices) { @@ -93,7 +93,7 @@ public class PieChartExport implements ExcelItemExportable, ExcelSheetExport { * @param colSize The column size of the chart. * @param rowSize The row size of the chart. */ - public PieChartExport(String keyColumnHeader, + PieChartExport(String keyColumnHeader, String valueColumnHeader, String valueFormatString, String chartTitle, String sheetName, List slices, From 356206bf505d31efc536372330c0f83023724271 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 5 Aug 2021 11:21:34 -0400 Subject: [PATCH 08/76] Moved excel tab generation code to report --- .../ui/BaseDataSourceSummaryPanel.java | 98 ------------- .../Bundle.properties-MERGED | 8 ++ .../datasourcesummaryexport/DataFetcher.java | 43 ++++++ .../ExcelExportAction.java | 120 +++++++++++++++- .../ExportRecentFiles.java | 129 ++++++++++++++++++ 5 files changed, 299 insertions(+), 99 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataFetcher.java create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index 97965ec9e8..2241cbedd9 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -473,104 +473,6 @@ abstract class BaseDataSourceSummaryPanel extends JPanel { } } - /** - * Function that converts data into a excel sheet data. - */ - // ELTODO protected interface ExcelExportFunction { - - /** - * Function that converts data into an excel sheet. - * - * @param data The data. - * @return The excel sheet export. - * @throws ExcelExportException - */ - // ExcelSheetExport convert(T data) throws ExcelExportException; - //} - - /** - * Helper method that converts data into an excel sheet export handling - * possible excel exceptions. - * - * @param excelConverter Function to convert data to an excel sheet export. - * @param data The data. If data is null, null will be returned. - * @param sheetName The name(s) of the sheet (to be used in the error - * message). - * @return The excel sheet export. - */ - /* ELTODO - protected static ExcelSheetExport convertToExcel(ExcelExportFunction excelConverter, T data, String sheetName) { - if (data == null) { - return null; - } - - try { - return excelConverter.convert(data); - } catch (ExcelExportException ex) { - logger.log(Level.WARNING, - String.format("There was an error while preparing export of worksheet(s): '%s'", - sheetName == null ? "" : sheetName), ex); - return null; - } - }*/ - - /** - * Returns an excel sheet export given the fetching of data or null if no - * export created. - * - * @param dataFetcher The means of fetching data. - * @param excelConverter The means of converting data to excel. - * @param sheetName The name of the sheet (for error handling reporting). - * @param ds The data source to use for fetching data. - * @return The excel sheet export or null if no export could be generated. - */ - /* ELTODO - protected static ExcelSheetExport getExport( - DataFetcher dataFetcher, ExcelExportFunction excelConverter, - String sheetName, DataSource ds) { - - T data = getFetchResult(dataFetcher, sheetName, ds); - return convertToExcel(excelConverter, data, sheetName); - }*/ - - /** - * Returns an excel table export of the data or null if no export created. - * - * @param columnsModel The model for the columns. - * @param sheetName The name for the sheet. - * @param data The data to be exported. - * @return The excel table export or null if no export could be generated. - */ - /* ELTODO - protected static ExcelSheetExport getTableExport(List> columnsModel, - String sheetName, List data) { - - return convertToExcel((dataList) -> new ExcelTableExport(sheetName, columnsModel, dataList), - data, - sheetName); - }*/ - - /** - * Returns an excel table export of the data or null if no export created. - * - * @param dataFetcher The means of fetching data for the data source and the - * export. - * @param columnsModel The model for the columns. - * @param sheetName The name for the sheet. - * @param ds The data source. - * @return The excel export or null if no export created. - */ - /* ELTODO - protected static ExcelSheetExport getTableExport( - DataFetcher> dataFetcher, List> columnsModel, - String sheetName, DataSource ds) { - - return getExport(dataFetcher, - (dataList) -> new ExcelTableExport(sheetName, columnsModel, dataList), - sheetName, - ds); - }*/ - /** * Utility method that shows a loading screen with loadable components, * create swing workers from the datafetch components and data source diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index 4388aad3e7..d754073fdc 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -15,3 +15,11 @@ ExcelExportAction_runXLSXExport_progressCancelActionTitle=Cancelling... ExcelExportAction_runXLSXExport_progressCancelTitle=Cancel # {0} - dataSource ExcelExportAction_runXLSXExport_progressTitle=Exporting {0} to XLSX +RecentFilePanel_col_header_domain=Domain +RecentFilePanel_col_header_path=Path +RecentFilePanel_col_header_sender=Sender +RecentFilePanel_emailParserModuleName=Email Parser +RecentFilesPanel_attachmentsTable_tabName=Recent Attachments +RecentFilesPanel_col_head_date=Date +RecentFilesPanel_docsTable_tabName=Recently Opened Documents +RecentFilesPanel_downloadsTable_tabName=Recently Downloads diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataFetcher.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataFetcher.java new file mode 100755 index 0000000000..f3b0b0fe6c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataFetcher.java @@ -0,0 +1,43 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 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.report.modules.datasourcesummaryexport; + +/** + * A function that accepts input of type I and outputs type O. This function is + * meant to be utilized with DataFetchWorker and can therefore, throw an + * interrupted exception if the processing is cancelled or an Exception of on + * another type in the event that the fetching encountered an error. + */ +@FunctionalInterface +public interface DataFetcher { + + /** + * A function that accepts an input argument and outputs a result. Since it + * is meant to be used with the DataFetchWorker, it may throw an interrupted + * exception if the thread has been interrupted. It throws another type of + * exception if there is an error during fetching. + * + * @param input The input argument. + * + * @return The output result. + * + * @throws Exception + */ + O runQuery(I input) throws Exception; +} diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index b839fe8aac..460c9bc554 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -34,7 +34,6 @@ import java.util.concurrent.ExecutionException; import java.util.function.Consumer; import java.util.logging.Level; import javax.swing.JOptionPane; -import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; @@ -297,4 +296,123 @@ class ExcelExportAction implements Consumer { logger.log(Level.WARNING, "There was an error attaching report to case.", ex); } } + + /** + * Function that converts data into a excel sheet data. + */ + protected interface ExcelExportFunction { + + /** + * Function that converts data into an excel sheet. + * + * @param data The data. + * @return The excel sheet export. + * @throws ExcelExportException + */ + ExcelSheetExport convert(T data) throws ExcelExportException; + } + + /** + * Runs a data fetcher and returns the result handling any possible errors + * with a log message. + * + * @param dataFetcher The means of fetching the data. + * @param sheetName The name of the sheet. + * @param ds The data source. + * + * @return The fetched data. + */ + protected static T getFetchResult( + DataFetcher dataFetcher, + String sheetName, DataSource ds) { + + try { + return dataFetcher.runQuery(ds); + } catch (Exception ex) { + logger.log(Level.WARNING, + String.format("There was an error while acquiring data for exporting worksheet(s): '%s' for dataSource: %s", + sheetName == null ? "" : sheetName, + ds == null || ds.getName() == null ? "" : ds.getName()), ex); + return null; + } + } + + /** + * Helper method that converts data into an excel sheet export handling + * possible excel exceptions. + * + * @param excelConverter Function to convert data to an excel sheet export. + * @param data The data. If data is null, null will be returned. + * @param sheetName The name(s) of the sheet (to be used in the error + * message). + * @return The excel sheet export. + */ + protected static ExcelSheetExport convertToExcel(ExcelExportFunction excelConverter, T data, String sheetName) { + if (data == null) { + return null; + } + + try { + return excelConverter.convert(data); + } catch (ExcelExportException ex) { + logger.log(Level.WARNING, + String.format("There was an error while preparing export of worksheet(s): '%s'", + sheetName == null ? "" : sheetName), ex); + return null; + } + } + + /** + * Returns an excel sheet export given the fetching of data or null if no + * export created. + * + * @param dataFetcher The means of fetching data. + * @param excelConverter The means of converting data to excel. + * @param sheetName The name of the sheet (for error handling reporting). + * @param ds The data source to use for fetching data. + * @return The excel sheet export or null if no export could be generated. + */ + protected static ExcelSheetExport getExport( + DataFetcher dataFetcher, ExcelExportFunction excelConverter, + String sheetName, DataSource ds) { + + T data = getFetchResult(dataFetcher, sheetName, ds); + return convertToExcel(excelConverter, data, sheetName); + } + + /** + * Returns an excel table export of the data or null if no export created. + * + * @param columnsModel The model for the columns. + * @param sheetName The name for the sheet. + * @param data The data to be exported. + * @return The excel table export or null if no export could be generated. + */ + protected static ExcelSheetExport getTableExport(List> columnsModel, + String sheetName, List data) { + + return convertToExcel((dataList) -> new ExcelTableExport(sheetName, columnsModel, dataList), + data, + sheetName); + } + + /** + * Returns an excel table export of the data or null if no export created. + * + * @param dataFetcher The means of fetching data for the data source and the + * export. + * @param columnsModel The model for the columns. + * @param sheetName The name for the sheet. + * @param ds The data source. + * @return The excel export or null if no export created. + */ + protected static ExcelSheetExport getTableExport( + DataFetcher> dataFetcher, List> columnsModel, + String sheetName, DataSource ds) { + + return getExport(dataFetcher, + (dataList) -> new ExcelTableExport(sheetName, columnsModel, dataList), + sheetName, + ds); + } } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java new file mode 100755 index 0000000000..efa328c294 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java @@ -0,0 +1,129 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.report.modules.datasourcesummaryexport; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.contentutils.RecentFilesSummary; +import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentAttachmentDetails; +import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentDownloadDetails; +import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentFileDetails; +import org.sleuthkit.datamodel.DataSource; + +/** + * Data Source Summary recent files panel. + */ +@Messages({ + "RecentFilesPanel_docsTable_tabName=Recently Opened Documents", + "RecentFilesPanel_downloadsTable_tabName=Recently Downloads", + "RecentFilesPanel_attachmentsTable_tabName=Recent Attachments",}) +final class ExportRecentFiles { + + private static final String DATETIME_FORMAT_STR = "yyyy/MM/dd HH:mm:ss"; + private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat(DATETIME_FORMAT_STR, Locale.getDefault()); + + private final DataFetcher> docsFetcher; + private final DataFetcher> downloadsFetcher; + private final DataFetcher> attachmentsFetcher; + + private final List>> docsTemplate = Arrays.asList( + new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), + (prog) -> { + return new DefaultCellModel<>(prog.getPath()); + }, 250), + new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(), + getDateFunct(), + 80)); + + private final List>> downloadsTemplate = Arrays.asList( + new ColumnModel<>(Bundle.RecentFilePanel_col_header_domain(), + (prog) -> { + return new DefaultCellModel<>(prog.getWebDomain()); + }, 100), + new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), + (prog) -> { + return new DefaultCellModel<>(prog.getPath()); + }, 250), + new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(), + getDateFunct(), + 80)); + + private final List>> attachmentsTemplate = Arrays.asList( + new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), + (prog) -> { + return new DefaultCellModel<>(prog.getPath()); + }, 250), + new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(), + getDateFunct(), + 80), + new ColumnModel<>(Bundle.RecentFilePanel_col_header_sender(), + (prog) -> { + return new DefaultCellModel<>(prog.getSender()); + }, 150)); + + /** + * Default constructor. + */ + @Messages({ + "RecentFilesPanel_col_head_date=Date", + "RecentFilePanel_col_header_domain=Domain", + "RecentFilePanel_col_header_path=Path", + "RecentFilePanel_col_header_sender=Sender", + "RecentFilePanel_emailParserModuleName=Email Parser" + }) + + /** + * Creates new form RecentFilesPanel + */ + ExportRecentFiles() { + docsFetcher = (dataSource) -> RecentFilesSummary.getRecentlyOpenedDocuments(dataSource, 10); + downloadsFetcher = (dataSource) -> RecentFilesSummary.getRecentDownloads(dataSource, 10); + attachmentsFetcher = (dataSource) -> RecentFilesSummary.getRecentAttachments(dataSource, 10); + } + + /** + * Returns a function that gets the date from the RecentFileDetails object and + * converts into a DefaultCellModel to be displayed in a table. + * + * @return The function that determines the date cell from a RecentFileDetails object. + */ + private Function> getDateFunct() { + return (T lastAccessed) -> { + Function dateParser = (dt) -> dt == null ? "" : DATETIME_FORMAT.format(dt); + return new DefaultCellModel<>(new Date(lastAccessed.getDateAsLong() * 1000), dateParser, DATETIME_FORMAT_STR); + }; + } + + List getExports(DataSource dataSource) { + return Stream.of( + ExcelExportAction.getTableExport(docsFetcher, docsTemplate, Bundle.RecentFilesPanel_docsTable_tabName(), dataSource), + ExcelExportAction.getTableExport(downloadsFetcher, downloadsTemplate, Bundle.RecentFilesPanel_downloadsTable_tabName(), dataSource), + ExcelExportAction.getTableExport(attachmentsFetcher, attachmentsTemplate, Bundle.RecentFilesPanel_attachmentsTable_tabName(), dataSource)) + .filter(sheet -> sheet != null) + .collect(Collectors.toList()); + } +} From 1e2a8efbc5f7a23120f16a95e0a0122a535935e9 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 5 Aug 2021 14:59:07 -0400 Subject: [PATCH 09/76] Making excel reports work in report module --- .../ui/BaseDataSourceSummaryPanel.java | 1 - .../Bundle.properties-MERGED | 9 +- .../DataSourceSummaryReport.java | 40 +++- .../datasourcesummaryexport/ExcelExport.java | 17 +- .../ExcelExportAction.java | 215 +++--------------- .../ExportRecentFiles.java | 27 +-- 6 files changed, 76 insertions(+), 233 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index 2241cbedd9..6ac490eb11 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -38,7 +38,6 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index d754073fdc..220e32dcca 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -4,17 +4,10 @@ DataSourceSummaryReport.endReport.srcModuleName.text=Excel Report # {0} - sheetNumber ExcelExport_writeExcel_noSheetName=Sheet {0} ExcelExportAction_exportToXLSX_beginExport=Beginning Export... -# {0} - tabName -ExcelExportAction_exportToXLSX_gatheringTabData=Fetching Data for {0} Tab... +ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data ExcelExportAction_exportToXLSX_writingToFile=Writing to File... ExcelExportAction_getXLSXPath_directory=DataSourceSummary ExcelExportAction_moduleName=Data Source Summary -ExcelExportAction_runXLSXExport_errorMessage=There was an error while exporting. -ExcelExportAction_runXLSXExport_errorTitle=Error While Exporting -ExcelExportAction_runXLSXExport_progressCancelActionTitle=Cancelling... -ExcelExportAction_runXLSXExport_progressCancelTitle=Cancel -# {0} - dataSource -ExcelExportAction_runXLSXExport_progressTitle=Exporting {0} to XLSX RecentFilePanel_col_header_domain=Domain RecentFilePanel_col_header_path=Path RecentFilePanel_col_header_sender=Sender diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java index 4713fa8f0e..1b659dd23e 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java @@ -18,10 +18,13 @@ */ package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport; +import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.stream.Collectors; import javax.swing.JPanel; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -30,6 +33,7 @@ import org.sleuthkit.autopsy.report.GeneralReportModule; import org.sleuthkit.autopsy.report.GeneralReportSettings; import org.sleuthkit.autopsy.report.ReportProgressPanel; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; class DataSourceSummaryReport implements GeneralReportModule { @@ -79,6 +83,7 @@ class DataSourceSummaryReport implements GeneralReportModule { @Override public void generateReport(GeneralReportSettings settings, ReportProgressPanel progressPanel) { + progressPanel.start(); Case currentCase = null; try { currentCase = Case.getCurrentCaseThrows(); @@ -87,31 +92,46 @@ class DataSourceSummaryReport implements GeneralReportModule { return; } + String errorMessage = ""; + ReportProgressPanel.ReportStatus result = ReportProgressPanel.ReportStatus.COMPLETE; + List selectedDataSources = new ArrayList<>(); if(settings.getSelectedDataSources() == null) { // Process all data sources if the list is null. try { - List selectedDataSources = currentCase.getDataSources() - .stream() - .map(Content::getId) - .collect(Collectors.toList()); - settings.setSelectedDataSources(selectedDataSources); + selectedDataSources = currentCase.getDataSources(); + // ELTODO settings.setSelectedDataSources(selectedDataSources); } catch (TskCoreException ex) { + result = ReportProgressPanel.ReportStatus.ERROR; + // ELTODO errorMessage = Bundle.KMLReport_failedToCompleteReport(); logger.log(Level.SEVERE, "Could not get the datasources from the case", ex); + progressPanel.complete(result, errorMessage); return; } } String baseReportDir = settings.getReportDirectoryPath(); // Start the progress bar and setup the report - progressPanel.setIndeterminate(true); - progressPanel.start(); + // ELTODO progressPanel.setIndeterminate(true); + //progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.querying")); String reportFullPath = baseReportDir + getRelativeFilePath(); //NON-NLS - String errorMessage = ""; - //progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.loading")); + + // looop over all data sources + for (Content dataSource : selectedDataSources){ + if (dataSource instanceof DataSource) { + try { + new ExcelExportAction().exportToXLSX(progressPanel, (DataSource) dataSource, reportFullPath); + } catch (IOException | ExcelExport.ExcelExportException ex) { + // ELTODO errorMessage = Bundle.KMLReport_kmlFileWriteError(); + logger.log(Level.SEVERE, errorMessage, ex); //NON-NLS + progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR, errorMessage); + return; + } + } + } - ReportProgressPanel.ReportStatus result = ReportProgressPanel.ReportStatus.COMPLETE; + progressPanel.complete(result, errorMessage); } } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java index 434ab34e96..4cc589bba8 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java @@ -250,21 +250,6 @@ class ExcelExport { void renderSheet(Sheet sheet, WorksheetEnv env) throws ExcelExportException; } - private static ExcelExport instance = null; - - /** - * Retrieves a singleton instance of this class. - * - * @return The instance. - */ - static ExcelExport getInstance() { - if (instance == null) { - instance = new ExcelExport(); - } - - return instance; - } - private ExcelExport() { } @@ -280,7 +265,7 @@ class ExcelExport { "# {0} - sheetNumber", "ExcelExport_writeExcel_noSheetName=Sheet {0}" }) - void writeExcel(List exports, File path) throws IOException, ExcelExportException { + static void writeExcel(List exports, File path) throws IOException, ExcelExportException { // Create a Workbook Workbook workbook = new XSSFWorkbook(); // new HSSFWorkbook() for generating `.xls` file diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index 460c9bc554..71007094a2 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -18,34 +18,24 @@ */ package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Collections; import java.util.Date; import java.util.List; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.function.Consumer; import java.util.logging.Level; -import javax.swing.JOptionPane; -import javax.swing.SwingWorker; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; -import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.report.ReportProgressPanel; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelExportException; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelSheetExport; -import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator; -import org.sleuthkit.autopsy.progress.ProgressIndicator; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; @@ -54,61 +44,16 @@ import org.sleuthkit.datamodel.TskCoreException; */ @Messages({ "ExcelExportAction_moduleName=Data Source Summary",}) -class ExcelExportAction implements Consumer { +class ExcelExportAction { private static final Logger logger = Logger.getLogger(ExcelExportAction.class.getName()); - /** - * A tab that can be exported. - */ - interface ExportableTab { - - /** - * Returns the name of the tab. - * - * @return The tab name. - */ - String getTabTitle(); - - /** - * Given the data source, provides the excel exports for this tab. - * - * @param dataSource The data source. - * @return The excel exports or null. - */ - List getExcelExports(DataSource dataSource); - } - - private final ExcelExport excelExport = ExcelExport.getInstance(); - private final List tabExports; - /** * Main constructor. * * @param tabExports The different tabs that may have excel exports. */ - ExcelExportAction(List tabExports) { - this.tabExports = Collections.unmodifiableList(new ArrayList<>(tabExports)); - } - - /** - * Accepts the data source for which this export pertains, prompts user for - * output location, and exports the data. - * - * @param ds The data source. - */ - @Override - public void accept(DataSource ds) { - if (ds == null) { - return; - } - - File outputLoc = getXLSXPath(ds.getName()); - if (outputLoc == null) { - return; - } - - runXLSXExport(ds, outputLoc); + ExcelExportAction() { } /** @@ -140,99 +85,10 @@ class ExcelExportAction implements Consumer { return null; } - /** - * An action listener that handles cancellation of the export process. - */ - private class CancelExportListener implements ActionListener { - - private SwingWorker worker = null; - - @Override - public void actionPerformed(ActionEvent e) { - if (worker != null && !worker.isCancelled() && !worker.isDone()) { - worker.cancel(true); - } - } - - /** - * Returns the swing worker that could be cancelled. - * - * @return The swing worker that could be cancelled. - */ - SwingWorker getWorker() { - return worker; - } - - /** - * Sets the swing worker that could be cancelled. - * - * @param worker The swing worker that could be cancelled. - */ - void setWorker(SwingWorker worker) { - this.worker = worker; - } - } - - /** - * Handles managing the gui and exporting data from the tabs into an excel - * document. - * - * @param dataSource The data source. - * @param path The output path. - */ - @NbBundle.Messages({ - "# {0} - dataSource", - "ExcelExportAction_runXLSXExport_progressTitle=Exporting {0} to XLSX", - "ExcelExportAction_runXLSXExport_progressCancelTitle=Cancel", - "ExcelExportAction_runXLSXExport_progressCancelActionTitle=Cancelling...", - "ExcelExportAction_runXLSXExport_errorTitle=Error While Exporting", - "ExcelExportAction_runXLSXExport_errorMessage=There was an error while exporting.", - }) - private void runXLSXExport(DataSource dataSource, File path) { - - CancelExportListener cancelButtonListener = new CancelExportListener(); - - ProgressIndicator progressIndicator = new ModalDialogProgressIndicator( - WindowManager.getDefault().getMainWindow(), - Bundle.ExcelExportAction_runXLSXExport_progressTitle(dataSource.getName()), - new String[]{Bundle.ExcelExportAction_runXLSXExport_progressCancelTitle()}, - Bundle.ExcelExportAction_runXLSXExport_progressCancelTitle(), - cancelButtonListener - ); - - SwingWorker worker = new SwingWorker() { - @Override - protected Boolean doInBackground() throws Exception { - exportToXLSX(progressIndicator, dataSource, path); - return true; - } - - @Override - protected void done() { - try { - get(); - } catch (ExecutionException ex) { - logger.log(Level.WARNING, "Error while trying to export data source summary to xlsx.", ex); - JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), - Bundle.ExcelExportAction_runXLSXExport_errorMessage(), - Bundle.ExcelExportAction_runXLSXExport_errorTitle(), - JOptionPane.ERROR_MESSAGE); - } catch (InterruptedException | CancellationException ex) { - // no op on cancellation - } finally { - progressIndicator.finish(); - } - } - }; - - cancelButtonListener.setWorker(worker); - worker.execute(); - } - /** * Action that handles updating progress and exporting data from the tabs. * - * @param progressIndicator The progress indicator. + * @param progressPanel The progress indicator. * @param dataSource The data source to be exported. * @param path The path of the excel export. * @throws InterruptedException @@ -241,57 +97,52 @@ class ExcelExportAction implements Consumer { */ @NbBundle.Messages({ "ExcelExportAction_exportToXLSX_beginExport=Beginning Export...", - "# {0} - tabName", - "ExcelExportAction_exportToXLSX_gatheringTabData=Fetching Data for {0} Tab...", + "ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data", "ExcelExportAction_exportToXLSX_writingToFile=Writing to File...",}) - private void exportToXLSX(ProgressIndicator progressIndicator, DataSource dataSource, File path) - throws InterruptedException, IOException, ExcelExport.ExcelExportException { + void exportToXLSX(ReportProgressPanel progressPanel, DataSource dataSource, String path) + throws IOException, ExcelExport.ExcelExportException { - int exportWeight = 3; - int totalWeight = tabExports.size() + exportWeight; - progressIndicator.start(Bundle.ExcelExportAction_exportToXLSX_beginExport(), totalWeight); + File reportFile = new File(path); + int totalWeight = 10; + progressPanel.setIndeterminate(false); + progressPanel.setMaximumProgress(totalWeight); + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_beginExport()); List sheetExports = new ArrayList<>(); - for (int i = 0; i < tabExports.size(); i++) { - if (Thread.interrupted()) { - throw new InterruptedException("Export has been cancelled."); - } - ExportableTab tab = tabExports.get(i); - progressIndicator.progress(Bundle.ExcelExportAction_exportToXLSX_gatheringTabData(tab == null ? "" : tab.getTabTitle()), i); + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringRecentActivityData()); + progressPanel.setProgress(1); - List exports = tab.getExcelExports(dataSource); - if (exports != null) { - sheetExports.addAll(exports); - } + // Export Recent Activity data + List exports = ExportRecentFiles.getExports(dataSource); + if (exports != null) { + sheetExports.addAll(exports); } - if (Thread.interrupted()) { - throw new InterruptedException("Export has been cancelled."); - } + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_writingToFile()); + progressPanel.setProgress(2); + ExcelExport.writeExcel(sheetExports, reportFile); - progressIndicator.progress(Bundle.ExcelExportAction_exportToXLSX_writingToFile(), tabExports.size()); - excelExport.writeExcel(sheetExports, path); - - progressIndicator.finish(); + progressPanel.complete(ReportProgressPanel.ReportStatus.COMPLETE, ""); try { // add to reports Case curCase = Case.getCurrentCaseThrows(); - curCase.addReport(path.getParent(), + curCase.addReport(reportFile.getParent(), Bundle.ExcelExportAction_moduleName(), - path.getName(), + reportFile.getName(), dataSource); // and show finished dialog - /* ELTODO SwingUtilities.invokeLater(() -> { - ExcelExportDialog dialog = new ExcelExportDialog(WindowManager.getDefault().getMainWindow(), path); - dialog.setResizable(false); - dialog.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); - dialog.setVisible(true); - dialog.toFront(); - });*/ - + /* + * ELTODO SwingUtilities.invokeLater(() -> { ExcelExportDialog + * dialog = new + * ExcelExportDialog(WindowManager.getDefault().getMainWindow(), + * path); dialog.setResizable(false); + * dialog.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + * dialog.setVisible(true); dialog.toFront(); + }); + */ } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.WARNING, "There was an error attaching report to case.", ex); } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java index efa328c294..b6cfd6a027 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java @@ -46,11 +46,7 @@ final class ExportRecentFiles { private static final String DATETIME_FORMAT_STR = "yyyy/MM/dd HH:mm:ss"; private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat(DATETIME_FORMAT_STR, Locale.getDefault()); - private final DataFetcher> docsFetcher; - private final DataFetcher> downloadsFetcher; - private final DataFetcher> attachmentsFetcher; - - private final List>> docsTemplate = Arrays.asList( + private static final List>> docsTemplate = Arrays.asList( new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), (prog) -> { return new DefaultCellModel<>(prog.getPath()); @@ -59,7 +55,7 @@ final class ExportRecentFiles { getDateFunct(), 80)); - private final List>> downloadsTemplate = Arrays.asList( + private static final List>> downloadsTemplate = Arrays.asList( new ColumnModel<>(Bundle.RecentFilePanel_col_header_domain(), (prog) -> { return new DefaultCellModel<>(prog.getWebDomain()); @@ -72,7 +68,7 @@ final class ExportRecentFiles { getDateFunct(), 80)); - private final List>> attachmentsTemplate = Arrays.asList( + private static final List>> attachmentsTemplate = Arrays.asList( new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), (prog) -> { return new DefaultCellModel<>(prog.getPath()); @@ -96,13 +92,7 @@ final class ExportRecentFiles { "RecentFilePanel_emailParserModuleName=Email Parser" }) - /** - * Creates new form RecentFilesPanel - */ - ExportRecentFiles() { - docsFetcher = (dataSource) -> RecentFilesSummary.getRecentlyOpenedDocuments(dataSource, 10); - downloadsFetcher = (dataSource) -> RecentFilesSummary.getRecentDownloads(dataSource, 10); - attachmentsFetcher = (dataSource) -> RecentFilesSummary.getRecentAttachments(dataSource, 10); + private ExportRecentFiles() { } /** @@ -111,14 +101,19 @@ final class ExportRecentFiles { * * @return The function that determines the date cell from a RecentFileDetails object. */ - private Function> getDateFunct() { + private static Function> getDateFunct() { return (T lastAccessed) -> { Function dateParser = (dt) -> dt == null ? "" : DATETIME_FORMAT.format(dt); return new DefaultCellModel<>(new Date(lastAccessed.getDateAsLong() * 1000), dateParser, DATETIME_FORMAT_STR); }; } - List getExports(DataSource dataSource) { + static List getExports(DataSource dataSource) { + + DataFetcher> docsFetcher = (ds) -> RecentFilesSummary.getRecentlyOpenedDocuments(ds, 10); + DataFetcher> downloadsFetcher = (ds) -> RecentFilesSummary.getRecentDownloads(ds, 10); + DataFetcher> attachmentsFetcher = (ds) -> RecentFilesSummary.getRecentAttachments(ds, 10); + return Stream.of( ExcelExportAction.getTableExport(docsFetcher, docsTemplate, Bundle.RecentFilesPanel_docsTable_tabName(), dataSource), ExcelExportAction.getTableExport(downloadsFetcher, downloadsTemplate, Bundle.RecentFilesPanel_downloadsTable_tabName(), dataSource), From 7e2354c91484ae63377d572b8ae867661550e1c5 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 5 Aug 2021 16:02:35 -0400 Subject: [PATCH 10/76] bug fixes and improvements --- .../DataSourceSummaryReport.java | 35 +++++++++++++++---- .../ExcelExportAction.java | 21 ++++------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java index 1b659dd23e..5eba7e2a36 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java @@ -26,6 +26,7 @@ import java.util.stream.Collectors; import javax.swing.JPanel; import org.openide.util.Exceptions; import org.openide.util.NbBundle; +import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; @@ -36,7 +37,12 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; -class DataSourceSummaryReport implements GeneralReportModule { +/** + * Instances of this class plug in to the reporting infrastructure to provide a + * convenient way to extract data source summary information into Excel. + */ +@ServiceProvider(service = GeneralReportModule.class) +public class DataSourceSummaryReport implements GeneralReportModule { private static final Logger logger = Logger.getLogger(DataSourceSummaryReport.class.getName()); private static DataSourceSummaryReport instance; @@ -49,8 +55,7 @@ class DataSourceSummaryReport implements GeneralReportModule { return instance; } - // Hidden constructor - private DataSourceSummaryReport() { + public DataSourceSummaryReport() { } @@ -62,7 +67,7 @@ class DataSourceSummaryReport implements GeneralReportModule { @Override public String getRelativeFilePath() { - return "DataSourceSummaryReport.xlsx"; //NON-NLS + return ""; //ELTODO "DataSourceSummaryReport.xlsx"; //NON-NLS } @Override @@ -98,8 +103,12 @@ class DataSourceSummaryReport implements GeneralReportModule { if(settings.getSelectedDataSources() == null) { // Process all data sources if the list is null. try { - selectedDataSources = currentCase.getDataSources(); - // ELTODO settings.setSelectedDataSources(selectedDataSources); + selectedDataSources = currentCase.getDataSources(); + List dsIDs = selectedDataSources + .stream() + .map(Content::getId) + .collect(Collectors.toList()); + settings.setSelectedDataSources(dsIDs); } catch (TskCoreException ex) { result = ReportProgressPanel.ReportStatus.ERROR; // ELTODO errorMessage = Bundle.KMLReport_failedToCompleteReport(); @@ -107,6 +116,18 @@ class DataSourceSummaryReport implements GeneralReportModule { progressPanel.complete(result, errorMessage); return; } + } else { + for (Long dsID : settings.getSelectedDataSources()) { + try { + selectedDataSources.add(currentCase.getSleuthkitCase().getContentById(dsID)); + } catch (TskCoreException ex) { + result = ReportProgressPanel.ReportStatus.ERROR; + // ELTODO errorMessage = Bundle.KMLReport_failedToCompleteReport(); + logger.log(Level.SEVERE, "Could not get the datasources from the case", ex); + progressPanel.complete(result, errorMessage); + return; + } + } } String baseReportDir = settings.getReportDirectoryPath(); @@ -121,7 +142,7 @@ class DataSourceSummaryReport implements GeneralReportModule { for (Content dataSource : selectedDataSources){ if (dataSource instanceof DataSource) { try { - new ExcelExportAction().exportToXLSX(progressPanel, (DataSource) dataSource, reportFullPath); + new ExcelExportAction().exportToXLSX(progressPanel, (DataSource) dataSource, baseReportDir); } catch (IOException | ExcelExport.ExcelExportException ex) { // ELTODO errorMessage = Bundle.KMLReport_kmlFileWriteError(); logger.log(Level.SEVERE, errorMessage, ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index 71007094a2..0f957acb31 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -65,24 +65,17 @@ class ExcelExportAction { */ @NbBundle.Messages({ "ExcelExportAction_getXLSXPath_directory=DataSourceSummary",}) - private File getXLSXPath(String dataSourceName) { + File getXLSXPath(String dataSourceName, String baseReportDir) { // set initial path to reports directory with filename that is // a combination of the data source name and time stamp DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss"); String fileName = String.format("%s-%s.xlsx", dataSourceName == null ? "" : FileUtil.escapeFileName(dataSourceName), dateFormat.format(new Date())); - try { - String reportsDir = Case.getCurrentCaseThrows().getReportDirectory(); - File reportsDirFile = Paths.get(reportsDir, Bundle.ExcelExportAction_getXLSXPath_directory()).toFile(); - if (!reportsDirFile.exists()) { - reportsDirFile.mkdirs(); - } - - return Paths.get(reportsDirFile.getAbsolutePath(), fileName).toFile(); - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Unable to find reports directory.", ex); + File reportsDirFile = Paths.get(baseReportDir, Bundle.ExcelExportAction_getXLSXPath_directory()).toFile(); + if (!reportsDirFile.exists()) { + reportsDirFile.mkdirs(); } - return null; + return Paths.get(reportsDirFile.getAbsolutePath(), fileName).toFile(); } /** @@ -100,10 +93,10 @@ class ExcelExportAction { "ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data", "ExcelExportAction_exportToXLSX_writingToFile=Writing to File...",}) - void exportToXLSX(ReportProgressPanel progressPanel, DataSource dataSource, String path) + void exportToXLSX(ReportProgressPanel progressPanel, DataSource dataSource, String baseReportDir) throws IOException, ExcelExport.ExcelExportException { - File reportFile = new File(path); + File reportFile = getXLSXPath(dataSource.getName(), baseReportDir); int totalWeight = 10; progressPanel.setIndeterminate(false); progressPanel.setMaximumProgress(totalWeight); From da1ec9bef647e27fbd9fb668ce3c36babc442255 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 5 Aug 2021 16:40:00 -0400 Subject: [PATCH 11/76] Refactoring --- .../Bundle.properties-MERGED | 16 +++---- .../DataSourceSummaryReport.java | 1 - .../ExportRecentFiles.java | 44 +++++++++---------- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index 220e32dcca..6c96e246b0 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -8,11 +8,11 @@ ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activ ExcelExportAction_exportToXLSX_writingToFile=Writing to File... ExcelExportAction_getXLSXPath_directory=DataSourceSummary ExcelExportAction_moduleName=Data Source Summary -RecentFilePanel_col_header_domain=Domain -RecentFilePanel_col_header_path=Path -RecentFilePanel_col_header_sender=Sender -RecentFilePanel_emailParserModuleName=Email Parser -RecentFilesPanel_attachmentsTable_tabName=Recent Attachments -RecentFilesPanel_col_head_date=Date -RecentFilesPanel_docsTable_tabName=Recently Opened Documents -RecentFilesPanel_downloadsTable_tabName=Recently Downloads +ExportRecentFiles_attachmentsTable_tabName=Recent Attachments +ExportRecentFiles_col_head_date=Date +ExportRecentFiles_col_header_domain=Domain +ExportRecentFiles_col_header_path=Path +ExportRecentFiles_col_header_sender=Sender +ExportRecentFiles_docsTable_tabName=Recently Opened Documents +ExportRecentFiles_downloadsTable_tabName=Recently Downloads +ExportRecentFiles_emailParserModuleName=Email Parser diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java index 5eba7e2a36..693667ceb1 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.logging.Level; import java.util.stream.Collectors; import javax.swing.JPanel; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.Case; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java index b6cfd6a027..2b9f244d3f 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java @@ -38,59 +38,55 @@ import org.sleuthkit.datamodel.DataSource; * Data Source Summary recent files panel. */ @Messages({ - "RecentFilesPanel_docsTable_tabName=Recently Opened Documents", - "RecentFilesPanel_downloadsTable_tabName=Recently Downloads", - "RecentFilesPanel_attachmentsTable_tabName=Recent Attachments",}) + "ExportRecentFiles_docsTable_tabName=Recently Opened Documents", + "ExportRecentFiles_downloadsTable_tabName=Recently Downloads", + "ExportRecentFiles_attachmentsTable_tabName=Recent Attachments", + "ExportRecentFiles_col_head_date=Date", + "ExportRecentFiles_col_header_domain=Domain", + "ExportRecentFiles_col_header_path=Path", + "ExportRecentFiles_col_header_sender=Sender", + "ExportRecentFiles_emailParserModuleName=Email Parser" +}) final class ExportRecentFiles { private static final String DATETIME_FORMAT_STR = "yyyy/MM/dd HH:mm:ss"; private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat(DATETIME_FORMAT_STR, Locale.getDefault()); private static final List>> docsTemplate = Arrays.asList( - new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), + new ColumnModel<>(Bundle.ExportRecentFiles_col_header_path(), (prog) -> { return new DefaultCellModel<>(prog.getPath()); }, 250), - new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(), + new ColumnModel<>(Bundle.ExportRecentFiles_col_head_date(), getDateFunct(), 80)); private static final List>> downloadsTemplate = Arrays.asList( - new ColumnModel<>(Bundle.RecentFilePanel_col_header_domain(), + new ColumnModel<>(Bundle.ExportRecentFiles_col_header_domain(), (prog) -> { return new DefaultCellModel<>(prog.getWebDomain()); }, 100), - new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), + new ColumnModel<>(Bundle.ExportRecentFiles_col_header_path(), (prog) -> { return new DefaultCellModel<>(prog.getPath()); }, 250), - new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(), + new ColumnModel<>(Bundle.ExportRecentFiles_col_head_date(), getDateFunct(), 80)); private static final List>> attachmentsTemplate = Arrays.asList( - new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), + new ColumnModel<>(Bundle.ExportRecentFiles_col_header_path(), (prog) -> { return new DefaultCellModel<>(prog.getPath()); }, 250), - new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(), + new ColumnModel<>(Bundle.ExportRecentFiles_col_head_date(), getDateFunct(), 80), - new ColumnModel<>(Bundle.RecentFilePanel_col_header_sender(), + new ColumnModel<>(Bundle.ExportRecentFiles_col_header_sender(), (prog) -> { return new DefaultCellModel<>(prog.getSender()); }, 150)); - /** - * Default constructor. - */ - @Messages({ - "RecentFilesPanel_col_head_date=Date", - "RecentFilePanel_col_header_domain=Domain", - "RecentFilePanel_col_header_path=Path", - "RecentFilePanel_col_header_sender=Sender", - "RecentFilePanel_emailParserModuleName=Email Parser" - }) private ExportRecentFiles() { } @@ -115,9 +111,9 @@ final class ExportRecentFiles { DataFetcher> attachmentsFetcher = (ds) -> RecentFilesSummary.getRecentAttachments(ds, 10); return Stream.of( - ExcelExportAction.getTableExport(docsFetcher, docsTemplate, Bundle.RecentFilesPanel_docsTable_tabName(), dataSource), - ExcelExportAction.getTableExport(downloadsFetcher, downloadsTemplate, Bundle.RecentFilesPanel_downloadsTable_tabName(), dataSource), - ExcelExportAction.getTableExport(attachmentsFetcher, attachmentsTemplate, Bundle.RecentFilesPanel_attachmentsTable_tabName(), dataSource)) + ExcelExportAction.getTableExport(docsFetcher, docsTemplate, Bundle.ExportRecentFiles_docsTable_tabName(), dataSource), + ExcelExportAction.getTableExport(downloadsFetcher, downloadsTemplate, Bundle.ExportRecentFiles_downloadsTable_tabName(), dataSource), + ExcelExportAction.getTableExport(attachmentsFetcher, attachmentsTemplate, Bundle.ExportRecentFiles_attachmentsTable_tabName(), dataSource)) .filter(sheet -> sheet != null) .collect(Collectors.toList()); } From 1a9f8bd8883d98c9b6da29345acddece9cc44825 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 5 Aug 2021 17:26:32 -0400 Subject: [PATCH 12/76] Bug fix for dates in Excel file --- .../datasourcesummaryexport/Bundle.properties-MERGED | 1 - .../report/modules/datasourcesummaryexport/CellModel.java | 6 ++++++ .../modules/datasourcesummaryexport/DefaultCellModel.java | 7 +++++++ .../modules/datasourcesummaryexport/ExcelExport.java | 4 ++-- .../modules/datasourcesummaryexport/ExportRecentFiles.java | 3 +-- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index 6c96e246b0..42143965be 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -15,4 +15,3 @@ ExportRecentFiles_col_header_path=Path ExportRecentFiles_col_header_sender=Sender ExportRecentFiles_docsTable_tabName=Recently Opened Documents ExportRecentFiles_downloadsTable_tabName=Recently Downloads -ExportRecentFiles_emailParserModuleName=Email Parser diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/CellModel.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/CellModel.java index bae7d770b7..ce072525ea 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/CellModel.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/CellModel.java @@ -82,4 +82,10 @@ interface CellModel { * @return The horizontal alignment for the text in the cell. */ HorizontalAlign getHorizontalAlignment(); + + /** + * @return The format string to be used with Apache POI during excel + * export or null if none necessary. + */ + String getExcelFormatString(); } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DefaultCellModel.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DefaultCellModel.java index 149d3413f6..c2e2b7d085 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DefaultCellModel.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DefaultCellModel.java @@ -27,6 +27,7 @@ class DefaultCellModel implements CellModel { private final T data; private final String text; private CellModel.HorizontalAlign horizontalAlignment; + private final String excelFormatString; /** * Main constructor. @@ -62,6 +63,7 @@ class DefaultCellModel implements CellModel { */ DefaultCellModel(T data, Function stringConverter, String excelFormatString) { this.data = data; + this.excelFormatString = excelFormatString; if (stringConverter == null) { text = this.data == null ? "" : this.data.toString(); @@ -84,6 +86,11 @@ class DefaultCellModel implements CellModel { public HorizontalAlign getHorizontalAlignment() { return horizontalAlignment; } + + @Override + public String getExcelFormatString() { + return this.excelFormatString; + } /** * Sets the horizontal alignment for this cell model. diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java index 4cc589bba8..47087dd985 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExport.java @@ -324,8 +324,8 @@ class ExcelExport { static Cell createCell(WorksheetEnv env, Row row, int colNum, CellModel cellModel, Optional cellStyle) { CellStyle cellStyleToUse = cellStyle.orElse(env.getDefaultCellStyle()); - if (cellModel.getText() != null || cellModel.getHorizontalAlignment() != null) { - cellStyleToUse = env.getCellStyle(new CellStyleKey(cellModel.getText(), cellStyleToUse, cellModel.getHorizontalAlignment())); + if (cellModel.getExcelFormatString() != null || cellModel.getHorizontalAlignment() != null) { + cellStyleToUse = env.getCellStyle(new CellStyleKey(cellModel.getExcelFormatString(), cellStyleToUse, cellModel.getHorizontalAlignment())); } Object cellData = cellModel.getData(); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java index 2b9f244d3f..1864dc5332 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java @@ -44,8 +44,7 @@ import org.sleuthkit.datamodel.DataSource; "ExportRecentFiles_col_head_date=Date", "ExportRecentFiles_col_header_domain=Domain", "ExportRecentFiles_col_header_path=Path", - "ExportRecentFiles_col_header_sender=Sender", - "ExportRecentFiles_emailParserModuleName=Email Parser" + "ExportRecentFiles_col_header_sender=Sender" }) final class ExportRecentFiles { From 343b8c792a29428e791ad9484ceadd4f2e8f69ac Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 5 Aug 2021 17:27:12 -0400 Subject: [PATCH 13/76] Minor --- .../ui/RecentFilesPanel.java | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index 52e0721cc8..3b082e5849 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -66,7 +66,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { private final DataFetcher> attachmentsFetcher; private final List>> docsTemplate = Arrays.asList( - new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), + new ColumnModel<>(Bundle.RecentFilesPanel_col_header_path(), (prog) -> { return new DefaultCellModel<>(prog.getPath()) .setPopupMenuRetriever(getPopupFunct(prog)); @@ -76,12 +76,12 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { 80)); private final List>> downloadsTemplate = Arrays.asList( - new ColumnModel<>(Bundle.RecentFilePanel_col_header_domain(), + new ColumnModel<>(Bundle.RecentFilesPanel_col_header_domain(), (prog) -> { return new DefaultCellModel<>(prog.getWebDomain()) .setPopupMenuRetriever(getPopupFunct(prog)); }, 100), - new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), + new ColumnModel<>(Bundle.RecentFilesPanel_col_header_path(), (prog) -> { return new DefaultCellModel<>(prog.getPath()) .setPopupMenuRetriever(getPopupFunct(prog)); @@ -91,7 +91,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { 80)); private final List>> attachmentsTemplate = Arrays.asList( - new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(), + new ColumnModel<>(Bundle.RecentFilesPanel_col_header_path(), (prog) -> { return new DefaultCellModel<>(prog.getPath()) .setPopupMenuRetriever(getPopupFunct(prog)); @@ -99,7 +99,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(), getDateFunct(), 80), - new ColumnModel<>(Bundle.RecentFilePanel_col_header_sender(), + new ColumnModel<>(Bundle.RecentFilesPanel_col_header_sender(), (prog) -> { return new DefaultCellModel<>(prog.getSender()) .setPopupMenuRetriever(getPopupFunct(prog)); @@ -110,10 +110,9 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { */ @Messages({ "RecentFilesPanel_col_head_date=Date", - "RecentFilePanel_col_header_domain=Domain", - "RecentFilePanel_col_header_path=Path", - "RecentFilePanel_col_header_sender=Sender", - "RecentFilePanel_emailParserModuleName=Email Parser" + "RecentFilesPanel_col_header_domain=Domain", + "RecentFilesPanel_col_header_path=Path", + "RecentFilesPanel_col_header_sender=Sender" }) public RecentFilesPanel() { this(new RecentFilesGetter()); @@ -186,17 +185,6 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { onNewDataSource(dataFetchComponents, tablePanelList, dataSource); } - /* ELTODO - @Override - List getExports(DataSource dataSource) { - return Stream.of( - getTableExport(docsFetcher, docsTemplate, Bundle.RecentFilesPanel_docsTable_tabName(), dataSource), - getTableExport(downloadsFetcher, downloadsTemplate, Bundle.RecentFilesPanel_downloadsTable_tabName(), dataSource), - getTableExport(attachmentsFetcher, attachmentsTemplate, Bundle.RecentFilesPanel_attachmentsTable_tabName(), dataSource)) - .filter(sheet -> sheet != null) - .collect(Collectors.toList()); - }*/ - @Override public void close() { ingestRunningLabel.unregister(); @@ -213,7 +201,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { } @Messages({ - "RecentFilePanel_no_open_documents=No recently open documents found." + "RecentFilesPanel_no_open_documents=No recently open documents found." }) /** * Setup the data model and columns for the recently open table. From 5fe0b036129ea5354251b5344db19d2d5fe89137 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Fri, 6 Aug 2021 10:31:19 -0400 Subject: [PATCH 14/76] moved data fetchers out of ContainerPanel into contentutils package --- .../contentutils/ContainerSummary.java | 434 ++++++++++++++++++ .../datamodel/ContainerSummary.java | 235 ---------- .../datamodel/ContainerSummaryGetter.java | 144 ++++++ .../ui/Bundle.properties-MERGED | 9 +- .../datasourcesummary/ui/ContainerPanel.java | 298 +----------- .../datasourcesummary/ui/TypesPanel.java | 6 +- 6 files changed, 602 insertions(+), 524 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java delete mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java new file mode 100755 index 0000000000..0f0e9cb72e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java @@ -0,0 +1,434 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020-2021 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.contentutils; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; + +/** + * Provides methods to query for data source overview details. + */ +public class ContainerSummary { + + private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( + BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_INFO.getTypeID(), + BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID() + )); + + private ContainerSummary() { + } + + public static Set getArtifactTypeIdsForRefresh() { + return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS); + } + + /** + * Gets the size of unallocated files in a particular datasource. + * + * @param currentDataSource The data source. + * + * @return The size or null if the query could not be executed. + * + * @throws NoCurrentCaseException + * @throws TskCoreException + * @throws SQLException + */ + public static Long getSizeOfUnallocatedFiles(DataSource currentDataSource) + throws TskCoreException, SQLException, NoCurrentCaseException { + if (currentDataSource == null) { + return null; + } + + final String valueParam = "value"; + final String countParam = "count"; + String query = "SELECT SUM(size) AS " + valueParam + ", COUNT(*) AS " + countParam + + " FROM tsk_files" + + " WHERE " + DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC) + + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType() + + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() + + " AND name<>''" + + " AND data_source_obj_id=" + currentDataSource.getId(); + + DataSourceInfoUtilities.ResultSetHandler handler = (resultSet) -> { + if (resultSet.next()) { + // ensure that there is an unallocated count result that is attached to this data source + long resultCount = resultSet.getLong(valueParam); + return (resultCount > 0) ? resultSet.getLong(valueParam) : null; + } else { + return null; + } + }; + + return DataSourceInfoUtilities.getBaseQueryResult(query, handler); + } + + /** + * Retrieves the concatenation of operating system attributes for a + * particular data source. + * + * @param dataSource The data source. + * + * @return The concatenated value or null if the query could not be + * executed. + * + * @throws NoCurrentCaseException + * @throws TskCoreException + * @throws SQLException + */ + public static String getOperatingSystems(DataSource dataSource) + throws TskCoreException, SQLException, NoCurrentCaseException { + + if (dataSource == null) { + return null; + } + + return getConcattedAttrValue(dataSource.getId(), + BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_INFO.getTypeID(), + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID()); + } + + /** + * Retrieves the concatenation of data source usage for a particular data + * source. + * + * @param dataSource The data source. + * + * @return The concatenated value or null if the query could not be + * executed. + * + * @throws NoCurrentCaseException + * @throws TskCoreException + * @throws SQLException + */ + public static String getDataSourceType(DataSource dataSource) + throws TskCoreException, SQLException, NoCurrentCaseException { + + if (dataSource == null) { + return null; + } + + return getConcattedAttrValue(dataSource.getId(), + BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID(), + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID()); + } + + /** + * Generates a string which is a concatenation of the value received from + * the result set. + * + * @param query The query. + * @param valueParam The parameter for the value in the result set. + * @param separator The string separator used in concatenation. + * + * @return The concatenated string or null if the query could not be + * executed. + * + * @throws NoCurrentCaseException + * @throws TskCoreException + * @throws SQLException + */ + private static String getConcattedStringsResult(String query, String valueParam, String separator) + throws TskCoreException, SQLException, NoCurrentCaseException { + + DataSourceInfoUtilities.ResultSetHandler handler = (resultSet) -> { + String toRet = ""; + boolean first = true; + while (resultSet.next()) { + if (first) { + first = false; + } else { + toRet += separator; + } + toRet += resultSet.getString(valueParam); + } + + return toRet; + }; + + return DataSourceInfoUtilities.getBaseQueryResult(query, handler); + } + + /** + * Generates a concatenated string value based on the text value of a + * particular attribute in a particular artifact for a specific data source. + * + * @param dataSourceId The data source id. + * @param artifactTypeId The artifact type id. + * @param attributeTypeId The attribute type id. + * + * @return The concatenated value or null if the query could not be + * executed. + * + * @throws NoCurrentCaseException + * @throws TskCoreException + * @throws SQLException + */ + private static String getConcattedAttrValue(long dataSourceId, int artifactTypeId, int attributeTypeId) + throws TskCoreException, SQLException, NoCurrentCaseException { + + final String valueParam = "concatted_attribute_value"; + String query = "SELECT attr.value_text AS " + valueParam + + " FROM blackboard_artifacts bba " + + " INNER JOIN blackboard_attributes attr ON bba.artifact_id = attr.artifact_id " + + " WHERE bba.data_source_obj_id = " + dataSourceId + + " AND bba.artifact_type_id = " + artifactTypeId + + " AND attr.attribute_type_id = " + attributeTypeId; + + String separator = ", "; + return getConcattedStringsResult(query, valueParam, separator); + } + + /** + * Data model data for data source images. + */ + public static class ImageDetails { + + private final long unallocatedSize; + private final long size; + private final long sectorSize; + + private final String timeZone; + private final String imageType; + + private final List paths; + private final String md5Hash; + private final String sha1Hash; + private final String sha256Hash; + + /** + * Main constructor. + * + * @param unallocatedSize Size in bytes of unallocated space. + * @param size Total size in bytes. + * @param sectorSize Sector size in bytes. + * @param timeZone The time zone. + * @param imageType The type of image. + * @param paths The source paths for the image. + * @param md5Hash The md5 hash or null. + * @param sha1Hash The sha1 hash or null. + * @param sha256Hash The sha256 hash or null. + */ + ImageDetails(long unallocatedSize, long size, long sectorSize, + String timeZone, String imageType, List paths, String md5Hash, + String sha1Hash, String sha256Hash) { + this.unallocatedSize = unallocatedSize; + this.size = size; + this.sectorSize = sectorSize; + this.timeZone = timeZone; + this.imageType = imageType; + this.paths = paths == null ? Collections.emptyList() : new ArrayList<>(paths); + this.md5Hash = md5Hash; + this.sha1Hash = sha1Hash; + this.sha256Hash = sha256Hash; + } + + /** + * @return Size in bytes of unallocated space. + */ + public long getUnallocatedSize() { + return unallocatedSize; + } + + /** + * @return Total size in bytes. + */ + public long getSize() { + return size; + } + + /** + * @return Sector size in bytes. + */ + public long getSectorSize() { + return sectorSize; + } + + /** + * @return The time zone. + */ + public String getTimeZone() { + return timeZone; + } + + /** + * @return The type of image. + */ + public String getImageType() { + return imageType; + } + + /** + * @return The source paths for the image. + */ + public List getPaths() { + return Collections.unmodifiableList(paths); + } + + /** + * @return The md5 hash or null. + */ + public String getMd5Hash() { + return md5Hash; + } + + /** + * @return The sha1 hash or null. + */ + public String getSha1Hash() { + return sha1Hash; + } + + /** + * @return The sha256 hash or null. + */ + public String getSha256Hash() { + return sha256Hash; + } + } + + /** + * Data model for container data. + */ + public static class ContainerDetails { + + private final String displayName; + private final String originalName; + private final String deviceIdValue; + private final String acquisitionDetails; + private final ImageDetails imageDetails; + + /** + * Main constructor. + * + * @param displayName The display name for this data source. + * @param originalName The original name for this data source. + * @param deviceIdValue The device id value for this data source. + * @param acquisitionDetails The acquisition details for this data + * source or null. + * @param imageDetails If the data source is an image, the image + * data model for this data source or null if + * non-image. + */ + ContainerDetails(String displayName, String originalName, String deviceIdValue, + String acquisitionDetails, ImageDetails imageDetails) { + this.displayName = displayName; + this.originalName = originalName; + this.deviceIdValue = deviceIdValue; + this.acquisitionDetails = acquisitionDetails; + this.imageDetails = imageDetails; + } + + /** + * @return The display name for this data source. + */ + public String getDisplayName() { + return displayName; + } + + /** + * @return The original name for this data source. + */ + public String getOriginalName() { + return originalName; + } + + /** + * @return The device id value for this data source. + */ + public String getDeviceId() { + return deviceIdValue; + } + + /** + * @return The acquisition details for this data source or null. + */ + public String getAcquisitionDetails() { + return acquisitionDetails; + } + + /** + * @return If the data source is an image, the image details for this + * data source or null if non-image. + */ + public ImageDetails getImageDetails() { + return imageDetails; + } + } + + /** + * Generates a container data model object containing data about + * the data source. + * + * @param ds The data source. + * + * @return The generated view model. + */ + public static ContainerDetails getContainerDetails(DataSource ds) throws TskCoreException, SQLException, NoCurrentCaseException { + if (ds == null) { + return null; + } + + return new ContainerDetails( + ds.getName(), + ds.getName(), + ds.getDeviceId(), + ds.getAcquisitionDetails(), + ds instanceof Image ? getImageDetails((Image) ds) : null + ); + } + + /** + * Generates an image data model object containing data about the + * image. + * + * @param image The image. + * + * @return The generated view model. + */ + public static ImageDetails getImageDetails(Image image) throws TskCoreException, SQLException, NoCurrentCaseException { + if (image == null) { + return null; + } + + Long unallocSize = getSizeOfUnallocatedFiles(image); + String imageType = image.getType().getName(); + Long size = image.getSize(); + Long sectorSize = image.getSsize(); + String timeZone = image.getTimeZone(); + List paths = image.getPaths() == null ? Collections.emptyList() : Arrays.asList(image.getPaths()); + String md5 = image.getMd5(); + String sha1 = image.getSha1(); + String sha256 = image.getSha256(); + + return new ImageDetails(unallocSize, size, sectorSize, timeZone, imageType, paths, md5, sha1, sha256); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java deleted file mode 100644 index eb11b99b2a..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2020 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.datasourcesummary.datamodel; - -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; -import org.sleuthkit.autopsy.ingest.ModuleContentEvent; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskData; - -/** - * Provides methods to query for data source overview details. - */ -public class ContainerSummary implements DefaultArtifactUpdateGovernor { - - private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( - BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_INFO.getTypeID(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID() - )); - - private final SleuthkitCaseProvider provider; - - /** - * Main constructor. - */ - public ContainerSummary() { - this(SleuthkitCaseProvider.DEFAULT); - } - - /** - * Main constructor. - * - * @param provider The means of obtaining a sleuthkit case. - */ - public ContainerSummary(SleuthkitCaseProvider provider) { - this.provider = provider; - } - - @Override - public boolean isRefreshRequired(ModuleContentEvent evt) { - return true; - } - - @Override - public boolean isRefreshRequired(AbstractFile file) { - return true; - } - - @Override - public Set getArtifactTypeIdsForRefresh() { - return ARTIFACT_UPDATE_TYPE_IDS; - } - - /** - * Gets the size of unallocated files in a particular datasource. - * - * @param currentDataSource The data source. - * - * @return The size or null if the query could not be executed. - * - * @throws SleuthkitCaseProviderException - * @throws TskCoreException - * @throws SQLException - */ - public Long getSizeOfUnallocatedFiles(DataSource currentDataSource) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - if (currentDataSource == null) { - return null; - } - - final String valueParam = "value"; - final String countParam = "count"; - String query = "SELECT SUM(size) AS " + valueParam + ", COUNT(*) AS " + countParam - + " FROM tsk_files" - + " WHERE " + DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC) - + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType() - + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() - + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() - + " AND name<>''" - + " AND data_source_obj_id=" + currentDataSource.getId(); - - DataSourceInfoUtilities.ResultSetHandler handler = (resultSet) -> { - if (resultSet.next()) { - // ensure that there is an unallocated count result that is attached to this data source - long resultCount = resultSet.getLong(valueParam); - return (resultCount > 0) ? resultSet.getLong(valueParam) : null; - } else { - return null; - } - }; - - return DataSourceInfoUtilities.getBaseQueryResult(provider.get(), query, handler); - } - - /** - * Retrieves the concatenation of operating system attributes for a - * particular data source. - * - * @param dataSource The data source. - * - * @return The concatenated value or null if the query could not be - * executed. - * - * @throws SleuthkitCaseProviderException - * @throws TskCoreException - * @throws SQLException - */ - public String getOperatingSystems(DataSource dataSource) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - - if (dataSource == null) { - return null; - } - - return getConcattedAttrValue(dataSource.getId(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_INFO.getTypeID(), - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID()); - } - - /** - * Retrieves the concatenation of data source usage for a particular data - * source. - * - * @param dataSource The data source. - * - * @return The concatenated value or null if the query could not be - * executed. - * - * @throws SleuthkitCaseProviderException - * @throws TskCoreException - * @throws SQLException - */ - public String getDataSourceType(DataSource dataSource) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - - if (dataSource == null) { - return null; - } - - return getConcattedAttrValue(dataSource.getId(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID(), - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID()); - } - - /** - * Generates a string which is a concatenation of the value received from - * the result set. - * - * @param query The query. - * @param valueParam The parameter for the value in the result set. - * @param separator The string separator used in concatenation. - * - * @return The concatenated string or null if the query could not be - * executed. - * - * @throws SleuthkitCaseProviderException - * @throws TskCoreException - * @throws SQLException - */ - private String getConcattedStringsResult(String query, String valueParam, String separator) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - - DataSourceInfoUtilities.ResultSetHandler handler = (resultSet) -> { - String toRet = ""; - boolean first = true; - while (resultSet.next()) { - if (first) { - first = false; - } else { - toRet += separator; - } - toRet += resultSet.getString(valueParam); - } - - return toRet; - }; - - return DataSourceInfoUtilities.getBaseQueryResult(provider.get(), query, handler); - } - - /** - * Generates a concatenated string value based on the text value of a - * particular attribute in a particular artifact for a specific data source. - * - * @param dataSourceId The data source id. - * @param artifactTypeId The artifact type id. - * @param attributeTypeId The attribute type id. - * - * @return The concatenated value or null if the query could not be - * executed. - * - * @throws SleuthkitCaseProviderException - * @throws TskCoreException - * @throws SQLException - */ - private String getConcattedAttrValue(long dataSourceId, int artifactTypeId, int attributeTypeId) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - - final String valueParam = "concatted_attribute_value"; - String query = "SELECT attr.value_text AS " + valueParam - + " FROM blackboard_artifacts bba " - + " INNER JOIN blackboard_attributes attr ON bba.artifact_id = attr.artifact_id " - + " WHERE bba.data_source_obj_id = " + dataSourceId - + " AND bba.artifact_type_id = " + artifactTypeId - + " AND attr.attribute_type_id = " + attributeTypeId; - - String separator = ", "; - return getConcattedStringsResult(query, valueParam, separator); - } -} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java new file mode 100644 index 0000000000..1238a36bd1 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java @@ -0,0 +1,144 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 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.datasourcesummary.datamodel; + +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; +import java.sql.SQLException; +import java.util.Set; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.contentutils.ContainerSummary; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.ingest.ModuleContentEvent; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Wrapper class for converting org.sleuthkit.autopsy.contentutils.ContainerSummary functionality into + * a DefaultArtifactUpdateGovernor used by Container tab. + */ +public class ContainerSummaryGetter implements DefaultArtifactUpdateGovernor { + + /** + * Main constructor. + */ + public ContainerSummaryGetter() { + } + + @Override + public boolean isRefreshRequired(ModuleContentEvent evt) { + return true; + } + + @Override + public boolean isRefreshRequired(AbstractFile file) { + return true; + } + + @Override + public Set getArtifactTypeIdsForRefresh() { + return ContainerSummary.getArtifactTypeIdsForRefresh(); + } + + /** + * Gets the size of unallocated files in a particular datasource. + * + * @param currentDataSource The data source. + * + * @return The size or null if the query could not be executed. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + * @throws SQLException + */ + public Long getSizeOfUnallocatedFiles(DataSource currentDataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { + try { + return ContainerSummary.getSizeOfUnallocatedFiles(currentDataSource); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } + + /** + * Retrieves the concatenation of operating system attributes for a + * particular data source. + * + * @param dataSource The data source. + * + * @return The concatenated value or null if the query could not be + * executed. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + * @throws SQLException + */ + public String getOperatingSystems(DataSource dataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { + try { + return ContainerSummary.getOperatingSystems(dataSource); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } + + /** + * Retrieves the concatenation of data source usage for a particular data + * source. + * + * @param dataSource The data source. + * + * @return The concatenated value or null if the query could not be + * executed. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + * @throws SQLException + */ + public String getDataSourceType(DataSource dataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { + try { + return ContainerSummary.getDataSourceType(dataSource); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } + + /** + * Retrieves a container data model object containing data about + * the data source. + * + * @param dataSource The data source. + * + * @return The concatenated value or null if the query could not be + * executed. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + * @throws SQLException + */ + public ContainerSummary.ContainerDetails getContainerDetails(DataSource dataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { + try { + return ContainerSummary.getContainerDetails(dataSource); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED index 2f5056ae25..b3c57b15dc 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -73,15 +73,14 @@ PastCasesPanel_countColumn_title=Count PastCasesPanel_notableFileTable_tabName=Cases with Common Notable PastCasesPanel_onNoCrIngest_message=No results will be shown because the Central Repository module was not run. PastCasesPanel_sameIdsTable_tabName=Past Cases with the Same Devices -RecentFilePanel_col_header_domain=Domain -RecentFilePanel_col_header_path=Path -RecentFilePanel_col_header_sender=Sender -RecentFilePanel_emailParserModuleName=Email Parser -RecentFilePanel_no_open_documents=No recently open documents found. RecentFilesPanel_attachmentsTable_tabName=Recent Attachments RecentFilesPanel_col_head_date=Date +RecentFilesPanel_col_header_domain=Domain +RecentFilesPanel_col_header_path=Path +RecentFilesPanel_col_header_sender=Sender RecentFilesPanel_docsTable_tabName=Recently Opened Documents RecentFilesPanel_downloadsTable_tabName=Recently Downloads +RecentFilesPanel_no_open_documents=No recently open documents found. SizeRepresentationUtil_units_bytes=bytes SizeRepresentationUtil_units_gigabytes=GB SizeRepresentationUtil_units_kilobytes=KB diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java index 1f46f48d48..1ab2c83afd 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,31 +19,24 @@ package org.sleuthkit.autopsy.datasourcesummary.ui; import java.beans.PropertyChangeEvent; -import java.sql.SQLException; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.table.DefaultTableModel; -import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.contentutils.ContainerSummary.ContainerDetails; +import org.sleuthkit.autopsy.contentutils.ContainerSummary.ImageDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummaryGetter; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; import org.sleuthkit.autopsy.datasourcesummary.uiutils.UpdateGovernor; import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.Image; -import org.sleuthkit.datamodel.TskCoreException; /** * Panel to display additional details associated with a specific DataSource @@ -53,182 +46,6 @@ import org.sleuthkit.datamodel.TskCoreException; }) class ContainerPanel extends BaseDataSourceSummaryPanel { - /** - * View model data for data source images. - */ - private static class ImageViewModel { - - private final long unallocatedSize; - private final long size; - private final long sectorSize; - - private final String timeZone; - private final String imageType; - - private final List paths; - private final String md5Hash; - private final String sha1Hash; - private final String sha256Hash; - - /** - * Main constructor. - * - * @param unallocatedSize Size in bytes of unallocated space. - * @param size Total size in bytes. - * @param sectorSize Sector size in bytes. - * @param timeZone The time zone. - * @param imageType The type of image. - * @param paths The source paths for the image. - * @param md5Hash The md5 hash or null. - * @param sha1Hash The sha1 hash or null. - * @param sha256Hash The sha256 hash or null. - */ - ImageViewModel(long unallocatedSize, long size, long sectorSize, - String timeZone, String imageType, List paths, String md5Hash, - String sha1Hash, String sha256Hash) { - this.unallocatedSize = unallocatedSize; - this.size = size; - this.sectorSize = sectorSize; - this.timeZone = timeZone; - this.imageType = imageType; - this.paths = paths == null ? Collections.emptyList() : new ArrayList<>(paths); - this.md5Hash = md5Hash; - this.sha1Hash = sha1Hash; - this.sha256Hash = sha256Hash; - } - - /** - * @return Size in bytes of unallocated space. - */ - long getUnallocatedSize() { - return unallocatedSize; - } - - /** - * @return Total size in bytes. - */ - long getSize() { - return size; - } - - /** - * @return Sector size in bytes. - */ - long getSectorSize() { - return sectorSize; - } - - /** - * @return The time zone. - */ - String getTimeZone() { - return timeZone; - } - - /** - * @return The type of image. - */ - String getImageType() { - return imageType; - } - - /** - * @return The source paths for the image. - */ - List getPaths() { - return paths; - } - - /** - * @return The md5 hash or null. - */ - String getMd5Hash() { - return md5Hash; - } - - /** - * @return The sha1 hash or null. - */ - String getSha1Hash() { - return sha1Hash; - } - - /** - * @return The sha256 hash or null. - */ - String getSha256Hash() { - return sha256Hash; - } - } - - /** - * View model for container data. - */ - private static class ContainerViewModel { - - private final String displayName; - private final String originalName; - private final String deviceIdValue; - private final String acquisitionDetails; - private final ImageViewModel imageViewModel; - - /** - * Main constructor. - * - * @param displayName The display name for this data source. - * @param originalName The original name for this data source. - * @param deviceIdValue The device id value for this data source. - * @param acquisitionDetails The acquisition details for this data - * source or null. - * @param imageViewModel If the data source is an image, the image view - * model for this data source or null if non-image. - */ - ContainerViewModel(String displayName, String originalName, String deviceIdValue, - String acquisitionDetails, ImageViewModel imageViewModel) { - this.displayName = displayName; - this.originalName = originalName; - this.deviceIdValue = deviceIdValue; - this.acquisitionDetails = acquisitionDetails; - this.imageViewModel = imageViewModel; - } - - /** - * @return The display name for this data source. - */ - String getDisplayName() { - return displayName; - } - - /** - * @return The original name for this data source. - */ - String getOriginalName() { - return originalName; - } - - /** - * @return The device id value for this data source. - */ - String getDeviceId() { - return deviceIdValue; - } - - /** - * @return The acquisition details for this data source or null. - */ - String getAcquisitionDetails() { - return acquisitionDetails; - } - - /** - * @return If the data source is an image, the image view model for this - * data source or null if non-image. - */ - ImageViewModel getImageViewModel() { - return imageViewModel; - } - } - // set of case events for which to call update (if the name changes, that will impact data shown) private static final Set CASE_EVENT_SET = new HashSet<>(Arrays.asList( Case.Events.DATA_SOURCE_NAME_CHANGED @@ -254,29 +71,29 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { private static final Logger logger = Logger.getLogger(ContainerPanel.class.getName()); private final List> dataFetchComponents; - private final DataFetcher containerDataFetcher; + private final DataFetcher containerDataFetcher; /** * Creates a new form ContainerPanel. */ ContainerPanel() { - this(new ContainerSummary()); + this(new ContainerSummaryGetter()); } /** * Creates new form ContainerPanel. */ - ContainerPanel(ContainerSummary containerSummary) { + ContainerPanel(ContainerSummaryGetter containerSummary) { super(containerSummary, CONTAINER_UPDATES); - containerDataFetcher = (dataSource) -> getContainerViewModel(containerSummary, dataSource); + containerDataFetcher = (dataSource) -> containerSummary.getContainerDetails(dataSource); dataFetchComponents = Arrays.asList( new DataFetchComponents<>( containerDataFetcher, (result) -> { if (result != null && result.getResultType() == ResultType.SUCCESS) { - ContainerViewModel data = result.getData(); + ContainerDetails data = result.getData(); updateDetailsPanelData(data); } else { if (result == null) { @@ -305,92 +122,12 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { fetchInformation(dataFetchComponents, dataSource); } - /** - * A means of retrieving data that could potentially throw an exception. - */ - private interface Retriever { - - /** - * Retrieves data of a certain type and possibly throws an exception. - * - * @return The data type. - * @throws TskCoreException - * @throws SleuthkitCaseProviderException - * @throws SQLException - */ - O retrieve() throws TskCoreException, SleuthkitCaseProviderException, SQLException; - } - - /** - * Retrieves data of a particular type and handles any exceptions that may - * be thrown by logging. - * - * @param retriever The retrieving function. - * @return The retrieved data. - */ - private static O retrieve(Retriever retriever) { - try { - return retriever.retrieve(); - } catch (TskCoreException | SleuthkitCaseProviderException | SQLException ex) { - logger.log(Level.WARNING, "Error while retrieving data.", ex); - return null; - } - } - - /** - * Generates a container view model object containing data to display about - * the data source. - * - * @param containerSummary The service providing data about the data source. - * @param ds The data source. - * @return The generated view model. - */ - private static ContainerViewModel getContainerViewModel(ContainerSummary containerSummary, DataSource ds) { - if (ds == null) { - return null; - } - - return new ContainerViewModel( - ds.getName(), - ds.getName(), - ds.getDeviceId(), - retrieve(() -> ds.getAcquisitionDetails()), - ds instanceof Image ? getImageViewModel(containerSummary, (Image) ds) : null - ); - } - - /** - * Generates an image view model object containing data to display about the - * image. - * - * @param containerSummary The service providing data about the image. - * @param image The image. - * @return The generated view model. - */ - private static ImageViewModel getImageViewModel(ContainerSummary containerSummary, Image image) { - if (image == null) { - return null; - } - - Long unallocSize = retrieve(() -> containerSummary.getSizeOfUnallocatedFiles(image)); - String imageType = image.getType().getName(); - Long size = image.getSize(); - Long sectorSize = image.getSsize(); - String timeZone = image.getTimeZone(); - List paths = image.getPaths() == null ? Collections.emptyList() : Arrays.asList(image.getPaths()); - String md5 = retrieve(() -> image.getMd5()); - String sha1 = retrieve(() -> image.getSha1()); - String sha256 = retrieve(() -> image.getSha256()); - - return new ImageViewModel(unallocSize, size, sectorSize, timeZone, imageType, paths, md5, sha1, sha256); - } - /** * Update the swing components with fetched data. * * @param viewModel The data source view model data. */ - private void updateDetailsPanelData(ContainerViewModel viewModel) { + private void updateDetailsPanelData(ContainerDetails viewModel) { clearTableValues(); if (viewModel == null) { return; @@ -401,8 +138,8 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { deviceIdValue.setText(viewModel.getDeviceId()); acquisitionDetailsTextArea.setText(viewModel.getAcquisitionDetails()); - if (viewModel.getImageViewModel() != null) { - setFieldsForImage(viewModel.getImageViewModel()); + if (viewModel.getImageDetails() != null) { + setFieldsForImage(viewModel.getImageDetails()); } else { setFieldsForNonImageDataSource(); } @@ -437,7 +174,7 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { * * @param viewModel The image view model data. */ - private void setFieldsForImage(ImageViewModel viewModel) { + private void setFieldsForImage(ImageDetails viewModel) { unallocatedSizeValue.setText(SizeRepresentationUtil.getSizeString(viewModel.getUnallocatedSize())); imageTypeValue.setText(viewModel.getImageType()); sizeValue.setText(SizeRepresentationUtil.getSizeString(viewModel.getSize())); @@ -490,9 +227,8 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { .filter(item -> item != null) .collect(Collectors.toList()); } - }*/ + } - /* ELTODO @Messages({ "ContainerPanel_export_displayName=Display Name:", "ContainerPanel_export_originalName=Name:", @@ -508,7 +244,7 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { "ContainerPanel_export_unallocatedSize=Unallocated Space:", "ContainerPanel_export_filePaths=File Paths:",}) protected List getExports(DataSource ds) { - ContainerViewModel result = getFetchResult(containerDataFetcher, "Container sheets", ds); + ContainerDetails result = getFetchResult(containerDataFetcher, "Container sheets", ds); if (ds == null || result == null) { return Collections.emptyList(); } @@ -516,7 +252,7 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { String NA = Bundle.ContainerPanel_setFieldsForNonImageDataSource_na(); DefaultCellModel NACell = new DefaultCellModel<>(NA); - ImageViewModel imageModel = result.getImageViewModel(); + ImageDetails imageModel = result.getImageDetails(); boolean hasImage = imageModel != null; DefaultCellModel timeZone = hasImage ? new DefaultCellModel<>(imageModel.getTimeZone()) : NACell; @@ -527,7 +263,7 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { DefaultCellModel sha1 = hasImage ? new DefaultCellModel<>(imageModel.getSha1Hash()) : NACell; DefaultCellModel sha256 = hasImage ? new DefaultCellModel<>(imageModel.getSha256Hash()) : NACell; DefaultCellModel unallocatedSize = hasImage ? SizeRepresentationUtil.getBytesCell(imageModel.getUnallocatedSize()) : NACell; - List paths = result.getImageViewModel() == null ? Collections.singletonList(NA) : result.getImageViewModel().getPaths(); + List paths = result.getImageDetails() == null ? Collections.singletonList(NA) : result.getImageDetails().getPaths(); List cellPaths = paths.stream() .map(SingleCellExportable::new) .collect(Collectors.toList()); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index 3e9ec03ea0..e333888d0c 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -32,7 +32,7 @@ import java.util.stream.Stream; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummaryGetter; import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; @@ -233,7 +233,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { * Creates a new TypesPanel. */ public TypesPanel() { - this(new MimeTypeSummary(), new TypesSummary(), new ContainerSummary()); + this(new MimeTypeSummary(), new TypesSummary(), new ContainerSummaryGetter()); } @Override @@ -252,7 +252,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { public TypesPanel( MimeTypeSummary mimeTypeData, TypesSummary typeData, - ContainerSummary containerData) { + ContainerSummaryGetter containerData) { super(mimeTypeData, typeData, containerData); From e1eda761eb25ff943fb860c0822183fd3d9318dd Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Fri, 6 Aug 2021 11:25:11 -0400 Subject: [PATCH 15/76] Moved Container summary Excel functionality to report module --- .../contentutils/ContainerSummary.java | 11 +- .../contentutils/DataSourceInfoUtilities.java | 12 +- .../contentutils/RecentFilesSummary.java | 2 +- .../datamodel/ContainerSummaryGetter.java | 2 +- .../datamodel/RecentFilesGetter.java | 21 +- .../datasourcesummary/ui/ContainerPanel.java | 78 -------- .../ui/RecentFilesPanel.java | 12 +- .../ui/SizeRepresentationUtil.java | 8 +- .../Bundle.properties-MERGED | 22 +++ .../ExcelExportAction.java | 14 +- .../ExportContainerInfo.java | 126 ++++++++++++ .../ExportRecentFiles.java | 10 +- .../SizeRepresentationUtil.java | 179 ++++++++++++++++++ 13 files changed, 378 insertions(+), 119 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/SizeRepresentationUtil.java diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java index 0f0e9cb72e..87a78093ca 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java @@ -385,10 +385,10 @@ public class ContainerSummary { } /** - * Generates a container data model object containing data about - * the data source. + * Generates a container data model object containing data about the data + * source. * - * @param ds The data source. + * @param ds The data source. * * @return The generated view model. */ @@ -407,10 +407,9 @@ public class ContainerSummary { } /** - * Generates an image data model object containing data about the - * image. + * Generates an image data model object containing data about the image. * - * @param image The image. + * @param image The image. * * @return The generated view model. */ diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/DataSourceInfoUtilities.java b/Core/src/org/sleuthkit/autopsy/contentutils/DataSourceInfoUtilities.java index 8fef1c54f0..b8bc2a54b6 100644 --- a/Core/src/org/sleuthkit/autopsy/contentutils/DataSourceInfoUtilities.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/DataSourceInfoUtilities.java @@ -29,6 +29,8 @@ import java.util.TreeMap; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.apache.commons.lang.StringUtils; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.Type; @@ -123,7 +125,6 @@ public final class DataSourceInfoUtilities { /** * Retrieves a result based on the provided query. * - * @param skCase The current SleuthkitCase. * @param query The query. * @param processor The result set handler. * @@ -132,10 +133,11 @@ public final class DataSourceInfoUtilities { * * @throws TskCoreException * @throws SQLException + * @throws NoCurrentCaseException */ - public static T getBaseQueryResult(SleuthkitCase skCase, String query, ResultSetHandler processor) - throws TskCoreException, SQLException { - try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(query)) { + public static T getBaseQueryResult(String query, ResultSetHandler processor) + throws TskCoreException, SQLException, NoCurrentCaseException { + try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCaseThrows().getSleuthkitCase().executeQuery(query)) { ResultSet resultSet = dbQuery.getResultSet(); return processor.process(resultSet); } @@ -398,7 +400,7 @@ public final class DataSourceInfoUtilities { BlackboardAttribute attr = getAttributeOrNull(artifact, attributeType); return (attr == null) ? null : attr.getValueLong(); } - + /** * Retrieves the int value of a certain attribute type from an artifact. * diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java index 62b80516cd..502e2c76a1 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java @@ -73,7 +73,7 @@ public class RecentFilesSummary { } public static Set getArtifactTypeIdsForRefresh() { - return ARTIFACT_UPDATE_TYPE_IDS; + return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS); } /** diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java index 1238a36bd1..69946a4b80 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java index 446659ebef..045394d7cc 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java @@ -31,8 +31,9 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; /** - * Wrapper class for converting org.sleuthkit.autopsy.contentutils.RecentFilesSummary functionality into - * a DefaultArtifactUpdateGovernor used by Recent Files Data Summary tab. + * Wrapper class for converting + * org.sleuthkit.autopsy.contentutils.RecentFilesSummary functionality into a + * DefaultArtifactUpdateGovernor used by Recent Files Data Summary tab. */ public class RecentFilesGetter implements DefaultArtifactUpdateGovernor { @@ -52,11 +53,11 @@ public class RecentFilesGetter implements DefaultArtifactUpdateGovernor { * TSK_RECENT_OBJECT artifact. * * @param dataSource The data source to query. - * @param maxCount The maximum number of results to return, pass 0 to get a - * list of all results. + * @param maxCount The maximum number of results to return, pass 0 to get + * a list of all results. * * @return A list RecentFileDetails representing the most recently opened - * documents or an empty list if none were found. + * documents or an empty list if none were found. * * @throws SleuthkitCaseProviderException * @throws TskCoreException @@ -74,11 +75,11 @@ public class RecentFilesGetter implements DefaultArtifactUpdateGovernor { * artifact TSK_DATETIME_ACCESSED attribute. * * @param dataSource Data source to query. - * @param maxCount Maximum number of results to return, passing 0 will - * return all results. + * @param maxCount Maximum number of results to return, passing 0 will + * return all results. * * @return A list of RecentFileDetails objects or empty list if none were - * found. + * found. * * @throws TskCoreException * @throws SleuthkitCaseProviderException @@ -95,8 +96,8 @@ public class RecentFilesGetter implements DefaultArtifactUpdateGovernor { * Returns a list of the most recent message attachments. * * @param dataSource Data source to query. - * @param maxCount Maximum number of results to return, passing 0 will - * return all results. + * @param maxCount Maximum number of results to return, passing 0 will + * return all results. * * @return A list of RecentFileDetails of the most recent attachments. * diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java index 1ab2c83afd..75e826f625 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java @@ -209,84 +209,6 @@ class ContainerPanel extends BaseDataSourceSummaryPanel { ((DefaultTableModel) filePathsTable.getModel()).setRowCount(0); } - /** - * Divides acquisition details into key/value pairs to be displayed in - * separate cells in an excel export. - * - * @param acquisitionDetails The acquisition details. - * @return The list of key value pairs that can be incorporated into the - * excel export. - */ - /* ELTODO - private static List getAcquisitionDetails(String acquisitionDetails) { - if (StringUtils.isBlank(acquisitionDetails)) { - return Collections.emptyList(); - } else { - return Stream.of(acquisitionDetails.split("\\r?\\n")) - .map((line) -> (StringUtils.isBlank(line)) ? null : new SingleCellExportable(line)) - .filter(item -> item != null) - .collect(Collectors.toList()); - } - } - - @Messages({ - "ContainerPanel_export_displayName=Display Name:", - "ContainerPanel_export_originalName=Name:", - "ContainerPanel_export_deviceId=Device ID:", - "ContainerPanel_export_timeZone=Time Zone:", - "ContainerPanel_export_acquisitionDetails=Acquisition Details:", - "ContainerPanel_export_imageType=Image Type:", - "ContainerPanel_export_size=Size:", - "ContainerPanel_export_sectorSize=Sector Size:", - "ContainerPanel_export_md5=MD5:", - "ContainerPanel_export_sha1=SHA1:", - "ContainerPanel_export_sha256=SHA256:", - "ContainerPanel_export_unallocatedSize=Unallocated Space:", - "ContainerPanel_export_filePaths=File Paths:",}) - protected List getExports(DataSource ds) { - ContainerDetails result = getFetchResult(containerDataFetcher, "Container sheets", ds); - if (ds == null || result == null) { - return Collections.emptyList(); - } - - String NA = Bundle.ContainerPanel_setFieldsForNonImageDataSource_na(); - DefaultCellModel NACell = new DefaultCellModel<>(NA); - - ImageDetails imageModel = result.getImageDetails(); - boolean hasImage = imageModel != null; - - DefaultCellModel timeZone = hasImage ? new DefaultCellModel<>(imageModel.getTimeZone()) : NACell; - DefaultCellModel imageType = hasImage ? new DefaultCellModel<>(imageModel.getImageType()) : NACell; - DefaultCellModel size = hasImage ? SizeRepresentationUtil.getBytesCell(imageModel.getSize()) : NACell; - DefaultCellModel sectorSize = hasImage ? SizeRepresentationUtil.getBytesCell(imageModel.getSectorSize()) : NACell; - DefaultCellModel md5 = hasImage ? new DefaultCellModel<>(imageModel.getMd5Hash()) : NACell; - DefaultCellModel sha1 = hasImage ? new DefaultCellModel<>(imageModel.getSha1Hash()) : NACell; - DefaultCellModel sha256 = hasImage ? new DefaultCellModel<>(imageModel.getSha256Hash()) : NACell; - DefaultCellModel unallocatedSize = hasImage ? SizeRepresentationUtil.getBytesCell(imageModel.getUnallocatedSize()) : NACell; - List paths = result.getImageDetails() == null ? Collections.singletonList(NA) : result.getImageDetails().getPaths(); - List cellPaths = paths.stream() - .map(SingleCellExportable::new) - .collect(Collectors.toList()); - - return Arrays.asList( - new ExcelSpecialFormatExport(Bundle.ContainerPanel_tabName(), Arrays.asList( - new KeyValueItemExportable(Bundle.ContainerPanel_export_displayName(), new DefaultCellModel<>(result.getDisplayName())), - new KeyValueItemExportable(Bundle.ContainerPanel_export_originalName(), new DefaultCellModel<>(result.getOriginalName())), - new KeyValueItemExportable(Bundle.ContainerPanel_export_deviceId(), new DefaultCellModel<>(result.getDeviceId())), - new KeyValueItemExportable(Bundle.ContainerPanel_export_timeZone(), timeZone), - new TitledExportable(Bundle.ContainerPanel_export_acquisitionDetails(), getAcquisitionDetails(result.getAcquisitionDetails())), - new KeyValueItemExportable(Bundle.ContainerPanel_export_imageType(), imageType), - new KeyValueItemExportable(Bundle.ContainerPanel_export_size(), size), - new KeyValueItemExportable(Bundle.ContainerPanel_export_sectorSize(), sectorSize), - new KeyValueItemExportable(Bundle.ContainerPanel_export_md5(), md5), - new KeyValueItemExportable(Bundle.ContainerPanel_export_sha1(), sha1), - new KeyValueItemExportable(Bundle.ContainerPanel_export_sha256(), sha256), - new KeyValueItemExportable(Bundle.ContainerPanel_export_unallocatedSize(), unallocatedSize), - new TitledExportable(Bundle.ContainerPanel_export_filePaths(), cellPaths) - ))); - - }*/ - /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index 3b082e5849..e2f38b38b6 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -132,10 +132,11 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { } /** - * Returns a function that gets the date from the RecentFileDetails object and - * converts into a DefaultCellModel to be displayed in a table. + * Returns a function that gets the date from the RecentFileDetails object + * and converts into a DefaultCellModel to be displayed in a table. * - * @return The function that determines the date cell from a RecentFileDetails object. + * @return The function that determines the date cell from a + * RecentFileDetails object. */ private Function> getDateFunct() { return (T lastAccessed) -> { @@ -150,9 +151,10 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { * items. * * @param record The RecentFileDetails instance. + * * @return The menu items list containing one action or navigating to the - * appropriate artifact/file and closing the data source summary dialog if - * open. + * appropriate artifact/file and closing the data source summary + * dialog if open. */ private Supplier> getPopupFunct(RecentFileDetails record) { return () -> { diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SizeRepresentationUtil.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SizeRepresentationUtil.java index 74b9be06a8..3c48da8db0 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SizeRepresentationUtil.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SizeRepresentationUtil.java @@ -19,8 +19,6 @@ package org.sleuthkit.autopsy.datasourcesummary.ui; import java.text.DecimalFormat; -import java.util.Arrays; -import java.util.List; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; @@ -53,7 +51,7 @@ public final class SizeRepresentationUtil { PB(Bundle.SizeRepresentationUtil_units_petabytes(), "#,##0.00,,,,,", 5); private final String suffix; - private final String excelFormatString; + private final String excelFormatString; // ELTODO private final long divisor; /** @@ -126,14 +124,14 @@ public final class SizeRepresentationUtil { } /** - * Get a long size in bytes as a string formated to be read by users. + * Get a long size in bytes as a string formatted to be read by users. * * @param size Long value representing a size in byte.s * @param format The means of formatting the number. * @param showFullSize Optionally show the number of bytes in the * datasource. * - * @return Return a string formated with a user friendly version of the size + * @return Return a string formatted with a user friendly version of the size * as a string, returns empty String when provided empty size. */ static String getSizeString(Long size, DecimalFormat format, boolean showFullSize) { diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index 42143965be..f93c0bc1c3 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -4,10 +4,26 @@ DataSourceSummaryReport.endReport.srcModuleName.text=Excel Report # {0} - sheetNumber ExcelExport_writeExcel_noSheetName=Sheet {0} ExcelExportAction_exportToXLSX_beginExport=Beginning Export... +ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data ExcelExportAction_exportToXLSX_writingToFile=Writing to File... ExcelExportAction_getXLSXPath_directory=DataSourceSummary ExcelExportAction_moduleName=Data Source Summary +ExportContainerInfo_export_acquisitionDetails=Acquisition Details: +ExportContainerInfo_export_deviceId=Device ID: +ExportContainerInfo_export_displayName=Display Name: +ExportContainerInfo_export_filePaths=File Paths: +ExportContainerInfo_export_imageType=Image Type: +ExportContainerInfo_export_md5=MD5: +ExportContainerInfo_export_originalName=Name: +ExportContainerInfo_export_sectorSize=Sector Size: +ExportContainerInfo_export_sha1=SHA1: +ExportContainerInfo_export_sha256=SHA256: +ExportContainerInfo_export_size=Size: +ExportContainerInfo_export_timeZone=Time Zone: +ExportContainerInfo_export_unallocatedSize=Unallocated Space: +ExportContainerInfo_setFieldsForNonImageDataSource_na=N/A +ExportContainerInfo_tabName=Container ExportRecentFiles_attachmentsTable_tabName=Recent Attachments ExportRecentFiles_col_head_date=Date ExportRecentFiles_col_header_domain=Domain @@ -15,3 +31,9 @@ ExportRecentFiles_col_header_path=Path ExportRecentFiles_col_header_sender=Sender ExportRecentFiles_docsTable_tabName=Recently Opened Documents ExportRecentFiles_downloadsTable_tabName=Recently Downloads +SizeRepresentationUtil_units_bytes=bytes +SizeRepresentationUtil_units_gigabytes=GB +SizeRepresentationUtil_units_kilobytes=KB +SizeRepresentationUtil_units_megabytes=MB +SizeRepresentationUtil_units_petabytes=PB +SizeRepresentationUtil_units_terabytes=TB diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index 0f957acb31..e8416453b3 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -91,6 +91,7 @@ class ExcelExportAction { @NbBundle.Messages({ "ExcelExportAction_exportToXLSX_beginExport=Beginning Export...", "ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data", + "ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data", "ExcelExportAction_exportToXLSX_writingToFile=Writing to File...",}) void exportToXLSX(ReportProgressPanel progressPanel, DataSource dataSource, String baseReportDir) @@ -103,17 +104,24 @@ class ExcelExportAction { progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_beginExport()); List sheetExports = new ArrayList<>(); + // Export Recent Activity data progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringRecentActivityData()); progressPanel.setProgress(1); - - // Export Recent Activity data List exports = ExportRecentFiles.getExports(dataSource); if (exports != null) { sheetExports.addAll(exports); } + + // Export Container & Image info data + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringContainerData()); + progressPanel.setProgress(2); + exports = ExportContainerInfo.getExports(dataSource); + if (exports != null) { + sheetExports.addAll(exports); + } progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_writingToFile()); - progressPanel.setProgress(2); + progressPanel.setProgress(3); ExcelExport.writeExcel(sheetExports, reportFile); progressPanel.complete(ReportProgressPanel.ReportStatus.COMPLETE, ""); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java new file mode 100755 index 0000000000..6d297abc0f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java @@ -0,0 +1,126 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.report.modules.datasourcesummaryexport; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.lang.StringUtils; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.contentutils.ContainerSummary; +import org.sleuthkit.autopsy.contentutils.ContainerSummary.ContainerDetails; +import org.sleuthkit.autopsy.contentutils.ContainerSummary.ImageDetails; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelSheetExport; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.ExcelItemExportable; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.KeyValueItemExportable; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.SingleCellExportable; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.TitledExportable; +import org.sleuthkit.datamodel.DataSource; + +/** + * Class to export additional details associated with a specific DataSource + */ +class ExportContainerInfo { + + /** + * Creates new form ExportContainerInfo. + */ + private ExportContainerInfo() { + } + + /** + * Divides acquisition details into key/value pairs to be displayed in + * separate cells in an excel export. + * + * @param acquisitionDetails The acquisition details. + * @return The list of key value pairs that can be incorporated into the + * excel export. + */ + private static List getAcquisitionDetails(String acquisitionDetails) { + if (StringUtils.isBlank(acquisitionDetails)) { + return Collections.emptyList(); + } else { + return Stream.of(acquisitionDetails.split("\\r?\\n")) + .map((line) -> (StringUtils.isBlank(line)) ? null : new SingleCellExportable(line)) + .filter(item -> item != null) + .collect(Collectors.toList()); + } + } + + @Messages({ + "ExportContainerInfo_setFieldsForNonImageDataSource_na=N/A", + "ExportContainerInfo_tabName=Container", + "ExportContainerInfo_export_displayName=Display Name:", + "ExportContainerInfo_export_originalName=Name:", + "ExportContainerInfo_export_deviceId=Device ID:", + "ExportContainerInfo_export_timeZone=Time Zone:", + "ExportContainerInfo_export_acquisitionDetails=Acquisition Details:", + "ExportContainerInfo_export_imageType=Image Type:", + "ExportContainerInfo_export_size=Size:", + "ExportContainerInfo_export_sectorSize=Sector Size:", + "ExportContainerInfo_export_md5=MD5:", + "ExportContainerInfo_export_sha1=SHA1:", + "ExportContainerInfo_export_sha256=SHA256:", + "ExportContainerInfo_export_unallocatedSize=Unallocated Space:", + "ExportContainerInfo_export_filePaths=File Paths:",}) + static List getExports(DataSource ds) { + DataFetcher containerDataFetcher = (dataSource) -> ContainerSummary.getContainerDetails(dataSource); + ContainerDetails containerDetails = ExcelExportAction.getFetchResult(containerDataFetcher, "Container sheets", ds); + if (ds == null || containerDetails == null) { + return Collections.emptyList(); + } + + String NA = Bundle.ExportContainerInfo_setFieldsForNonImageDataSource_na(); + DefaultCellModel NACell = new DefaultCellModel<>(NA); + + ImageDetails imageDetails = containerDetails.getImageDetails(); + boolean hasImage = imageDetails != null; + + DefaultCellModel timeZone = hasImage ? new DefaultCellModel<>(imageDetails.getTimeZone()) : NACell; + DefaultCellModel imageType = hasImage ? new DefaultCellModel<>(imageDetails.getImageType()) : NACell; + DefaultCellModel size = hasImage ? SizeRepresentationUtil.getBytesCell(imageDetails.getSize()) : NACell; + DefaultCellModel sectorSize = hasImage ? SizeRepresentationUtil.getBytesCell(imageDetails.getSectorSize()) : NACell; + DefaultCellModel md5 = hasImage ? new DefaultCellModel<>(imageDetails.getMd5Hash()) : NACell; + DefaultCellModel sha1 = hasImage ? new DefaultCellModel<>(imageDetails.getSha1Hash()) : NACell; + DefaultCellModel sha256 = hasImage ? new DefaultCellModel<>(imageDetails.getSha256Hash()) : NACell; + DefaultCellModel unallocatedSize = hasImage ? SizeRepresentationUtil.getBytesCell(imageDetails.getUnallocatedSize()) : NACell; + List paths = containerDetails.getImageDetails() == null ? Collections.singletonList(NA) : containerDetails.getImageDetails().getPaths(); + List cellPaths = paths.stream() + .map(SingleCellExportable::new) + .collect(Collectors.toList()); + + return Arrays.asList(new ExcelSpecialFormatExport(Bundle.ExportContainerInfo_tabName(), Arrays.asList(new KeyValueItemExportable(Bundle.ExportContainerInfo_export_displayName(), new DefaultCellModel<>(containerDetails.getDisplayName())), + new KeyValueItemExportable(Bundle.ExportContainerInfo_export_originalName(), new DefaultCellModel<>(containerDetails.getOriginalName())), + new KeyValueItemExportable(Bundle.ExportContainerInfo_export_deviceId(), new DefaultCellModel<>(containerDetails.getDeviceId())), + new KeyValueItemExportable(Bundle.ExportContainerInfo_export_timeZone(), timeZone), + new TitledExportable(Bundle.ExportContainerInfo_export_acquisitionDetails(), getAcquisitionDetails(containerDetails.getAcquisitionDetails())), + new KeyValueItemExportable(Bundle.ExportContainerInfo_export_imageType(), imageType), + new KeyValueItemExportable(Bundle.ExportContainerInfo_export_size(), size), + new KeyValueItemExportable(Bundle.ExportContainerInfo_export_sectorSize(), sectorSize), + new KeyValueItemExportable(Bundle.ExportContainerInfo_export_md5(), md5), + new KeyValueItemExportable(Bundle.ExportContainerInfo_export_sha1(), sha1), + new KeyValueItemExportable(Bundle.ExportContainerInfo_export_sha256(), sha256), + new KeyValueItemExportable(Bundle.ExportContainerInfo_export_unallocatedSize(), unallocatedSize), + new TitledExportable(Bundle.ExportContainerInfo_export_filePaths(), cellPaths) + ))); + + } +} diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java index 1864dc5332..c9a57cc3aa 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java @@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentFileDetails; import org.sleuthkit.datamodel.DataSource; /** - * Data Source Summary recent files panel. + * Class to export data source summary info. */ @Messages({ "ExportRecentFiles_docsTable_tabName=Recently Opened Documents", @@ -86,15 +86,15 @@ final class ExportRecentFiles { return new DefaultCellModel<>(prog.getSender()); }, 150)); - private ExportRecentFiles() { } /** - * Returns a function that gets the date from the RecentFileDetails object and - * converts into a DefaultCellModel to be displayed in a table. + * Returns a function that gets the date from the RecentFileDetails object + * and converts into a DefaultCellModel to be displayed in a table. * - * @return The function that determines the date cell from a RecentFileDetails object. + * @return The function that determines the date cell from a + * RecentFileDetails object. */ private static Function> getDateFunct() { return (T lastAccessed) -> { diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/SizeRepresentationUtil.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/SizeRepresentationUtil.java new file mode 100755 index 0000000000..664401c684 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/SizeRepresentationUtil.java @@ -0,0 +1,179 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.report.modules.datasourcesummaryexport; + +import java.text.DecimalFormat; +import org.openide.util.NbBundle; + +/** + * This class provides utilities for representing storage size in most relevant + * units (i.e. bytes, megabytes, etc.). + */ +final class SizeRepresentationUtil { + + private static final int SIZE_CONVERSION_CONSTANT = 1000; + private static final DecimalFormat APPROXIMATE_SIZE_FORMAT = new DecimalFormat("#.##"); + + /** + * A size unit corresponding to orders of magnitude of bytes (kilobyte, gigabytes, etc.). + */ + @NbBundle.Messages({ + "SizeRepresentationUtil_units_bytes=bytes", + "SizeRepresentationUtil_units_kilobytes=KB", + "SizeRepresentationUtil_units_megabytes=MB", + "SizeRepresentationUtil_units_gigabytes=GB", + "SizeRepresentationUtil_units_terabytes=TB", + "SizeRepresentationUtil_units_petabytes=PB" + }) + enum SizeUnit { + BYTES(Bundle.SizeRepresentationUtil_units_bytes(), "#", 0), + KB(Bundle.SizeRepresentationUtil_units_kilobytes(), "#,##0.00,", 1), + MB(Bundle.SizeRepresentationUtil_units_megabytes(), "#,##0.00,,", 2), + GB(Bundle.SizeRepresentationUtil_units_gigabytes(), "#,##0.00,,,", 3), + TB(Bundle.SizeRepresentationUtil_units_terabytes(), "#,##0.00,,,,", 4), + PB(Bundle.SizeRepresentationUtil_units_petabytes(), "#,##0.00,,,,,", 5); + + private final String suffix; + private final String excelFormatString; + private final long divisor; + + /** + * Main constructor. + * @param suffix The string suffix to use for size unit. + * @param excelFormatString The excel format string to use for this size unit. + * @param power The power of 1000 of bytes for this size unit. + */ + SizeUnit(String suffix, String excelFormatString, int power) { + this.suffix = suffix; + + // based on https://www.mrexcel.com/board/threads/how-do-i-format-cells-to-show-gb-mb-kb.140135/ + this.excelFormatString = String.format("%s \"%s\"", excelFormatString, suffix); + this.divisor = (long) Math.pow(SIZE_CONVERSION_CONSTANT, power); + } + + /** + * @return The string suffix to use for size unit. + */ + String getSuffix() { + return suffix; + } + + /** + * @return The excel format string to use for this size unit. + */ + String getExcelFormatString() { + return excelFormatString; + } + + /** + * @return The divisor to convert from bytes to this unit. + */ + long getDivisor() { + return divisor; + } + } + + /** + * Get a long size in bytes as a string formated to be read by users. + * + * @param size Long value representing a size in bytes. + * + * @return Return a string formated with a user friendly version of the size + * as a string, returns empty String when provided empty size. + */ + static String getSizeString(Long size) { + return getSizeString(size, APPROXIMATE_SIZE_FORMAT, true); + } + + /** + * Determines the relevant size unit that should be used for a particular size. + * @param size The size in bytes. + * @return The relevant size unit. + */ + static SizeUnit getSizeUnit(Long size) { + if (size == null) { + return SizeUnit.values()[0]; + } + + for (int unitsIndex = 0; unitsIndex < SizeUnit.values().length; unitsIndex++) { + SizeUnit unit = SizeUnit.values()[unitsIndex]; + long result = size / unit.getDivisor(); + if (result < SIZE_CONVERSION_CONSTANT) { + return unit; + } + } + + return SizeUnit.values()[SizeUnit.values().length - 1]; + } + + /** + * Get a long size in bytes as a string formatted to be read by users. + * + * @param size Long value representing a size in byte.s + * @param format The means of formatting the number. + * @param showFullSize Optionally show the number of bytes in the + * datasource. + * + * @return Return a string formatted with a user friendly version of the size + * as a string, returns empty String when provided empty size. + */ + static String getSizeString(Long size, DecimalFormat format, boolean showFullSize) { + if (size == null) { + return ""; + } + + SizeUnit sizeUnit = getSizeUnit(size); + if (sizeUnit == null) { + sizeUnit = SizeUnit.BYTES; + } + + String closestUnitSize = String.format("%s %s", + format.format(((double) size) / sizeUnit.getDivisor()), sizeUnit.getSuffix()); + + String fullSize = String.format("%d %s", size, SizeUnit.BYTES.getSuffix()); + if (sizeUnit.equals(SizeUnit.BYTES)) { + return fullSize; + } else if (showFullSize) { + return String.format("%s (%s)", closestUnitSize, fullSize); + } else { + return closestUnitSize; + } + } + + /** + * Returns a default cell model using size units. + * @param bytes The number of bytes. + * @return The default cell model. + */ + static DefaultCellModel getBytesCell(Long bytes) { + if (bytes == null) { + return new DefaultCellModel<>(""); + } else { + SizeUnit unit = SizeRepresentationUtil.getSizeUnit(bytes); + if (unit == null) { + unit = SizeUnit.BYTES; + } + + return new DefaultCellModel(bytes, SizeRepresentationUtil::getSizeString, unit.getExcelFormatString()); + } + } + + private SizeRepresentationUtil() { + } +} From 0aa708388c3505ada0e55f7deb31b86925d9c92e Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Fri, 6 Aug 2021 14:45:06 -0400 Subject: [PATCH 16/76] Moved timeline getters and export functionality out of datasourcesummary --- .../contentutils/ContainerSummary.java | 11 +- .../contentutils/RecentFilesSummary.java | 12 - .../TimelineSummary.java | 213 ++++++++++-------- .../datamodel/ContainerSummaryGetter.java | 28 ++- .../datamodel/RecentFilesGetter.java | 14 +- .../datamodel/TimelineDataSourceUtils.java | 95 -------- .../datamodel/TimelineSummaryGetter.java | 89 ++++++++ .../datasourcesummary/ui/TimelinePanel.java | 108 ++------- .../BarChartSeries.java | 99 +++++++- .../Bundle.properties-MERGED | 12 + .../ExcelExportAction.java | 11 +- .../ExportTimeline.java | 139 ++++++++++++ 12 files changed, 507 insertions(+), 324 deletions(-) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/datamodel => contentutils}/TimelineSummary.java (63%) mode change 100644 => 100755 delete mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummaryGetter.java create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java index 87a78093ca..13f7eec7bf 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java @@ -38,18 +38,9 @@ import org.sleuthkit.datamodel.TskData; */ public class ContainerSummary { - private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( - BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_INFO.getTypeID(), - BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID() - )); - private ContainerSummary() { } - - public static Set getArtifactTypeIdsForRefresh() { - return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS); - } - + /** * Gets the size of unallocated files in a particular datasource. * diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java index 502e2c76a1..f298602351 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java @@ -58,24 +58,12 @@ public class RecentFilesSummary { private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.getDefault()); - private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( - ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID(), - ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID(), - ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT.getTypeID(), - ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(), - ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() - )); - /** * Default constructor. */ private RecentFilesSummary() { } - public static Set getArtifactTypeIdsForRefresh() { - return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS); - } - /** * Removes fileDetails entries with redundant paths, sorts by date * descending and limits to the limit provided. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/TimelineSummary.java old mode 100644 new mode 100755 similarity index 63% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java rename to Core/src/org/sleuthkit/autopsy/contentutils/TimelineSummary.java index a43d46764b..345cda6332 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/TimelineSummary.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,8 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.contentutils; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; @@ -26,51 +28,34 @@ import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TimeZone; import org.joda.time.Interval; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; -import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.autopsy.ingest.ModuleContentEvent; -import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TimelineEvent; import org.sleuthkit.datamodel.TimelineEventType; import org.sleuthkit.datamodel.TimelineFilter.RootFilter; import org.sleuthkit.datamodel.TimelineManager; import org.sleuthkit.datamodel.TskCoreException; -import java.util.function.Supplier; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.timeline.TimeLineController; +import org.sleuthkit.autopsy.timeline.TimeLineModule; +import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.FilterState; +import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState; +import org.sleuthkit.datamodel.TimelineFilter; /** * Provides data source summary information pertaining to Timeline data. */ -public class TimelineSummary implements DefaultUpdateGovernor { +public class TimelineSummary { - /** - * A function for obtaining a Timeline RootFilter filtered to the specific - * data source. - */ - public interface DataSourceFilterFunction { - - /** - * Obtains a Timeline RootFilter filtered to the specific data source. - * - * @param dataSource The data source. - * @return The timeline root filter. - * @throws NoCurrentCaseException - * @throws TskCoreException - */ - RootFilter apply(DataSource dataSource) throws NoCurrentCaseException, TskCoreException; - } + private static final TimeZone timeZone = TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()); private static final long DAY_SECS = 24 * 60 * 60; - private static final Set INGEST_JOB_EVENTS = new HashSet<>( - Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED)); - private static final Set FILE_SYSTEM_EVENTS = new HashSet<>(Arrays.asList( TimelineEventType.FILE_MODIFIED, @@ -78,68 +63,24 @@ public class TimelineSummary implements DefaultUpdateGovernor { TimelineEventType.FILE_CREATED, TimelineEventType.FILE_CHANGED)); - private final SleuthkitCaseProvider caseProvider; - private final Supplier timeZoneProvider; - private final DataSourceFilterFunction filterFunction; - - /** - * Default constructor. - */ - public TimelineSummary() { - this(SleuthkitCaseProvider.DEFAULT, - () -> TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()), - (ds) -> TimelineDataSourceUtils.getInstance().getDataSourceFilter(ds)); - } - - /** - * Construct object with given SleuthkitCaseProvider - * - * @param caseProvider SleuthkitCaseProvider provider; cannot be null. - * @param timeZoneProvider The timezone provider; cannot be null. - * @param filterFunction Provides the default root filter function filtered - * to the data source; cannot be null. - */ - public TimelineSummary(SleuthkitCaseProvider caseProvider, Supplier timeZoneProvider, DataSourceFilterFunction filterFunction) { - this.caseProvider = caseProvider; - this.timeZoneProvider = timeZoneProvider; - this.filterFunction = filterFunction; - } - - @Override - public boolean isRefreshRequired(ModuleContentEvent evt) { - return true; - } - - @Override - public boolean isRefreshRequired(AbstractFile file) { - return true; - } - - @Override - public boolean isRefreshRequired(IngestManager.IngestJobEvent evt) { - return (evt != null && INGEST_JOB_EVENTS.contains(evt)); - } - - @Override - public Set getIngestJobEventUpdates() { - return INGEST_JOB_EVENTS; + private TimelineSummary() { } /** * Retrieves timeline summary data. * - * @param dataSource The data source for which timeline data will be - * retrieved. + * @param dataSource The data source for which timeline data will be + * retrieved. * @param recentDaysNum The maximum number of most recent days' activity to - * include. + * include. + * * @return The retrieved data. - * @throws SleuthkitCaseProviderException + * * @throws TskCoreException * @throws NoCurrentCaseException */ - public TimelineSummaryData getData(DataSource dataSource, int recentDaysNum) throws SleuthkitCaseProviderException, TskCoreException, NoCurrentCaseException { - TimeZone timeZone = this.timeZoneProvider.get(); - TimelineManager timelineManager = this.caseProvider.get().getTimelineManager(); + public static TimelineSummaryData getTimelineSummaryData(DataSource dataSource, int recentDaysNum) throws TskCoreException, NoCurrentCaseException { + TimelineManager timelineManager = Case.getCurrentCaseThrows().getSleuthkitCase().getTimelineManager(); // get a mapping of days from epoch to the activity for that day Map dateCounts = getTimelineEventsByDay(dataSource, timelineManager, timeZone); @@ -174,13 +115,14 @@ public class TimelineSummary implements DefaultUpdateGovernor { * Given activity by day, converts to most recent days' activity handling * empty values. * - * @param dateCounts The day from epoch mapped to activity amounts for that - * day. + * @param dateCounts The day from epoch mapped to activity amounts for + * that day. * @param minRecentDay The minimum recent day in days from epoch. - * @param maxDay The maximum recent day in days from epoch; + * @param maxDay The maximum recent day in days from epoch; + * * @return The most recent daily activity amounts. */ - private List getMostRecentActivityAmounts(Map dateCounts, long minRecentDay, long maxDay) { + private static List getMostRecentActivityAmounts(Map dateCounts, long minRecentDay, long maxDay) { List mostRecentActivityAmt = new ArrayList<>(); for (long curRecentDay = minRecentDay; curRecentDay <= maxDay; curRecentDay++) { @@ -197,18 +139,20 @@ public class TimelineSummary implements DefaultUpdateGovernor { /** * Fetches timeline events per day for a particular data source. * - * @param dataSource The data source. + * @param dataSource The data source. * @param timelineManager The timeline manager to use while fetching the - * data. - * @param timeZone The time zone to use to determine which day activity - * belongs. + * data. + * @param timeZone The time zone to use to determine which day + * activity belongs. + * * @return A Map mapping days from epoch to the activity for that day. + * * @throws TskCoreException * @throws NoCurrentCaseException */ - private Map getTimelineEventsByDay(DataSource dataSource, TimelineManager timelineManager, TimeZone timeZone) + private static Map getTimelineEventsByDay(DataSource dataSource, TimelineManager timelineManager, TimeZone timeZone) throws TskCoreException, NoCurrentCaseException { - RootFilter rootFilter = this.filterFunction.apply(dataSource); + RootFilter rootFilter = getDataSourceFilter(dataSource); // get events for data source long curRunTime = System.currentTimeMillis(); @@ -251,12 +195,14 @@ public class TimelineSummary implements DefaultUpdateGovernor { /** * Main constructor. * - * @param minDate Earliest usage date recorded for the data source. - * @param maxDate Latest usage date recorded for the data source. + * @param minDate Earliest usage date recorded for the data + * source. + * @param maxDate Latest usage date recorded for the data + * source. * @param recentDaysActivity A list of activity prior to and including - * max date sorted by min to max date. - * @param dataSource The data source for which this data applies. the - * latest usage date by day. + * max date sorted by min to max date. + * @param dataSource The data source for which this data + * applies. the latest usage date by day. */ TimelineSummaryData(Date minDate, Date maxDate, List recentDaysActivity, DataSource dataSource) { this.minDate = minDate; @@ -281,7 +227,7 @@ public class TimelineSummary implements DefaultUpdateGovernor { /** * @return A list of activity prior to and including the latest usage - * date by day sorted min to max date. + * date by day sorted min to max date. */ public List getMostRecentDaysActivity() { return histogramActivity; @@ -307,8 +253,10 @@ public class TimelineSummary implements DefaultUpdateGovernor { /** * Main constructor. * - * @param day The day for which activity is being measured. - * @param fileActivityCount The amount of file activity timeline events. + * @param day The day for which activity is being + * measured. + * @param fileActivityCount The amount of file activity timeline + * events. * @param artifactActivityCount The amount of artifact timeline events. */ DailyActivityAmount(Date day, long fileActivityCount, long artifactActivityCount) { @@ -337,6 +285,73 @@ public class TimelineSummary implements DefaultUpdateGovernor { public long getArtifactActivityCount() { return artifactActivityCount; } - } + + /** + * Retrieves a RootFilter based on the default filter state but only the + * specified dataSource is selected. + * + * @param dataSource The data source. + * + * @return The root filter representing a default filter with only this data + * source selected. + * + * @throws NoCurrentCaseException + * @throws TskCoreException + */ + public static RootFilter getDataSourceFilter(DataSource dataSource) throws NoCurrentCaseException, TskCoreException { + RootFilterState filterState = getDataSourceFilterState(dataSource); + return filterState == null ? null : filterState.getActiveFilter(); + } + + /** + * Retrieves a TimeLineController based on the default filter state but only + * the specified dataSource is selected. + * + * @param dataSource The data source. + * + * @return The root filter state representing a default filter with only + * this data source selected. + * + * @throws NoCurrentCaseException + * @throws TskCoreException + */ + public static RootFilterState getDataSourceFilterState(DataSource dataSource) throws NoCurrentCaseException, TskCoreException { + TimeLineController controller = TimeLineModule.getController(); + RootFilterState dataSourceState = controller.getEventsModel().getDefaultEventFilterState().copyOf(); + + for (FilterState filterState : dataSourceState.getDataSourcesFilterState().getSubFilterStates()) { + TimelineFilter.DataSourceFilter dsFilter = filterState.getFilter(); + if (dsFilter != null) { + filterState.setSelected(dsFilter.getDataSourceID() == dataSource.getId()); + } + + } + + return dataSourceState; + } + + /** + * Creates a DateFormat formatter that uses UTC for time zone. + * + * @param formatString The date format string. + * @return The data format. + */ + public static DateFormat getUtcFormat(String formatString) { + return new SimpleDateFormat(formatString, Locale.getDefault()); + } + + /** + * Formats a date using a DateFormat. In the event that the date is null, + * returns a null string. + * + * @param date The date to format. + * @param formatter The DateFormat to use to format the date. + * + * @return The formatted string generated from the formatter or null if the + * date is null. + */ + public static String formatDate(Date date, DateFormat formatter) { + return date == null ? null : formatter.format(date); + } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java index 69946a4b80..9cf43f408e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java @@ -20,21 +20,31 @@ package org.sleuthkit.autopsy.datasourcesummary.datamodel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; import java.util.Set; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.contentutils.ContainerSummary; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; /** - * Wrapper class for converting org.sleuthkit.autopsy.contentutils.ContainerSummary functionality into - * a DefaultArtifactUpdateGovernor used by Container tab. + * Wrapper class for converting + * org.sleuthkit.autopsy.contentutils.ContainerSummary functionality into a + * DefaultArtifactUpdateGovernor used by Container tab. */ public class ContainerSummaryGetter implements DefaultArtifactUpdateGovernor { + private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( + BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_INFO.getTypeID(), + BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID() + )); + /** * Main constructor. */ @@ -53,7 +63,7 @@ public class ContainerSummaryGetter implements DefaultArtifactUpdateGovernor { @Override public Set getArtifactTypeIdsForRefresh() { - return ContainerSummary.getArtifactTypeIdsForRefresh(); + return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS); } /** @@ -73,7 +83,7 @@ public class ContainerSummaryGetter implements DefaultArtifactUpdateGovernor { return ContainerSummary.getSizeOfUnallocatedFiles(currentDataSource); } catch (NoCurrentCaseException ex) { throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + } } /** @@ -95,7 +105,7 @@ public class ContainerSummaryGetter implements DefaultArtifactUpdateGovernor { return ContainerSummary.getOperatingSystems(dataSource); } catch (NoCurrentCaseException ex) { throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + } } /** @@ -117,12 +127,12 @@ public class ContainerSummaryGetter implements DefaultArtifactUpdateGovernor { return ContainerSummary.getDataSourceType(dataSource); } catch (NoCurrentCaseException ex) { throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + } } - + /** - * Retrieves a container data model object containing data about - * the data source. + * Retrieves a container data model object containing data about the data + * source. * * @param dataSource The data source. * diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java index 045394d7cc..668c0085df 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java @@ -18,6 +18,9 @@ */ package org.sleuthkit.autopsy.datasourcesummary.datamodel; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; import java.util.List; import java.util.Set; @@ -29,6 +32,7 @@ import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentFileDetails; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.datamodel.BlackboardArtifact; /** * Wrapper class for converting @@ -37,6 +41,14 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.S */ public class RecentFilesGetter implements DefaultArtifactUpdateGovernor { + private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( + BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID(), + BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID(), + BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT.getTypeID(), + BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(), + BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() + )); + /** * Default constructor. */ @@ -45,7 +57,7 @@ public class RecentFilesGetter implements DefaultArtifactUpdateGovernor { @Override public Set getArtifactTypeIdsForRefresh() { - return RecentFilesSummary.getArtifactTypeIdsForRefresh(); + return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS); } /** diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java deleted file mode 100644 index 40f76cce80..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2020 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.datasourcesummary.datamodel; - -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.timeline.TimeLineController; -import org.sleuthkit.autopsy.timeline.TimeLineModule; -import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.FilterState; -import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState; -import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.TimelineFilter; -import org.sleuthkit.datamodel.TimelineFilter.DataSourceFilter; -import org.sleuthkit.datamodel.TimelineFilter.RootFilter; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Utilities for interacting with Timeline in relation to data sources. - */ -public class TimelineDataSourceUtils { - - private static TimelineDataSourceUtils instance = null; - - /** - * @return Singleton instance of this class. - */ - public static TimelineDataSourceUtils getInstance() { - if (instance == null) { - instance = new TimelineDataSourceUtils(); - } - - return instance; - } - - /** - * Main constructor. Should be instantiated through getInstance(). - */ - private TimelineDataSourceUtils() { - } - - /** - * Retrieves a RootFilter based on the default filter state but only the - * specified dataSource is selected. - * - * @param dataSource The data source. - * @return The root filter representing a default filter with only this data - * source selected. - * @throws NoCurrentCaseException - * @throws TskCoreException - */ - public RootFilter getDataSourceFilter(DataSource dataSource) throws NoCurrentCaseException, TskCoreException { - RootFilterState filterState = getDataSourceFilterState(dataSource); - return filterState == null ? null : filterState.getActiveFilter(); - } - - /** - * Retrieves a TimeLineController based on the default filter state but only - * the specified dataSource is selected. - * - * @param dataSource The data source. - * @return The root filter state representing a default filter with only - * this data source selected. - * @throws NoCurrentCaseException - * @throws TskCoreException - */ - public RootFilterState getDataSourceFilterState(DataSource dataSource) throws NoCurrentCaseException, TskCoreException { - TimeLineController controller = TimeLineModule.getController(); - RootFilterState dataSourceState = controller.getEventsModel().getDefaultEventFilterState().copyOf(); - - for (FilterState filterState : dataSourceState.getDataSourcesFilterState().getSubFilterStates()) { - DataSourceFilter dsFilter = filterState.getFilter(); - if (dsFilter != null) { - filterState.setSelected(dsFilter.getDataSourceID() == dataSource.getId()); - } - - } - - return dataSourceState; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummaryGetter.java new file mode 100644 index 0000000000..3331cd45ed --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummaryGetter.java @@ -0,0 +1,89 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 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.datasourcesummary.datamodel; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; +import org.sleuthkit.autopsy.contentutils.TimelineSummary; +import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.ModuleContentEvent; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.contentutils.TimelineSummary.TimelineSummaryData; + +/** + * Provides data source summary information pertaining to Timeline data. + */ +public class TimelineSummaryGetter implements DefaultUpdateGovernor { + + private static final Set INGEST_JOB_EVENTS = new HashSet<>( + Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED)); + + /** + * Default constructor. + */ + public TimelineSummaryGetter() { + } + + @Override + public boolean isRefreshRequired(ModuleContentEvent evt) { + return true; + } + + @Override + public boolean isRefreshRequired(AbstractFile file) { + return true; + } + + @Override + public boolean isRefreshRequired(IngestManager.IngestJobEvent evt) { + return (evt != null && INGEST_JOB_EVENTS.contains(evt)); + } + + @Override + public Set getIngestJobEventUpdates() { + return Collections.unmodifiableSet(INGEST_JOB_EVENTS); + } + + /** + * Retrieves timeline summary data. + * + * @param dataSource The data source for which timeline data will be + * retrieved. + * @param recentDaysNum The maximum number of most recent days' activity to + * include. + * @return The retrieved data. + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + * @throws NoCurrentCaseException + */ + public TimelineSummaryData getData(DataSource dataSource, int recentDaysNum) throws SleuthkitCaseProviderException, TskCoreException, NoCurrentCaseException { + try { + return TimelineSummary.getTimelineSummaryData(dataSource, recentDaysNum); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java index 318da42943..dab41e9cc8 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,13 +20,10 @@ package org.sleuthkit.autopsy.datasourcesummary.ui; import java.awt.Color; import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Date; import java.util.List; -import java.util.Locale; import java.util.logging.Level; import org.apache.commons.collections.CollectionUtils; import org.joda.time.DateTime; @@ -35,10 +32,10 @@ import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineDataSourceUtils; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData; +import org.sleuthkit.autopsy.contentutils.TimelineSummary; +import org.sleuthkit.autopsy.contentutils.TimelineSummary.DailyActivityAmount; +import org.sleuthkit.autopsy.contentutils.TimelineSummary.TimelineSummaryData; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummaryGetter; import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries; import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.OrderedKey; @@ -47,7 +44,6 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel; @@ -73,26 +69,15 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { private static final long serialVersionUID = 1L; private static final String EARLIEST_LATEST_FORMAT_STR = "MMM d, yyyy"; - private static final DateFormat EARLIEST_LATEST_FORMAT = getUtcFormat(EARLIEST_LATEST_FORMAT_STR); - private static final DateFormat CHART_FORMAT = getUtcFormat("MMM d, yyyy"); + private static final DateFormat EARLIEST_LATEST_FORMAT = TimelineSummary.getUtcFormat(EARLIEST_LATEST_FORMAT_STR); + private static final DateFormat CHART_FORMAT = TimelineSummary.getUtcFormat("MMM d, yyyy"); private static final int MOST_RECENT_DAYS_COUNT = 30; - /** - * Creates a DateFormat formatter that uses UTC for time zone. - * - * @param formatString The date format string. - * @return The data format. - */ - private static DateFormat getUtcFormat(String formatString) { - return new SimpleDateFormat(formatString, Locale.getDefault()); - } - // components displayed in the tab private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel(); private final LoadableLabel earliestLabel = new LoadableLabel(Bundle.TimelinePanel_earliestLabel_title()); private final LoadableLabel latestLabel = new LoadableLabel(Bundle.TimelinePanel_latestLabel_title()); private final BarChartPanel last30DaysChart = new BarChartPanel(Bundle.TimlinePanel_last30DaysChart_title(), "", ""); - private final TimelineDataSourceUtils timelineUtils = TimelineDataSourceUtils.getInstance(); // all loadable components on this tab private final List> loadableComponents = Arrays.asList(earliestLabel, latestLabel, last30DaysChart); @@ -103,16 +88,16 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { private final List> dataFetchComponents; public TimelinePanel() { - this(new TimelineSummary()); + this(new TimelineSummaryGetter()); } /** * Creates new form PastCasesPanel */ - public TimelinePanel(TimelineSummary timelineData) { + public TimelinePanel(TimelineSummaryGetter timelineData) { super(timelineData); - dataFetcher = (dataSource) -> timelineData.getData(dataSource, MOST_RECENT_DAYS_COUNT); + dataFetcher = (dataSource) -> TimelineSummary.getTimelineSummaryData(dataSource, MOST_RECENT_DAYS_COUNT); // set up data acquisition methods dataFetchComponents = Arrays.asList( @@ -121,29 +106,18 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { initComponents(); } - /** - * Formats a date using a DateFormat. In the event that the date is null, - * returns a null string. - * - * @param date The date to format. - * @param formatter The DateFormat to use to format the date. - * @return The formatted string generated from the formatter or null if the - * date is null. - */ - private static String formatDate(Date date, DateFormat formatter) { - return date == null ? null : formatter.format(date); - } - private static final Color FILE_EVT_COLOR = new Color(228, 22, 28); private static final Color ARTIFACT_EVT_COLOR = new Color(21, 227, 100); /** - * Converts DailyActivityAmount data retrieved from TimelineSummary into - * data to be displayed as a bar chart. + * Converts DailyActivityAmount data retrieved from TimelineSummaryGetter + * into data to be displayed as a bar chart. * - * @param recentDaysActivity The data retrieved from TimelineSummary. + * @param recentDaysActivity The data retrieved from + * TimelineSummaryGetter. * @param showIntermediateDates If true, shows all dates. If false, shows - * only first and last date. + * only first and last date. + * * @return The data to be displayed in the BarChart. */ private List parseChartData(List recentDaysActivity, boolean showIntermediateDates) { @@ -162,7 +136,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { long fileAmt = curItem.getFileActivityCount(); long artifactAmt = curItem.getArtifactActivityCount() * 100; String formattedDate = (showIntermediateDates || i == 0 || i == recentDaysActivity.size() - 1) - ? formatDate(curItem.getDay(), CHART_FORMAT) : ""; + ? TimelineSummary.formatDate(curItem.getDay(), CHART_FORMAT) : ""; OrderedKey thisKey = new OrderedKey(formattedDate, i); fileEvtCounts.add(new BarChartItem(thisKey, fileAmt)); @@ -186,8 +160,8 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { * @param result The result to be displayed on this tab. */ private void handleResult(DataFetchResult result) { - earliestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> formatDate(r.getMinDate(), EARLIEST_LATEST_FORMAT))); - latestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> formatDate(r.getMaxDate(), EARLIEST_LATEST_FORMAT))); + earliestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> TimelineSummary.formatDate(r.getMinDate(), EARLIEST_LATEST_FORMAT))); + latestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> TimelineSummary.formatDate(r.getMaxDate(), EARLIEST_LATEST_FORMAT))); last30DaysChart.showDataFetchResult(DataFetchResult.getSubResult(result, r -> parseChartData(r.getMostRecentDaysActivity(), false))); if (result != null @@ -237,8 +211,8 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { * Action that occurs when 'View in Timeline' button is pressed. * * @param dataSource The data source to filter to. - * @param minDate The min date for the zoom of the window. - * @param maxDate The max date for the zoom of the window. + * @param minDate The min date for the zoom of the window. + * @param maxDate The max date for the zoom of the window. */ private void openFilteredChart(DataSource dataSource, Date minDate, Date maxDate) { OpenTimelineAction openTimelineAction = CallableSystemAction.get(OpenTimelineAction.class); @@ -255,7 +229,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { final TimeLineController controller = TimeLineModule.getController(); if (dataSource != null) { - controller.pushFilters(timelineUtils.getDataSourceFilterState(dataSource)); + controller.pushFilters(TimelineSummary.getDataSourceFilterState(dataSource)); } if (minDate != null && maxDate != null) { @@ -288,44 +262,6 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { super.close(); } - /** - * Create a default cell model to be use with excel export in the earliest / - * latest date format. - * - * @param date The date. - * @return The cell model. - */ - private static DefaultCellModel getEarliestLatestCell(Date date) { - return new DefaultCellModel<>(date, (dt) -> dt == null ? "" : EARLIEST_LATEST_FORMAT.format(dt), EARLIEST_LATEST_FORMAT_STR); - } - - /* ELTODO - @Messages({ - "TimelinePanel_getExports_sheetName=Timeline", - "TimelinePanel_getExports_activityRange=Activity Range", - "TimelinePanel_getExports_earliest=Earliest:", - "TimelinePanel_getExports_latest=Latest:", - "TimelinePanel_getExports_dateColumnHeader=Date", - "TimelinePanel_getExports_chartName=Last 30 Days",}) - @Override - List getExports(DataSource dataSource) { - TimelineSummaryData summaryData = getFetchResult(dataFetcher, "Timeline", dataSource); - if (summaryData == null) { - return Collections.emptyList(); - } - - return Arrays.asList( - new ExcelSpecialFormatExport(Bundle.TimelinePanel_getExports_sheetName(), - Arrays.asList( - new TitledExportable(Bundle.TimelinePanel_getExports_activityRange(), Collections.emptyList()), - new KeyValueItemExportable(Bundle.TimelinePanel_getExports_earliest(), getEarliestLatestCell(summaryData.getMinDate())), - new KeyValueItemExportable(Bundle.TimelinePanel_getExports_latest(), getEarliestLatestCell(summaryData.getMaxDate())), - new BarChartExport(Bundle.TimelinePanel_getExports_dateColumnHeader(), - "#,###", - Bundle.TimelinePanel_getExports_chartName(), - parseChartData(summaryData.getMostRecentDaysActivity(), true))))); - }*/ - /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartSeries.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartSeries.java index f7c48a2f30..99a5d1b557 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartSeries.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartSeries.java @@ -25,12 +25,12 @@ import java.util.List; /** * Represents a series in a bar chart where all items pertain to one category. */ -public class BarChartSeries { +class BarChartSeries { /** * An individual bar to be displayed in the bar chart. */ - public static class BarChartItem { + static class BarChartItem { private final Comparable key; private final double value; @@ -38,10 +38,10 @@ public class BarChartSeries { /** * Main constructor. * - * @param key The key. + * @param key The key. * @param value The value for this item. */ - public BarChartItem(Comparable key, double value) { + BarChartItem(Comparable key, double value) { this.key = key; this.value = value; } @@ -49,14 +49,14 @@ public class BarChartSeries { /** * @return The key for this item. */ - public Comparable getKey() { + Comparable getKey() { return key; } /** * @return The value for this item. */ - public double getValue() { + double getValue() { return value; } } @@ -67,11 +67,11 @@ public class BarChartSeries { /** * Main constructor. * - * @param key The key. + * @param key The key. * @param color The color for this series. * @param items The bars to be displayed for this series. */ - public BarChartSeries(Comparable key, Color color, List items) { + BarChartSeries(Comparable key, Color color, List items) { this.key = key; this.color = color; this.items = (items == null) ? Collections.emptyList() : Collections.unmodifiableList(items); @@ -80,22 +80,99 @@ public class BarChartSeries { /** * @return The color for this series. */ - public Color getColor() { + Color getColor() { return color; } /** * @return The bars to be displayed for this series. */ - public List getItems() { + List getItems() { return items; } /** * @return The key for this item. */ - public Comparable getKey() { + Comparable getKey() { return key; } + /** + * JFreeChart bar charts don't preserve the order of bars provided to the + * chart, but instead uses the comparable nature to order items. This + * provides order using a provided index as well as the value for the axis. + */ + static class OrderedKey implements Comparable { + + private final Object keyValue; + private final int keyIndex; + + /** + * Main constructor. + * + * @param keyValue The value for the key to be displayed in the domain + * axis. + * @param keyIndex The index at which it will be displayed. + */ + OrderedKey(Object keyValue, int keyIndex) { + this.keyValue = keyValue; + this.keyIndex = keyIndex; + } + + /** + * @return The value for the key to be displayed in the domain axis. + */ + Object getKeyValue() { + return keyValue; + } + + /** + * @return The index at which it will be displayed. + */ + int getKeyIndex() { + return keyIndex; + } + + @Override + public int compareTo(OrderedKey o) { + // this will have a higher value than null. + if (o == null) { + return 1; + } + + // compare by index + return Integer.compare(this.getKeyIndex(), o.getKeyIndex()); + } + + @Override + public int hashCode() { + int hash = 3; + 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 OrderedKey other = (OrderedKey) obj; + if (this.keyIndex != other.keyIndex) { + return false; + } + return true; + } + + @Override + public String toString() { + // use toString on the key. + return this.getKeyValue() == null ? null : this.getKeyValue().toString(); + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index f93c0bc1c3..07d26f8e14 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -6,6 +6,7 @@ ExcelExport_writeExcel_noSheetName=Sheet {0} ExcelExportAction_exportToXLSX_beginExport=Beginning Export... ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data +ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data ExcelExportAction_exportToXLSX_writingToFile=Writing to File... ExcelExportAction_getXLSXPath_directory=DataSourceSummary ExcelExportAction_moduleName=Data Source Summary @@ -37,3 +38,14 @@ SizeRepresentationUtil_units_kilobytes=KB SizeRepresentationUtil_units_megabytes=MB SizeRepresentationUtil_units_petabytes=PB SizeRepresentationUtil_units_terabytes=TB +TimelinePanel_earliestLabel_title=Earliest +TimelinePanel_getExports_activityRange=Activity Range +TimelinePanel_getExports_chartName=Last 30 Days +TimelinePanel_getExports_dateColumnHeader=Date +TimelinePanel_getExports_earliest=Earliest: +TimelinePanel_getExports_latest=Latest: +TimelinePanel_getExports_sheetName=Timeline +TimelinePanel_latestLabel_title=Latest +TimlinePanel_last30DaysChart_artifactEvts_title=Result Events +TimlinePanel_last30DaysChart_fileEvts_title=File Events +TimlinePanel_last30DaysChart_title=Last 30 Days diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index e8416453b3..8492b4aca6 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -92,6 +92,7 @@ class ExcelExportAction { "ExcelExportAction_exportToXLSX_beginExport=Beginning Export...", "ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data", "ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data", + "ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data", "ExcelExportAction_exportToXLSX_writingToFile=Writing to File...",}) void exportToXLSX(ReportProgressPanel progressPanel, DataSource dataSource, String baseReportDir) @@ -120,8 +121,16 @@ class ExcelExportAction { sheetExports.addAll(exports); } - progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_writingToFile()); + // Export Timeline data + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringTimelineData()); progressPanel.setProgress(3); + exports = ExportTimeline.getExports(dataSource); + if (exports != null) { + sheetExports.addAll(exports); + } + + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_writingToFile()); + progressPanel.setProgress(9); ExcelExport.writeExcel(sheetExports, reportFile); progressPanel.complete(ReportProgressPanel.ReportStatus.COMPLETE, ""); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java new file mode 100755 index 0000000000..e845093f08 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java @@ -0,0 +1,139 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.report.modules.datasourcesummaryexport; + +import java.awt.Color; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import org.apache.commons.collections.CollectionUtils; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.contentutils.TimelineSummary; +import org.sleuthkit.autopsy.contentutils.TimelineSummary.DailyActivityAmount; +import org.sleuthkit.autopsy.contentutils.TimelineSummary.TimelineSummaryData; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.BarChartSeries.BarChartItem; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.BarChartSeries.OrderedKey; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.KeyValueItemExportable; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.TitledExportable; +import org.sleuthkit.datamodel.DataSource; + +/** + * Class to export information about a data source's timeline events. + */ +@Messages({ + "TimelinePanel_earliestLabel_title=Earliest", + "TimelinePanel_latestLabel_title=Latest", + "TimlinePanel_last30DaysChart_title=Last 30 Days", + "TimlinePanel_last30DaysChart_fileEvts_title=File Events", + "TimlinePanel_last30DaysChart_artifactEvts_title=Result Events",}) +class ExportTimeline { + + private static final String EARLIEST_LATEST_FORMAT_STR = "MMM d, yyyy"; + private static final DateFormat EARLIEST_LATEST_FORMAT = TimelineSummary.getUtcFormat(EARLIEST_LATEST_FORMAT_STR); + private static final DateFormat CHART_FORMAT = TimelineSummary.getUtcFormat("MMM d, yyyy"); + private static final int MOST_RECENT_DAYS_COUNT = 30; + + private static final Color FILE_EVT_COLOR = new Color(228, 22, 28); + private static final Color ARTIFACT_EVT_COLOR = new Color(21, 227, 100); + + /** + * Creates new form PastCasesPanel + */ + private ExportTimeline() { + } + + /** + * Converts DailyActivityAmount data retrieved from TimelineSummaryGetter + * into data to be displayed as a bar chart. + * + * @param recentDaysActivity The data retrieved from + * TimelineSummaryGetter. + * @param showIntermediateDates If true, shows all dates. If false, shows + * only first and last date. + * + * @return The data to be displayed in the BarChart. + */ + private static List parseChartData(List recentDaysActivity, boolean showIntermediateDates) { + // if no data, return null indicating no result. + if (CollectionUtils.isEmpty(recentDaysActivity)) { + return null; + } + + // Create a bar chart item for each recent days activity item + List fileEvtCounts = new ArrayList<>(); + List artifactEvtCounts = new ArrayList<>(); + + for (int i = 0; i < recentDaysActivity.size(); i++) { + DailyActivityAmount curItem = recentDaysActivity.get(i); + + long fileAmt = curItem.getFileActivityCount(); + long artifactAmt = curItem.getArtifactActivityCount() * 100; + String formattedDate = (showIntermediateDates || i == 0 || i == recentDaysActivity.size() - 1) + ? TimelineSummary.formatDate(curItem.getDay(), CHART_FORMAT) : ""; + + OrderedKey thisKey = new OrderedKey(formattedDate, i); + fileEvtCounts.add(new BarChartItem(thisKey, fileAmt)); + artifactEvtCounts.add(new BarChartItem(thisKey, artifactAmt)); + } + + return Arrays.asList( + new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_fileEvts_title(), FILE_EVT_COLOR, fileEvtCounts), + new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_artifactEvts_title(), ARTIFACT_EVT_COLOR, artifactEvtCounts)); + } + + /** + * Create a default cell model to be use with excel export in the earliest / + * latest date format. + * + * @param date The date. + * @return The cell model. + */ + private static DefaultCellModel getEarliestLatestCell(Date date) { + return new DefaultCellModel<>(date, (dt) -> dt == null ? "" : EARLIEST_LATEST_FORMAT.format(dt), EARLIEST_LATEST_FORMAT_STR); + } + + @Messages({ + "TimelinePanel_getExports_sheetName=Timeline", + "TimelinePanel_getExports_activityRange=Activity Range", + "TimelinePanel_getExports_earliest=Earliest:", + "TimelinePanel_getExports_latest=Latest:", + "TimelinePanel_getExports_dateColumnHeader=Date", + "TimelinePanel_getExports_chartName=Last 30 Days",}) + static List getExports(DataSource dataSource) { + DataFetcher dataFetcher = (ds) -> TimelineSummary.getTimelineSummaryData(ds, MOST_RECENT_DAYS_COUNT); + TimelineSummaryData summaryData = ExcelExportAction.getFetchResult(dataFetcher, "Timeline", dataSource); + if (summaryData == null) { + return Collections.emptyList(); + } + + return Arrays.asList( + new ExcelSpecialFormatExport(Bundle.TimelinePanel_getExports_sheetName(), + Arrays.asList( + new TitledExportable(Bundle.TimelinePanel_getExports_activityRange(), Collections.emptyList()), + new KeyValueItemExportable(Bundle.TimelinePanel_getExports_earliest(), getEarliestLatestCell(summaryData.getMinDate())), + new KeyValueItemExportable(Bundle.TimelinePanel_getExports_latest(), getEarliestLatestCell(summaryData.getMaxDate())), + new BarChartExport(Bundle.TimelinePanel_getExports_dateColumnHeader(), + "#,###", + Bundle.TimelinePanel_getExports_chartName(), + parseChartData(summaryData.getMostRecentDaysActivity(), true))))); + } +} From e948b14c86f35e7ba04d2a77192aaace7a692ecd Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Fri, 6 Aug 2021 17:31:44 -0400 Subject: [PATCH 17/76] Moved file type export functionality --- .../contentutils/DataSourceInfoUtilities.java | 51 ++- .../contentutils/RecentFilesSummary.java | 3 - .../autopsy/contentutils/TypesSummary.java | 182 ++++++++++ ...ummary.java => MimeTypeSummaryGetter.java} | 68 ++-- ...esSummary.java => TypesSummaryGetter.java} | 69 ++-- .../datasourcesummary/ui/TypesPanel.java | 135 ++------ .../Bundle.properties-MERGED | 20 ++ .../ExcelExportAction.java | 11 +- .../datasourcesummaryexport/ExportTypes.java | 312 ++++++++++++++++++ 9 files changed, 653 insertions(+), 198 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/contentutils/TypesSummary.java rename Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/{MimeTypeSummary.java => MimeTypeSummaryGetter.java} (77%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/{TypesSummary.java => TypesSummaryGetter.java} (72%) create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/DataSourceInfoUtilities.java b/Core/src/org/sleuthkit/autopsy/contentutils/DataSourceInfoUtilities.java index b8bc2a54b6..2b69808eba 100644 --- a/Core/src/org/sleuthkit/autopsy/contentutils/DataSourceInfoUtilities.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/DataSourceInfoUtilities.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.contentutils; import java.sql.ResultSet; import java.sql.SQLException; +import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Comparator; import java.util.Date; @@ -45,10 +46,12 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_META_TYPE_ENUM; */ public final class DataSourceInfoUtilities { + public static final String COMMA_FORMAT_STR = "#,###"; + public static final DecimalFormat COMMA_FORMATTER = new DecimalFormat(COMMA_FORMAT_STR); + /** * Gets a count of tsk_files for a particular datasource. * - * @param skCase The current SleuthkitCase. * @param currentDataSource The datasource. * @param additionalWhere Additional sql where clauses. * @@ -56,11 +59,12 @@ public final class DataSourceInfoUtilities { * * @throws TskCoreException * @throws SQLException + * @throws NoCurrentCaseException */ - public static Long getCountOfTskFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) - throws TskCoreException, SQLException { + public static Long getCountOfTskFiles(DataSource currentDataSource, String additionalWhere) + throws TskCoreException, SQLException, NoCurrentCaseException { if (currentDataSource != null) { - return skCase.countFilesWhere( + return Case.getCurrentCaseThrows().getSleuthkitCase().countFilesWhere( "data_source_obj_id=" + currentDataSource.getId() + (StringUtils.isBlank(additionalWhere) ? "" : (" AND " + additionalWhere))); } @@ -70,7 +74,6 @@ public final class DataSourceInfoUtilities { /** * Gets a count of regular files for a particular datasource. * - * @param skCase The current SleuthkitCase. * @param currentDataSource The datasource. * @param additionalWhere Additional sql where clauses. * @@ -78,22 +81,22 @@ public final class DataSourceInfoUtilities { * * @throws TskCoreException * @throws SQLException + * @throws NoCurrentCaseException */ - public static Long getCountOfRegularFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) - throws TskCoreException, SQLException { + public static Long getCountOfRegularFiles(DataSource currentDataSource, String additionalWhere) + throws TskCoreException, SQLException, NoCurrentCaseException { String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue(); if (StringUtils.isNotBlank(additionalWhere)) { whereClause += " AND " + additionalWhere; } - return getCountOfTskFiles(skCase, currentDataSource, whereClause); + return getCountOfTskFiles(currentDataSource, whereClause); } /** * Gets a count of regular non-slack files for a particular datasource. * - * @param skCase The current SleuthkitCase. * @param currentDataSource The datasource. * @param additionalWhere Additional sql where clauses. * @@ -101,9 +104,10 @@ public final class DataSourceInfoUtilities { * * @throws TskCoreException * @throws SQLException + * @throws NoCurrentCaseException */ - public static Long getCountOfRegNonSlackFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) - throws TskCoreException, SQLException { + public static Long getCountOfRegNonSlackFiles(DataSource currentDataSource, String additionalWhere) + throws TskCoreException, SQLException, NoCurrentCaseException { String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue() + " AND type<>" + TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType(); @@ -111,7 +115,7 @@ public final class DataSourceInfoUtilities { whereClause += " AND " + additionalWhere; } - return getCountOfTskFiles(skCase, currentDataSource, whereClause); + return getCountOfTskFiles(currentDataSource, whereClause); } /** @@ -429,4 +433,27 @@ public final class DataSourceInfoUtilities { Long longVal = getLongOrNull(artifact, attributeType); return (longVal == null || longVal == 0) ? null : new Date(longVal * 1000); } + + /** + * Returns the long value or zero if longVal is null. + * + * @param longVal The long value. + * + * @return The long value or 0 if provided value is null. + */ + public static long getLongOrZero(Long longVal) { + return longVal == null ? 0 : longVal; + } + + /** + * Returns string value of long with comma separators. If null returns a + * string of '0'. + * + * @param longVal The long value. + * + * @return The string value of the long. + */ + public static String getStringOrZero(Long longVal) { + return longVal == null ? "0" : COMMA_FORMATTER.format(longVal); + } } diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java index f298602351..fd2d8341e7 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java @@ -22,14 +22,11 @@ import java.nio.file.Paths; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.lang.StringUtils; import org.sleuthkit.autopsy.casemodule.Case; diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/TypesSummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/TypesSummary.java new file mode 100755 index 0000000000..4c6944de37 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentutils/TypesSummary.java @@ -0,0 +1,182 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 - 2021 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.contentutils; + +import java.awt.Color; +import java.sql.SQLException; +import java.util.Set; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.coreutils.FileTypeUtils; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; + +/** + * Helper class for getting summary information on the known files present in the + * specified DataSource.. + */ +public class TypesSummary { + + private TypesSummary() { + } + + /** + * Get count of regular files (not directories) in a data source. + * + * @param currentDataSource The data source. + * + * @return The count. + * + * @throws TskCoreException + * @throws SQLException + * @throws NoCurrentCaseException + */ + public static Long getCountOfFiles(DataSource currentDataSource) + throws TskCoreException, SQLException, NoCurrentCaseException { + return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource, null); + } + + /** + * Get count of allocated files in a data source. + * + * @param currentDataSource The data source. + * + * @return The count. + * + * @throws TskCoreException + * @throws SQLException + * @throws NoCurrentCaseException + */ + public static Long getCountOfAllocatedFiles(DataSource currentDataSource) + throws TskCoreException, SQLException, NoCurrentCaseException { + + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, + DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)); + } + + /** + * Get count of unallocated files in a data source. + * + * @param currentDataSource The data source. + * + * @return The count. + * + * @throws TskCoreException + * @throws SQLException + * @throws NoCurrentCaseException + */ + public static Long getCountOfUnallocatedFiles(DataSource currentDataSource) + throws NoCurrentCaseException, TskCoreException, SQLException { + + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, + DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)); + } + + /** + * Get count of directories in a data source. + * + * @param currentDataSource The data source. + * + * @return The count. + * + * @throws TskCoreException + * @throws SQLException + * @throws NoCurrentCaseException + */ + public static Long getCountOfDirectories(DataSource currentDataSource) + throws NoCurrentCaseException, TskCoreException, SQLException { + + return DataSourceInfoUtilities.getCountOfTskFiles(currentDataSource, + "meta_type=" + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue() + + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()); + } + + /** + * Get count of slack files in a data source. + * + * @param currentDataSource The data source. + * + * @return The count. + * + * @throws TskCoreException + * @throws SQLException + * @throws NoCurrentCaseException + */ + public static Long getCountOfSlackFiles(DataSource currentDataSource) + throws NoCurrentCaseException, TskCoreException, SQLException { + + return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource, + "type=" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()); + } + + /** + * Information concerning a particular file type category. + */ + public static class FileTypeCategoryData { + + private final String label; + private final Set mimeTypes; + private final Color color; + + /** + * Main constructor. + * + * @param label The label for this slice. + * @param mimeTypes The mime types associated with this slice. + * @param color The color associated with this slice. + */ + public FileTypeCategoryData(String label, Set mimeTypes, Color color) { + this.label = label; + this.mimeTypes = mimeTypes; + this.color = color; + } + + /** + * Constructor that accepts FileTypeCategory. + * + * @param label The label for this slice. + * @param mimeTypes The mime types associated with this slice. + * @param color The color associated with this slice. + */ + public FileTypeCategoryData(String label, FileTypeUtils.FileTypeCategory fileCategory, Color color) { + this(label, fileCategory.getMediaTypes(), color); + } + + /** + * @return The label for this category. + */ + public String getLabel() { + return label; + } + + /** + * @return The mime types associated with this category. + */ + public Set getMimeTypes() { + return mimeTypes; + } + + /** + * @return The color associated with this category. + */ + public Color getColor() { + return color; + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummaryGetter.java similarity index 77% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummaryGetter.java index 1b8ac3fc1c..a0b29e8a7f 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummaryGetter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,10 +21,12 @@ package org.sleuthkit.autopsy.datasourcesummary.datamodel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; import java.sql.SQLException; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -34,11 +36,10 @@ import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; /** - * Provides methods to query for datasource files by mime type. + * Wrapper class for converting org.sleuthkit.autopsy.contentutils.TypesSummary + * functionality into a DefaultArtifactUpdateGovernor used by TypesPanel tab. */ -public class MimeTypeSummary implements DefaultUpdateGovernor { - - private final SleuthkitCaseProvider provider; +public class MimeTypeSummaryGetter implements DefaultUpdateGovernor { private static final Set INGEST_JOB_EVENTS = new HashSet<>( Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED)); @@ -46,17 +47,7 @@ public class MimeTypeSummary implements DefaultUpdateGovernor { /** * Main constructor. */ - public MimeTypeSummary() { - this(SleuthkitCaseProvider.DEFAULT); - } - - /** - * Main constructor. - * - * @param provider The means of obtaining a sleuthkit case. - */ - public MimeTypeSummary(SleuthkitCaseProvider provider) { - this.provider = provider; + public MimeTypeSummaryGetter() { } @Override @@ -76,7 +67,7 @@ public class MimeTypeSummary implements DefaultUpdateGovernor { @Override public Set getIngestJobEventUpdates() { - return INGEST_JOB_EVENTS; + return Collections.unmodifiableSet(INGEST_JOB_EVENTS); } /** @@ -99,12 +90,11 @@ public class MimeTypeSummary implements DefaultUpdateGovernor { */ public Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set setOfMimeTypes) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles( - provider.get(), - currentDataSource, - "mime_type IN " + getSqlSet(setOfMimeTypes) - ); + try { + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "mime_type IN " + getSqlSet(setOfMimeTypes)); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } } /** @@ -125,13 +115,13 @@ public class MimeTypeSummary implements DefaultUpdateGovernor { */ public Long getCountOfFilesNotInMimeTypes(DataSource currentDataSource, Set setOfMimeTypes) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles( - provider.get(), - currentDataSource, - "mime_type NOT IN " + getSqlSet(setOfMimeTypes) - + " AND mime_type IS NOT NULL AND mime_type <> '' " - ); + try { + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, + "mime_type NOT IN " + getSqlSet(setOfMimeTypes) + + " AND mime_type IS NOT NULL AND mime_type <> '' "); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } } /** @@ -147,8 +137,11 @@ public class MimeTypeSummary implements DefaultUpdateGovernor { */ public Long getCountOfAllRegularFiles(DataSource dataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), dataSource, null); + try { + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(dataSource, null); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } } /** @@ -165,12 +158,11 @@ public class MimeTypeSummary implements DefaultUpdateGovernor { */ public Long getCountOfFilesWithNoMimeType(DataSource currentDataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles( - provider.get(), - currentDataSource, - "(mime_type IS NULL OR mime_type = '') " - ); + try { + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "(mime_type IS NULL OR mime_type = '') "); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummaryGetter.java similarity index 72% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummaryGetter.java index 3b21654c14..7e0129382d 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummaryGetter.java @@ -21,41 +21,31 @@ package org.sleuthkit.autopsy.datasourcesummary.datamodel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; import java.sql.SQLException; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.Set; -import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.contentutils.TypesSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskData; /** - * Provides information for the DataSourceSummaryCountsPanel. + * Wrapper class for converting org.sleuthkit.autopsy.contentutils.TypesSummary functionality into a + * DefaultArtifactUpdateGovernor used by DataSourceSummaryCountsPanel. */ -public class TypesSummary implements DefaultUpdateGovernor { +public class TypesSummaryGetter implements DefaultUpdateGovernor { private static final Set INGEST_JOB_EVENTS = new HashSet<>( Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED)); - private final SleuthkitCaseProvider provider; - /** * Main constructor. */ - public TypesSummary() { - this(SleuthkitCaseProvider.DEFAULT); - } - - /** - * Main constructor. - * - * @param provider The means of obtaining a sleuthkit case. - */ - public TypesSummary(SleuthkitCaseProvider provider) { - this.provider = provider; + public TypesSummaryGetter() { } @Override @@ -75,7 +65,7 @@ public class TypesSummary implements DefaultUpdateGovernor { @Override public Set getIngestJobEventUpdates() { - return INGEST_JOB_EVENTS; + return Collections.unmodifiableSet(INGEST_JOB_EVENTS); } /** @@ -91,11 +81,11 @@ public class TypesSummary implements DefaultUpdateGovernor { */ public Long getCountOfFiles(DataSource currentDataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - return DataSourceInfoUtilities.getCountOfRegularFiles( - provider.get(), - currentDataSource, - null - ); + try { + return TypesSummary.getCountOfFiles(currentDataSource); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } } /** @@ -111,9 +101,11 @@ public class TypesSummary implements DefaultUpdateGovernor { */ public Long getCountOfAllocatedFiles(DataSource currentDataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, - DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)); + try { + return TypesSummary.getCountOfAllocatedFiles(currentDataSource); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } } /** @@ -129,9 +121,11 @@ public class TypesSummary implements DefaultUpdateGovernor { */ public Long getCountOfUnallocatedFiles(DataSource currentDataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, - DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)); + try { + return TypesSummary.getCountOfUnallocatedFiles(currentDataSource); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } } /** @@ -147,10 +141,11 @@ public class TypesSummary implements DefaultUpdateGovernor { */ public Long getCountOfDirectories(DataSource currentDataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - - return DataSourceInfoUtilities.getCountOfTskFiles(provider.get(), currentDataSource, - "meta_type=" + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue() - + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()); + try { + return TypesSummary.getCountOfDirectories(currentDataSource); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } } /** @@ -166,8 +161,10 @@ public class TypesSummary implements DefaultUpdateGovernor { */ public Long getCountOfSlackFiles(DataSource currentDataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - - return DataSourceInfoUtilities.getCountOfRegularFiles(provider.get(), currentDataSource, - "type=" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()); + try { + return TypesSummary.getCountOfSlackFiles(currentDataSource); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index e333888d0c..a5040a355e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,17 +23,17 @@ import java.sql.SQLException; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary; +import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; +import org.sleuthkit.autopsy.contentutils.TypesSummary.FileTypeCategoryData; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummaryGetter; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummaryGetter; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummaryGetter; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; @@ -90,7 +90,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { * @param usefulContent True if this is useful content; false if there * is 0 mime type information. */ - public TypesPieChartData(List pieSlices, boolean usefulContent) { + TypesPieChartData(List pieSlices, boolean usefulContent) { this.pieSlices = pieSlices; this.usefulContent = usefulContent; } @@ -98,78 +98,20 @@ class TypesPanel extends BaseDataSourceSummaryPanel { /** * @return The pie chart data. */ - public List getPieSlices() { + List getPieSlices() { return pieSlices; } /** * @return Whether or not the data is usefulContent. */ - public boolean isUsefulContent() { + boolean isUsefulContent() { return usefulContent; } } - /** - * Information concerning a particular category in the file types pie chart. - */ - private static class TypesPieCategory { - - private final String label; - private final Set mimeTypes; - private final Color color; - - /** - * Main constructor. - * - * @param label The label for this slice. - * @param mimeTypes The mime types associated with this slice. - * @param color The color associated with this slice. - */ - TypesPieCategory(String label, Set mimeTypes, Color color) { - this.label = label; - this.mimeTypes = mimeTypes; - this.color = color; - } - - /** - * Constructor that accepts FileTypeCategory. - * - * @param label The label for this slice. - * @param mimeTypes The mime types associated with this slice. - * @param color The color associated with this slice. - */ - TypesPieCategory(String label, FileTypeCategory fileCategory, Color color) { - this(label, fileCategory.getMediaTypes(), color); - } - - /** - * @return The label for this category. - */ - String getLabel() { - return label; - } - - /** - * @return The mime types associated with this category. - */ - Set getMimeTypes() { - return mimeTypes; - } - - /** - * @return The color associated with this category. - */ - Color getColor() { - return color; - } - } - private static final long serialVersionUID = 1L; private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#"); - private static final String COMMA_FORMAT_STR = "#,###"; - - private static final DecimalFormat COMMA_FORMATTER = new DecimalFormat(COMMA_FORMAT_STR); private static final Color IMAGES_COLOR = new Color(156, 39, 176); private static final Color VIDEOS_COLOR = Color.YELLOW; @@ -181,13 +123,13 @@ class TypesPanel extends BaseDataSourceSummaryPanel { private static final Color NOT_ANALYZED_COLOR = Color.WHITE; // All file type categories. - private static final List FILE_MIME_TYPE_CATEGORIES = Arrays.asList( - new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE.getMediaTypes(), IMAGES_COLOR), - new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_videos_title(), FileTypeCategory.VIDEO.getMediaTypes(), VIDEOS_COLOR), - new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_audio_title(), FileTypeCategory.AUDIO.getMediaTypes(), AUDIO_COLOR), - new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_documents_title(), FileTypeCategory.DOCUMENTS.getMediaTypes(), DOCUMENTS_COLOR), - new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_executables_title(), FileTypeCategory.EXECUTABLE.getMediaTypes(), EXECUTABLES_COLOR), - new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")), UNKNOWN_COLOR) + private static final List FILE_MIME_TYPE_CATEGORIES = Arrays.asList( + new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE.getMediaTypes(), IMAGES_COLOR), + new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_videos_title(), FileTypeCategory.VIDEO.getMediaTypes(), VIDEOS_COLOR), + new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_audio_title(), FileTypeCategory.AUDIO.getMediaTypes(), AUDIO_COLOR), + new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_documents_title(), FileTypeCategory.DOCUMENTS.getMediaTypes(), DOCUMENTS_COLOR), + new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_executables_title(), FileTypeCategory.EXECUTABLE.getMediaTypes(), EXECUTABLES_COLOR), + new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")), UNKNOWN_COLOR) ); private final DataFetcher usageFetcher; @@ -233,7 +175,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { * Creates a new TypesPanel. */ public TypesPanel() { - this(new MimeTypeSummary(), new TypesSummary(), new ContainerSummaryGetter()); + this(new MimeTypeSummaryGetter(), new TypesSummaryGetter(), new ContainerSummaryGetter()); } @Override @@ -250,8 +192,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel { * @param containerData The service for container information. */ public TypesPanel( - MimeTypeSummary mimeTypeData, - TypesSummary typeData, + MimeTypeSummaryGetter mimeTypeData, + TypesSummaryGetter typeData, ContainerSummaryGetter containerData) { super(mimeTypeData, typeData, containerData); @@ -277,13 +219,13 @@ class TypesPanel extends BaseDataSourceSummaryPanel { size -> SizeRepresentationUtil.getSizeString(size, INTEGER_SIZE_FORMAT, false)))), new DataFetchWorker.DataFetchComponents<>(typesFetcher, this::showMimeTypeCategories), new DataFetchWorker.DataFetchComponents<>(allocatedFetcher, - countRes -> allocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))), + countRes -> allocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count)))), new DataFetchWorker.DataFetchComponents<>(unallocatedFetcher, - countRes -> unallocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))), + countRes -> unallocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count)))), new DataFetchWorker.DataFetchComponents<>(slackFetcher, - countRes -> slackLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))), + countRes -> slackLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count)))), new DataFetchWorker.DataFetchComponents<>(directoriesFetcher, - countRes -> directoriesLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))) + countRes -> directoriesLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count)))) ); initComponents(); @@ -307,7 +249,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { * * @return The pie chart items. */ - private TypesPieChartData getMimeTypeCategoriesModel(MimeTypeSummary mimeTypeData, DataSource dataSource) + private TypesPieChartData getMimeTypeCategoriesModel(MimeTypeSummaryGetter mimeTypeData, DataSource dataSource) throws SQLException, SleuthkitCaseProviderException, TskCoreException { if (dataSource == null) { @@ -318,8 +260,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel { List fileCategoryItems = new ArrayList<>(); long categoryTotalCount = 0; - for (TypesPieCategory cat : FILE_MIME_TYPE_CATEGORIES) { - long thisValue = getLongOrZero(mimeTypeData.getCountOfFilesForMimeTypes(dataSource, cat.getMimeTypes())); + for (FileTypeCategoryData cat : FILE_MIME_TYPE_CATEGORIES) { + long thisValue = DataSourceInfoUtilities.getLongOrZero(mimeTypeData.getCountOfFilesForMimeTypes(dataSource, cat.getMimeTypes())); categoryTotalCount += thisValue; fileCategoryItems.add(new PieChartItem( @@ -329,10 +271,10 @@ class TypesPanel extends BaseDataSourceSummaryPanel { } // get a count of all files with no mime type - long noMimeTypeCount = getLongOrZero(mimeTypeData.getCountOfFilesWithNoMimeType(dataSource)); + long noMimeTypeCount = DataSourceInfoUtilities.getLongOrZero(mimeTypeData.getCountOfFilesWithNoMimeType(dataSource)); // get a count of all regular files - long allRegularFiles = getLongOrZero(mimeTypeData.getCountOfAllRegularFiles(dataSource)); + long allRegularFiles = DataSourceInfoUtilities.getLongOrZero(mimeTypeData.getCountOfAllRegularFiles(dataSource)); // create entry for mime types in other category long otherCount = allRegularFiles - (categoryTotalCount + noMimeTypeCount); @@ -385,29 +327,6 @@ class TypesPanel extends BaseDataSourceSummaryPanel { } } - /** - * Returns the long value or zero if longVal is null. - * - * @param longVal The long value. - * - * @return The long value or 0 if provided value is null. - */ - private static long getLongOrZero(Long longVal) { - return longVal == null ? 0 : longVal; - } - - /** - * Returns string value of long with comma separators. If null returns a - * string of '0'. - * - * @param longVal The long value. - * - * @return The string value of the long. - */ - private static String getStringOrZero(Long longVal) { - return longVal == null ? "0" : COMMA_FORMATTER.format(longVal); - } - /** * Returns a key value pair to be exported in a sheet. * diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index 07d26f8e14..6b90d2414d 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -5,6 +5,7 @@ DataSourceSummaryReport.endReport.srcModuleName.text=Excel Report ExcelExport_writeExcel_noSheetName=Sheet {0} ExcelExportAction_exportToXLSX_beginExport=Beginning Export... ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data +ExcelExportAction_exportToXLSX_gatheringFileData=Fetching File and MIME Type Data ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data ExcelExportAction_exportToXLSX_writingToFile=Writing to File... @@ -32,6 +33,25 @@ ExportRecentFiles_col_header_path=Path ExportRecentFiles_col_header_sender=Sender ExportRecentFiles_docsTable_tabName=Recently Opened Documents ExportRecentFiles_downloadsTable_tabName=Recently Downloads +ExportTypes_artifactsTypesPieChart_title=Artifact Types +ExportTypes_excelTabName=Types +ExportTypes_fileMimeTypesChart_audio_title=Audio +ExportTypes_fileMimeTypesChart_documents_title=Documents +ExportTypes_fileMimeTypesChart_executables_title=Executables +ExportTypes_fileMimeTypesChart_images_title=Images +ExportTypes_fileMimeTypesChart_notAnalyzed_title=Not Analyzed +ExportTypes_fileMimeTypesChart_other_title=Other +ExportTypes_fileMimeTypesChart_title=File Types +ExportTypes_fileMimeTypesChart_unknown_title=Unknown +ExportTypes_fileMimeTypesChart_valueLabel=Count +ExportTypes_fileMimeTypesChart_videos_title=Videos +ExportTypes_filesByCategoryTable_allocatedRow_title=Allocated Files +ExportTypes_filesByCategoryTable_directoryRow_title=Directories +ExportTypes_filesByCategoryTable_slackRow_title=Slack Files +ExportTypes_filesByCategoryTable_unallocatedRow_title=Unallocated Files +ExportTypes_osLabel_title=OS +ExportTypes_sizeLabel_title=Size +ExportTypes_usageLabel_title=Usage SizeRepresentationUtil_units_bytes=bytes SizeRepresentationUtil_units_gigabytes=GB SizeRepresentationUtil_units_kilobytes=KB diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index 8492b4aca6..842ad9179a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -93,6 +93,7 @@ class ExcelExportAction { "ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data", "ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data", "ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data", + "ExcelExportAction_exportToXLSX_gatheringFileData=Fetching File and MIME Type Data", "ExcelExportAction_exportToXLSX_writingToFile=Writing to File...",}) void exportToXLSX(ReportProgressPanel progressPanel, DataSource dataSource, String baseReportDir) @@ -127,7 +128,15 @@ class ExcelExportAction { exports = ExportTimeline.getExports(dataSource); if (exports != null) { sheetExports.addAll(exports); - } + } + + // Export file and MIME type data + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringFileData()); + progressPanel.setProgress(4); + exports = ExportTypes.getExports(dataSource); + if (exports != null) { + sheetExports.addAll(exports); + } progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_writingToFile()); progressPanel.setProgress(9); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java new file mode 100755 index 0000000000..5453a879c8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java @@ -0,0 +1,312 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019-2021 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.report.modules.datasourcesummaryexport; + +import java.awt.Color; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.contentutils.ContainerSummary; +import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory; +import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; +import org.sleuthkit.autopsy.contentutils.TypesSummary; +import org.sleuthkit.autopsy.contentutils.TypesSummary.FileTypeCategoryData; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.KeyValueItemExportable; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Panel for displaying summary information on the known files present in the + * specified DataSource. + */ +@Messages({ + "ExportTypes_artifactsTypesPieChart_title=Artifact Types", + "ExportTypes_filesByCategoryTable_allocatedRow_title=Allocated Files", + "ExportTypes_filesByCategoryTable_unallocatedRow_title=Unallocated Files", + "ExportTypes_filesByCategoryTable_slackRow_title=Slack Files", + "ExportTypes_filesByCategoryTable_directoryRow_title=Directories", + "ExportTypes_fileMimeTypesChart_title=File Types", + "ExportTypes_fileMimeTypesChart_valueLabel=Count", + "ExportTypes_fileMimeTypesChart_audio_title=Audio", + "ExportTypes_fileMimeTypesChart_documents_title=Documents", + "ExportTypes_fileMimeTypesChart_executables_title=Executables", + "ExportTypes_fileMimeTypesChart_images_title=Images", + "ExportTypes_fileMimeTypesChart_videos_title=Videos", + "ExportTypes_fileMimeTypesChart_other_title=Other", + "ExportTypes_fileMimeTypesChart_unknown_title=Unknown", + "ExportTypes_fileMimeTypesChart_notAnalyzed_title=Not Analyzed", + "ExportTypes_usageLabel_title=Usage", + "ExportTypes_osLabel_title=OS", + "ExportTypes_sizeLabel_title=Size", + "ExportTypes_excelTabName=Types"}) +class ExportTypes { + + /** + * Data for types pie chart. + */ + private static class TypesPieChartData { + + private final List pieSlices; + private final boolean usefulContent; + + /** + * Main constructor. + * + * @param pieSlices The pie slices. + * @param usefulContent True if this is useful content; false if there + * is 0 mime type information. + */ + TypesPieChartData(List pieSlices, boolean usefulContent) { + this.pieSlices = pieSlices; + this.usefulContent = usefulContent; + } + + /** + * @return The pie chart data. + */ + List getPieSlices() { + return pieSlices; + } + + /** + * @return Whether or not the data is usefulContent. + */ + boolean isUsefulContent() { + return usefulContent; + } + } + + private static final Color IMAGES_COLOR = new Color(156, 39, 176); + private static final Color VIDEOS_COLOR = Color.YELLOW; + private static final Color AUDIO_COLOR = Color.BLUE; + private static final Color DOCUMENTS_COLOR = Color.GREEN; + private static final Color EXECUTABLES_COLOR = new Color(0, 188, 212); + private static final Color UNKNOWN_COLOR = Color.ORANGE; + private static final Color OTHER_COLOR = new Color(78, 52, 46); + private static final Color NOT_ANALYZED_COLOR = Color.WHITE; + + // All file type categories. + private static final List FILE_MIME_TYPE_CATEGORIES = Arrays.asList( + new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE.getMediaTypes(), IMAGES_COLOR), + new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_videos_title(), FileTypeCategory.VIDEO.getMediaTypes(), VIDEOS_COLOR), + new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_audio_title(), FileTypeCategory.AUDIO.getMediaTypes(), AUDIO_COLOR), + new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_documents_title(), FileTypeCategory.DOCUMENTS.getMediaTypes(), DOCUMENTS_COLOR), + new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_executables_title(), FileTypeCategory.EXECUTABLE.getMediaTypes(), EXECUTABLES_COLOR), + new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")), UNKNOWN_COLOR) + ); + + private ExportTypes() { + } + + /** + * Derives a sql set string (i.e. "('val1', 'val2', 'val3')"). A naive + * attempt is made to sanitize the strings by removing single quotes from + * values. + * + * @param setValues The values that should be present in the set. Single + * quotes are removed. + * + * @return The sql set string. + */ + private static String getSqlSet(Set setValues) { + List quotedValues = setValues + .stream() + .map(str -> String.format("'%s'", str.replace("'", ""))) + .collect(Collectors.toList()); + + String commaSeparatedQuoted = String.join(", ", quotedValues); + return String.format("(%s) ", commaSeparatedQuoted); + } + + /** + * Get the number of files in the case database for the current data source + * which have the specified mimetypes. + * + * @param currentDataSource the data source which we are finding a file + * count + * + * @param setOfMimeTypes the set of mime types which we are finding the + * number of occurences of + * + * @return a Long value which represents the number of occurrences of the + * specified mime types in the current case for the specified data + * source, null if no count was retrieved + * + * @throws NoCurrentCaseException + * @throws TskCoreException + * @throws SQLException + */ + private static Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set setOfMimeTypes) throws TskCoreException, SQLException, NoCurrentCaseException { + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "mime_type IN " + getSqlSet(setOfMimeTypes)); + } + + /** + * Gets the number of files in the data source with no assigned mime type. + * + * @param currentDataSource The data source. + * + * @return The number of files with no mime type or null if there is an + * issue searching the data source. + * + * @throws NoCurrentCaseException + * @throws TskCoreException + * @throws SQLException + */ + private static Long getCountOfFilesWithNoMimeType(DataSource currentDataSource) throws TskCoreException, SQLException, NoCurrentCaseException { + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "(mime_type IS NULL OR mime_type = '') "); + } + + /** + * Gets all the data for the file type pie chart. + * + * @param mimeTypeData The means of acquiring data. + * @param dataSource The datasource. + * + * @return The pie chart items. + */ + private static TypesPieChartData getMimeTypeCategoriesModel(DataSource dataSource) + throws SQLException, TskCoreException, NoCurrentCaseException { + + if (dataSource == null) { + return null; + } + + // for each category of file types, get the counts of files + List fileCategoryItems = new ArrayList<>(); + long categoryTotalCount = 0; + + for (FileTypeCategoryData cat : FILE_MIME_TYPE_CATEGORIES) { + long thisValue = DataSourceInfoUtilities.getLongOrZero(getCountOfFilesForMimeTypes(dataSource, cat.getMimeTypes())); + categoryTotalCount += thisValue; + + fileCategoryItems.add(new PieChartItem( + cat.getLabel(), + thisValue, + cat.getColor())); + } + + // get a count of all files with no mime type + long noMimeTypeCount = DataSourceInfoUtilities.getLongOrZero(getCountOfFilesWithNoMimeType(dataSource)); + + // get a count of all regular files + long allRegularFiles = DataSourceInfoUtilities.getLongOrZero(DataSourceInfoUtilities.getCountOfRegNonSlackFiles(dataSource, null)); + + // create entry for mime types in other category + long otherCount = allRegularFiles - (categoryTotalCount + noMimeTypeCount); + PieChartItem otherPieItem = new PieChartItem(Bundle.ExportTypes_fileMimeTypesChart_other_title(), + otherCount, OTHER_COLOR); + + // check at this point to see if these are all 0; if so, we don't have useful content. + boolean usefulContent = categoryTotalCount > 0 || otherCount > 0; + + // create entry for not analyzed mime types category + PieChartItem notAnalyzedItem = new PieChartItem(Bundle.ExportTypes_fileMimeTypesChart_notAnalyzed_title(), + noMimeTypeCount, NOT_ANALYZED_COLOR); + + // combine categories with 'other' and 'not analyzed' + List items = Stream.concat( + fileCategoryItems.stream(), + Stream.of(otherPieItem, notAnalyzedItem)) + // remove items that have no value + .filter(slice -> slice.getValue() > 0) + .collect(Collectors.toList()); + + return new TypesPieChartData(items, usefulContent); + } + + /** + * Returns a key value pair to be exported in a sheet. + * + * @param fetcher The means of fetching the data. + * @param key The key to use. + * @param dataSource The data source containing the data. + * + * @return The key value pair to be exported. + */ + private static KeyValueItemExportable getStrExportable(DataFetcher fetcher, String key, DataSource dataSource) { + String result = ExcelExportAction.getFetchResult(fetcher, "Types", dataSource); + return (result == null) ? null : new KeyValueItemExportable(key, new DefaultCellModel<>(result)); + } + + /** + * Returns a key value pair to be exported in a sheet formatting the long + * with commas separated by orders of 1000. + * + * @param fetcher The means of fetching the data. + * @param key The string key for this key value pair. + * @param dataSource The data source. + * + * @return The key value pair. + */ + private static KeyValueItemExportable getCountExportable(DataFetcher fetcher, String key, DataSource dataSource) { + Long count = ExcelExportAction.getFetchResult(fetcher, "Types", dataSource); + return (count == null) ? null : new KeyValueItemExportable(key, + new DefaultCellModel(count, DataSourceInfoUtilities.COMMA_FORMATTER::format, DataSourceInfoUtilities.COMMA_FORMAT_STR)); + } + + static List getExports(DataSource dataSource) { + if (dataSource == null) { + return Collections.emptyList(); + } + + DataFetcher usageFetcher = (ds) -> ContainerSummary.getDataSourceType(ds); + DataFetcher osFetcher = (ds) -> ContainerSummary.getOperatingSystems(ds); + DataFetcher sizeFetcher = (ds) -> ds == null ? null : ds.getSize(); + + DataFetcher typesFetcher = (ds) -> getMimeTypeCategoriesModel(ds); + + DataFetcher allocatedFetcher = (ds) -> TypesSummary.getCountOfAllocatedFiles(ds); + DataFetcher unallocatedFetcher = (ds) -> TypesSummary.getCountOfUnallocatedFiles(ds); + DataFetcher slackFetcher = (ds) -> TypesSummary.getCountOfSlackFiles(ds); + DataFetcher directoriesFetcher = (ds) -> TypesSummary.getCountOfDirectories(ds); + + // Retrieve data to create the types pie chart + TypesPieChartData typesData = ExcelExportAction.getFetchResult(typesFetcher, "Types", dataSource); + PieChartExport typesChart = (typesData == null || !typesData.isUsefulContent()) ? null + : new PieChartExport( + Bundle.ExportTypes_fileMimeTypesChart_title(), + Bundle.ExportTypes_fileMimeTypesChart_valueLabel(), + "#,###", + Bundle.ExportTypes_fileMimeTypesChart_title(), + typesData.getPieSlices()); + + return Arrays.asList(new ExcelSpecialFormatExport(Bundle.ExportTypes_excelTabName(), + Stream.of( + getStrExportable(usageFetcher, Bundle.ExportTypes_usageLabel_title(), dataSource), + getStrExportable(osFetcher, Bundle.ExportTypes_osLabel_title(), dataSource), + new KeyValueItemExportable(Bundle.ExportTypes_sizeLabel_title(), + SizeRepresentationUtil.getBytesCell(ExcelExportAction.getFetchResult(sizeFetcher, "Types", dataSource))), + typesChart, + getCountExportable(allocatedFetcher, Bundle.ExportTypes_filesByCategoryTable_allocatedRow_title(), dataSource), + getCountExportable(unallocatedFetcher, Bundle.ExportTypes_filesByCategoryTable_unallocatedRow_title(), dataSource), + getCountExportable(slackFetcher, Bundle.ExportTypes_filesByCategoryTable_slackRow_title(), dataSource), + getCountExportable(directoriesFetcher, Bundle.ExportTypes_filesByCategoryTable_directoryRow_title(), dataSource)) + .filter(sheet -> sheet != null) + .collect(Collectors.toList()) + )); + } +} From 445cb904ce344f7f256115ab8b7a7477e01feb28 Mon Sep 17 00:00:00 2001 From: Seb2lyon Date: Sat, 7 Aug 2021 18:32:27 +0200 Subject: [PATCH 18/76] Updated tanslation of page Doxyfile --- docs/doxygen-user_fr/Doxyfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/doxygen-user_fr/Doxyfile b/docs/doxygen-user_fr/Doxyfile index 80ef7fab53..177c9cdb6e 100644 --- a/docs/doxygen-user_fr/Doxyfile +++ b/docs/doxygen-user_fr/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "Documentation utilisateur Autopsy" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.19.0 +PROJECT_NUMBER = 4.19.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -1025,7 +1025,7 @@ GENERATE_HTML = YES # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_OUTPUT = 4.19.0 +HTML_OUTPUT = 4.19.1 # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). From df4964f94083625c3c6ce905f267bf4b8a864b19 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 9 Aug 2021 11:23:40 -0400 Subject: [PATCH 19/76] Refactored AnalysisPanel --- .../AnalysisSummary.java | 61 +++------- .../datamodel/AnalysisSummaryGetter.java | 115 ++++++++++++++++++ .../datasourcesummary/ui/AnalysisPanel.java | 20 +-- .../Bundle.properties-MERGED | 7 ++ .../ExcelExportAction.java | 59 +++++---- .../ExportAnalysisResults.java | 75 ++++++++++++ 6 files changed, 254 insertions(+), 83 deletions(-) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/datamodel => contentutils}/AnalysisSummary.java (68%) mode change 100644 => 100755 create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummaryGetter.java create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/AnalysisSummary.java old mode 100644 new mode 100755 similarity index 68% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java rename to Core/src/org/sleuthkit/autopsy/contentutils/AnalysisSummary.java index db9bc067c2..dc12c9edad --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/AnalysisSummary.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,11 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.contentutils; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -30,53 +28,25 @@ import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; -import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; /** - * Providing data for the data source analysis tab. + * Helper class for getting hash set hits, keyword hits, and interesting item + * hits within a datasource. */ -public class AnalysisSummary implements DefaultArtifactUpdateGovernor { +public class AnalysisSummary { private static final BlackboardAttribute.Type TYPE_SET_NAME = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME); - private static final Set EXCLUDED_KEYWORD_SEARCH_ITEMS = new HashSet<>(); - private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( - ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), - ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID(), - ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(), - ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() - )); - - private final SleuthkitCaseProvider provider; - - /** - * Main constructor. - */ - public AnalysisSummary() { - this(SleuthkitCaseProvider.DEFAULT); - } - - /** - * Main constructor. - * - * @param provider The means of obtaining a sleuthkit case. - */ - public AnalysisSummary(SleuthkitCaseProvider provider) { - this.provider = provider; - } - - @Override - public Set getArtifactTypeIdsForRefresh() { - return ARTIFACT_UPDATE_TYPE_IDS; + private AnalysisSummary() { } /** @@ -89,7 +59,7 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor { * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public List> getHashsetCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { + public static List> getHashsetCounts(DataSource dataSource) throws NoCurrentCaseException, TskCoreException { return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_HASHSET_HIT); } @@ -103,7 +73,7 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor { * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public List> getKeywordCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { + public static List> getKeywordCounts(DataSource dataSource) throws NoCurrentCaseException, TskCoreException { return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT).stream() // make sure we have a valid set and that that set does not belong to the set of excluded items .filter((pair) -> pair != null && pair.getKey() != null && !EXCLUDED_KEYWORD_SEARCH_ITEMS.contains(pair.getKey().toUpperCase().trim())) @@ -122,7 +92,7 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor { * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public List> getInterestingItemCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { + public static List> getInterestingItemCounts(DataSource dataSource) throws NoCurrentCaseException, TskCoreException { return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); } @@ -137,22 +107,21 @@ public class AnalysisSummary implements DefaultArtifactUpdateGovernor { * value and the value is the count of items found. This list is * sorted by the count descending max to min. * - * @throws SleuthkitCaseProviderException + * @throws NoCurrentCaseException * @throws TskCoreException */ - private List> getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes) - throws SleuthkitCaseProviderException, TskCoreException { + private static List> getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes) + throws NoCurrentCaseException, TskCoreException { if (dataSource == null) { return Collections.emptyList(); } List artifacts = new ArrayList<>(); - SleuthkitCase skCase = provider.get(); // get all artifacts in one list for each artifact type for (ARTIFACT_TYPE type : artifactTypes) { - artifacts.addAll(skCase.getBlackboard().getArtifacts(type.getTypeID(), dataSource.getId())); + artifacts.addAll(Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(type.getTypeID(), dataSource.getId())); } // group those based on the value of the attribute type that should serve as a key diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummaryGetter.java new file mode 100644 index 0000000000..33cf925fba --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummaryGetter.java @@ -0,0 +1,115 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020-2021 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.datasourcesummary.datamodel; + +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.apache.commons.lang3.tuple.Pair; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.contentutils.AnalysisSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Wrapper class for converting + * org.sleuthkit.autopsy.contentutils.AnalysisSummary functionality into a + * DefaultArtifactUpdateGovernor used by data source analysis tab. + */ +public class AnalysisSummaryGetter implements DefaultArtifactUpdateGovernor { + + private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( + ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), + ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID(), + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(), + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + )); + + /** + * Main constructor. + */ + public AnalysisSummaryGetter() { + } + + @Override + public Set getArtifactTypeIdsForRefresh() { + return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS); + } + + /** + * Gets counts for hashset hits. + * + * @param dataSource The datasource for which to identify hashset hits. + * + * @return The hashset set name with the number of hits in descending order. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + */ + public List> getHashsetCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { + try { + return AnalysisSummary.getHashsetCounts(dataSource); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } + + /** + * Gets counts for keyword hits. + * + * @param dataSource The datasource for which to identify keyword hits. + * + * @return The keyword set name with the number of hits in descending order. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + */ + public List> getKeywordCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { + try { + return AnalysisSummary.getKeywordCounts(dataSource); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } + + /** + * Gets counts for interesting item hits. + * + * @param dataSource The datasource for which to identify interesting item + * hits. + * + * @return The interesting item set name with the number of hits in + * descending order. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + */ + public List> getInterestingItemCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { + try { + return AnalysisSummary.getInterestingItemCounts(dataSource); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index 10f0df97dd..df86d973b1 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ import java.util.List; import java.util.function.Function; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummaryGetter; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; @@ -98,10 +98,10 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { * Creates a new DataSourceUserActivityPanel. */ public AnalysisPanel() { - this(new AnalysisSummary()); + this(new AnalysisSummaryGetter()); } - public AnalysisPanel(AnalysisSummary analysisData) { + public AnalysisPanel(AnalysisSummaryGetter analysisData) { super(analysisData); hashsetsFetcher = (dataSource) -> analysisData.getHashsetCounts(dataSource); @@ -226,18 +226,6 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { ); }// //GEN-END:initComponents - /* ELTODO - @Override - List getExports(DataSource dataSource) { - return Stream.of( - getTableExport(hashsetsFetcher, DEFAULT_COLUMNS, Bundle.AnalysisPanel_hashsetHits_tabName(), dataSource), - getTableExport(keywordsFetcher, DEFAULT_COLUMNS, Bundle.AnalysisPanel_keywordHits_tabName(), dataSource), - getTableExport(interestingItemsFetcher, DEFAULT_COLUMNS, Bundle.AnalysisPanel_interestingItemHits_tabName(), dataSource)) - .filter(sheet -> sheet != null) - .collect(Collectors.toList()); - }*/ - - // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index 6b90d2414d..e66edab769 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -4,6 +4,7 @@ DataSourceSummaryReport.endReport.srcModuleName.text=Excel Report # {0} - sheetNumber ExcelExport_writeExcel_noSheetName=Sheet {0} ExcelExportAction_exportToXLSX_beginExport=Beginning Export... +ExcelExportAction_exportToXLSX_gatheringAnalysisData=Fetching Analysis Data ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data ExcelExportAction_exportToXLSX_gatheringFileData=Fetching File and MIME Type Data ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data @@ -11,6 +12,12 @@ ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data ExcelExportAction_exportToXLSX_writingToFile=Writing to File... ExcelExportAction_getXLSXPath_directory=DataSourceSummary ExcelExportAction_moduleName=Data Source Summary +ExportAnalysisResults_countColumn_title=Count +ExportAnalysisResults_hashsetHits_tabName=Hashset Hits +ExportAnalysisResults_interestingItemHits_tabName=Interesting Item Hits +ExportAnalysisResults_keyColumn_title=Name +ExportAnalysisResults_keywordHits_tabName=Keyword Hits +ExportAnalysisResults_keywordSearchModuleName=Keyword Search ExportContainerInfo_export_acquisitionDetails=Acquisition Details: ExportContainerInfo_export_deviceId=Device ID: ExportContainerInfo_export_displayName=Display Name: diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index 842ad9179a..4524104515 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -60,8 +60,9 @@ class ExcelExportAction { * Generates an xlsx path for the data source summary export. * * @param dataSourceName The name of the data source. + * * @return The file to which the excel document should be written or null if - * file already exists or cancellation. + * file already exists or cancellation. */ @NbBundle.Messages({ "ExcelExportAction_getXLSXPath_directory=DataSourceSummary",}) @@ -82,8 +83,9 @@ class ExcelExportAction { * Action that handles updating progress and exporting data from the tabs. * * @param progressPanel The progress indicator. - * @param dataSource The data source to be exported. - * @param path The path of the excel export. + * @param dataSource The data source to be exported. + * @param path The path of the excel export. + * * @throws InterruptedException * @throws IOException * @throws ExcelExportException @@ -94,6 +96,7 @@ class ExcelExportAction { "ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data", "ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data", "ExcelExportAction_exportToXLSX_gatheringFileData=Fetching File and MIME Type Data", + "ExcelExportAction_exportToXLSX_gatheringAnalysisData=Fetching Analysis Data", "ExcelExportAction_exportToXLSX_writingToFile=Writing to File...",}) void exportToXLSX(ReportProgressPanel progressPanel, DataSource dataSource, String baseReportDir) @@ -113,7 +116,7 @@ class ExcelExportAction { if (exports != null) { sheetExports.addAll(exports); } - + // Export Container & Image info data progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringContainerData()); progressPanel.setProgress(2); @@ -129,7 +132,7 @@ class ExcelExportAction { if (exports != null) { sheetExports.addAll(exports); } - + // Export file and MIME type data progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringFileData()); progressPanel.setProgress(4); @@ -137,7 +140,15 @@ class ExcelExportAction { if (exports != null) { sheetExports.addAll(exports); } - + + // Export hash set hits, keyword hits, and interesting item hits + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringAnalysisData()); + progressPanel.setProgress(5); + exports = ExportAnalysisResults.getExports(dataSource); + if (exports != null) { + sheetExports.addAll(exports); + } + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_writingToFile()); progressPanel.setProgress(9); ExcelExport.writeExcel(sheetExports, reportFile); @@ -159,14 +170,13 @@ class ExcelExportAction { * ExcelExportDialog(WindowManager.getDefault().getMainWindow(), * path); dialog.setResizable(false); * dialog.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); - * dialog.setVisible(true); dialog.toFront(); - }); + * dialog.setVisible(true); dialog.toFront(); }); */ } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.WARNING, "There was an error attaching report to case.", ex); } } - + /** * Function that converts data into a excel sheet data. */ @@ -176,7 +186,9 @@ class ExcelExportAction { * Function that converts data into an excel sheet. * * @param data The data. + * * @return The excel sheet export. + * * @throws ExcelExportException */ ExcelSheetExport convert(T data) throws ExcelExportException; @@ -212,9 +224,10 @@ class ExcelExportAction { * possible excel exceptions. * * @param excelConverter Function to convert data to an excel sheet export. - * @param data The data. If data is null, null will be returned. - * @param sheetName The name(s) of the sheet (to be used in the error - * message). + * @param data The data. If data is null, null will be returned. + * @param sheetName The name(s) of the sheet (to be used in the error + * message). + * * @return The excel sheet export. */ protected static ExcelSheetExport convertToExcel(ExcelExportFunction excelConverter, T data, String sheetName) { @@ -236,10 +249,12 @@ class ExcelExportAction { * Returns an excel sheet export given the fetching of data or null if no * export created. * - * @param dataFetcher The means of fetching data. + * @param dataFetcher The means of fetching data. * @param excelConverter The means of converting data to excel. - * @param sheetName The name of the sheet (for error handling reporting). - * @param ds The data source to use for fetching data. + * @param sheetName The name of the sheet (for error handling + * reporting). + * @param ds The data source to use for fetching data. + * * @return The excel sheet export or null if no export could be generated. */ protected static ExcelSheetExport getExport( @@ -254,8 +269,9 @@ class ExcelExportAction { * Returns an excel table export of the data or null if no export created. * * @param columnsModel The model for the columns. - * @param sheetName The name for the sheet. - * @param data The data to be exported. + * @param sheetName The name for the sheet. + * @param data The data to be exported. + * * @return The excel table export or null if no export could be generated. */ protected static ExcelSheetExport getTableExport(List> columnsModel, @@ -269,11 +285,12 @@ class ExcelExportAction { /** * Returns an excel table export of the data or null if no export created. * - * @param dataFetcher The means of fetching data for the data source and the - * export. + * @param dataFetcher The means of fetching data for the data source and + * the export. * @param columnsModel The model for the columns. - * @param sheetName The name for the sheet. - * @param ds The data source. + * @param sheetName The name for the sheet. + * @param ds The data source. + * * @return The excel export or null if no export created. */ protected static ExcelSheetExport getTableExport( diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java new file mode 100755 index 0000000000..6ae7bb0381 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java @@ -0,0 +1,75 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.report.modules.datasourcesummaryexport; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.lang3.tuple.Pair; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.contentutils.AnalysisSummary; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelSheetExport; +import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getTableExport; +import org.sleuthkit.datamodel.DataSource; + +/** + * Class to export data hash set hits, keyword hits, and interesting item hits + * within a datasource. + */ +@Messages({ + "ExportAnalysisResults_keyColumn_title=Name", + "ExportAnalysisResults_countColumn_title=Count", + "ExportAnalysisResults_keywordSearchModuleName=Keyword Search", + "ExportAnalysisResults_hashsetHits_tabName=Hashset Hits", + "ExportAnalysisResults_keywordHits_tabName=Keyword Hits", + "ExportAnalysisResults_interestingItemHits_tabName=Interesting Item Hits",}) +class ExportAnalysisResults { + + // Default Column definitions for each table + private static final List, DefaultCellModel>> DEFAULT_COLUMNS = Arrays.asList( + new ColumnModel<>( + Bundle.ExportAnalysisResults_keyColumn_title(), + (pair) -> new DefaultCellModel<>(pair.getKey()), + 300 + ), + new ColumnModel<>( + Bundle.ExportAnalysisResults_countColumn_title(), + (pair) -> new DefaultCellModel<>(pair.getValue()), + 100 + ) + ); + + private ExportAnalysisResults() { + } + + static List getExports(DataSource dataSource) { + + DataFetcher>> hashsetsFetcher = (ds) -> AnalysisSummary.getHashsetCounts(ds); + DataFetcher>> keywordsFetcher = (ds) -> AnalysisSummary.getKeywordCounts(ds); + DataFetcher>> interestingItemsFetcher = (ds) -> AnalysisSummary.getInterestingItemCounts(ds); + + return Stream.of( + getTableExport(hashsetsFetcher, DEFAULT_COLUMNS, Bundle.ExportAnalysisResults_hashsetHits_tabName(), dataSource), + getTableExport(keywordsFetcher, DEFAULT_COLUMNS, Bundle.ExportAnalysisResults_keywordHits_tabName(), dataSource), + getTableExport(interestingItemsFetcher, DEFAULT_COLUMNS, Bundle.ExportAnalysisResults_interestingItemHits_tabName(), dataSource)) + .filter(sheet -> sheet != null) + .collect(Collectors.toList()); + } +} From a368694c18c7df281f6fa1898663ca91c69bdf4a Mon Sep 17 00:00:00 2001 From: apriestman Date: Mon, 9 Aug 2021 15:13:41 -0400 Subject: [PATCH 20/76] Update python tutorials --- docs/doxygen/modDSIngestTutorial.dox | 39 ++++++------ docs/doxygen/modFileIngestTutorial.dox | 76 ++++++++++-------------- docs/doxygen/modReportModuleTutorial.dox | 2 +- 3 files changed, 54 insertions(+), 63 deletions(-) diff --git a/docs/doxygen/modDSIngestTutorial.dox b/docs/doxygen/modDSIngestTutorial.dox index c187f7ab33..ed8f128c13 100644 --- a/docs/doxygen/modDSIngestTutorial.dox +++ b/docs/doxygen/modDSIngestTutorial.dox @@ -76,29 +76,28 @@ With our connection in hand, we can do some queries. In our sample database, we stmt = dbConn.createStatement() resultSet = stmt.executeQuery("SELECT * FROM contacts")\endverbatim -For each row, we are going to get the values for the name, e-mail, and phone number and make a TSK_CONTACT artifact. Recall from the first tutorial that posting artifacts to the blackboard allows modules to communicate with each other and also allows you to easily display data to the user. The TSK_CONTACT artifact is for storing contact information. +For each row, we are going to get the values for the name, e-mail, and phone number and make a TSK_CONTACT artifact. Recall from the first tutorial that posting artifacts to the blackboard allows modules to communicate with each other and also allows you to easily display data to the user. The TSK_CONTACT artifact is for storing contact information. The artifact catalog shows that TSK_CONTACT is a data artifact, so we will be using the newDataArtifact() method to create each one. The basic approach in our example is to make an artifact of a given type (TSK_CONTACT) and have it be associated with the database it came from. We then make attributes for the name, email, and phone. The following code does this for each row in the database: \verbatim while resultSet.next(): - - # Make an artifact on the blackboard and give it attributes - art = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) - - name = resultSet.getString("name") - art.addAttribute(BlackboardAttribute( - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME_PERSON.getTypeID(), - ContactsDbIngestModuleFactory.moduleName, name)) - - email = resultSet.getString("email") - art.addAttribute(BlackboardAttribute( - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL.getTypeID(), - ContactsDbIngestModuleFactory.moduleName, email)) - - phone = resultSet.getString("phone") - art.addAttribute(BlackboardAttribute( - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID(), - ContactsDbIngestModuleFactory.moduleName, phone))\endverbatim + try: + name = resultSet.getString("name") + email = resultSet.getString("email") + phone = resultSet.getString("phone") + except SQLException as e: + self.log(Level.INFO, "Error getting values from contacts table (" + e.getMessage() + ")") + + + # Make an artifact on the blackboard, TSK_CONTACT and give it attributes for each of the fields + art = file.newDataArtifact(BlackboardArtifact.Type.TSK_CONTACT, Arrays.asList( + BlackboardAttribute(BlackboardAttribute.Type.TSK_NAME_PERSON, + ContactsDbIngestModuleFactory.moduleName, name), + BlackboardAttribute(BlackboardAttribute.Type.TSK_EMAIL, + ContactsDbIngestModuleFactory.moduleName, email), + BlackboardAttribute(BlackboardAttribute.Type.TSK_PHONE_NUMBER, + ContactsDbIngestModuleFactory.moduleName, phone) + ))\endverbatim That's it. We've just found the databases, queried them, and made artifacts for the user to see. There are some final things though. First, we should fire off an event so that the UI updates and refreshes with the new artifacts. We can fire just one event after each database is parsed (or you could fire one for each artifact - it's up to you). @@ -113,6 +112,8 @@ stmt.close() dbConn.close() os.remove(lclDbPath)\endverbatim +The final version of findContactsDb.py can be found on github. + \subsection python_tutorial2_niceties Niceties Data source-level ingest modules can run for quite some time. Therefore, data source-level ingest modules should do some additional things that file-level ingest modules do not need to. diff --git a/docs/doxygen/modFileIngestTutorial.dox b/docs/doxygen/modFileIngestTutorial.dox index 8079718137..dadc31305b 100644 --- a/docs/doxygen/modFileIngestTutorial.dox +++ b/docs/doxygen/modFileIngestTutorial.dox @@ -75,75 +75,65 @@ The process() method is passed in a reference to an AbstractFile Object. With th Now that we have found the files, we want to do something with them. In our situation, we just want to alert the user to them. We do this by making an "Interesting Item" blackboard artifact. The Blackboard is where ingest modules can communicate with each other and with the Autopsy GUI. The blackboard has a set of artifacts on it and each artifact:

  • Has a type
  • +
  • Has a category
  • Is associated with a file
  • Has one or more attributes. Attributes are simply name and value pairs.
-For our example, we are going to make an artifact of type "TSK_INTERESTING_FILE" whenever we find a big and round file. These are one of the most generic artifact types and are simply a way of alerting the user that a file is interesting for some reason. Once you make the artifact, it will be shown in the UI. The below code makes an artifact for the file and puts it into the set of "Big and Round Files". You can create whatever set names you want. The Autopsy GUI organizes Interesting Files by their set name. +A list of standard artifact types can be found in the artifact catalog. It is important to note the catagory for the artifact you want to since this affects which method you will use to create the artifact. + +For our example, we are going to make an artifact of type "TSK_INTERESTING_FILE", which is an analysis result, whenever we find a big and round file. These are one of the most generic artifact types and are simply a way of alerting the user that a file is interesting for some reason. Once you make the artifact, it will be shown in the UI. The below code makes an artifact for the file and puts it into the set of "Big and Round Files". You can create whatever set names you want. The Autopsy GUI organizes Interesting Files by their set name. \verbatim - art = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT) - att = BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), - FindBigRoundFilesIngestModuleFactory.moduleName, "Big and Round Files") - art.addAttribute(att)\endverbatim + art = file.newAnalysisResult(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, Score.SCORE_LIKELY_NOTABLE, + None, "Big and Round Files", None, + Arrays.asList( + BlackboardAttribute(BlackboardAttribute.Type.TSK_SET_NAME, + FindBigRoundFilesIngestModuleFactory.moduleName, + "Big and Round Files"))).getAnalysisResult()\endverbatim -The above code adds the artifact and a single attribute to the blackboard in the embedded database, but it does not notify other modules or the UI. The UI will eventually refresh, but it is faster to fire an event with this: +The above code adds the artifact and a single attribute to the blackboard in the embedded database, but it does not notify other modules or the UI. Calling postArtifact() will let the tree viewer and other parts of the UI know that a refresh may be necessary, and passes the newly created artifacts to other modules that may do further processing on it. \verbatim - IngestServices.getInstance().fireModuleDataEvent( - ModuleDataEvent(FindBigRoundFilesIngestModuleFactory.moduleName, - BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, None))\endverbatim + blackboard.postArtifact(art, FindBigRoundFilesIngestModuleFactory.moduleName)\endverbatim That's it. Your process() method should look something like this: \verbatim def process(self, file): + # Use blackboard class to index blackboard artifacts for keyword search + blackboard = Case.getCurrentCase().getSleuthkitCase().getBlackboard() + # Skip non-files - - if ((file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) or - - (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) or - + if ((file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) or + (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) or (file.isFile() == False)): - return IngestModule.ProcessResult.OK - - - # Look for files bigger than 10MB that are a multiple of 4096 - - if ((file.getSize() > 10485760) and ((file.getSize() % 4096) == 0)): - - + # Look for files bigger than 10MB that are a multiple of 4096 + if ((file.getSize() > 10485760) and ((file.getSize() % 4096) == 0)): # Make an artifact on the blackboard. TSK_INTERESTING_FILE_HIT is a generic type of - # artifact. Refer to the developer docs for other examples. + art = file.newAnalysisResult(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, Score.SCORE_LIKELY_NOTABLE, + None, "Big and Round Files", None, + Arrays.asList( + BlackboardAttribute(BlackboardAttribute.Type.TSK_SET_NAME, + FindBigRoundFilesIngestModuleFactory.moduleName, + "Big and Round Files"))).getAnalysisResult() - art = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT) + try: + # post the artifact for listeners of artifact events + blackboard.postArtifact(art, FindBigRoundFilesIngestModuleFactory.moduleName) + except Blackboard.BlackboardException as e: + self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName()) - att = BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), - - FindBigRoundFilesIngestModuleFactory.moduleName, "Big and Round Files") - - art.addAttribute(att) - - - - # Fire an event to notify the UI and others that there is a new artifact - - IngestServices.getInstance().fireModuleDataEvent( - - ModuleDataEvent(FindBigRoundFilesIngestModuleFactory.moduleName, - - BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, None)) - - - - return IngestModule.ProcessResult.OK\endverbatim + return IngestModule.ProcessResult.OK\endverbatim Save this file and run the module on some of your data. If you have any big and round files, you should see an entry under the "Interesting Items" node in the tree. \image html bigAndRoundFiles.png +The full big and round file module along with test data can be found on github. + \subsection python_tutorial1_debug Debugging and Development Tips Whenever you have syntax errors or other errors in your script, you will get some form of dialog from Autopsy when you try to run ingest modules. If that happens, fix the problem and run ingest modules again. You don't need to restart Autopsy each time! diff --git a/docs/doxygen/modReportModuleTutorial.dox b/docs/doxygen/modReportModuleTutorial.dox index ed2b184cf0..d620076df5 100644 --- a/docs/doxygen/modReportModuleTutorial.dox +++ b/docs/doxygen/modReportModuleTutorial.dox @@ -45,7 +45,7 @@ A third approach is to call org.sleuthkit.autopsy.casemodule.Case.getDataSources \subsubsection python_tutorial3_getting_artifacts Getting Blackboard Artifacts -The blackboard is where modules store their analysis results. If you want to include them in your report, then there are several methods that you could use. If you want all artifacts of a given type, then you can use SleuthkitCase.getBlackboardArtifacts(). There are many variations of this method that take different arguments. Look at them to find the one that is most convenient for you. +The blackboard is where modules store their analysis results. If you want to include them in your report, then there are several methods that you could use. If you want all artifacts of a given type, then you can use getDataArtifacts()or Blackboard.getAnalysisResultsByType(). There are variations of these methods that take different arguments. Look at them to find the one that is most convenient for you. \subsubsection python_tutorial3_getting_tags Getting Tagged Files or Artifacts From 44ad30fd8085d29221513da9b21cf85da56d09a0 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 9 Aug 2021 15:36:33 -0400 Subject: [PATCH 21/76] Refactored PastCasesSummary --- .../PastCasesSummary.java | 84 ++++++------------- .../datamodel/PastCasesSummaryGetter.java | 76 +++++++++++++++++ .../datasourcesummary/ui/PastCasesPanel.java | 26 ++---- .../Bundle.properties-MERGED | 5 ++ .../ExcelExportAction.java | 9 ++ .../ExportPastCases.java | 76 +++++++++++++++++ .../datasourcesummaryexport/ExportTypes.java | 2 +- 7 files changed, 197 insertions(+), 81 deletions(-) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/datamodel => contentutils}/PastCasesSummary.java (78%) mode change 100644 => 100755 create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummaryGetter.java create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/PastCasesSummary.java old mode 100644 new mode 100755 similarity index 78% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java rename to Core/src/org/sleuthkit/autopsy/contentutils/PastCasesSummary.java index e7776fbf62..d50f2b44d5 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/PastCasesSummary.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.contentutils; import java.util.ArrayList; import java.util.Arrays; @@ -25,14 +25,12 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; -import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -63,7 +61,7 @@ import org.sleuthkit.datamodel.TskCoreException; * d) The content of that TSK_COMMENT attribute will be of the form "Previous * Case: case1,case2...caseN" */ -public class PastCasesSummary implements DefaultArtifactUpdateGovernor { +public class PastCasesSummary { /** * Return type for results items in the past cases tab. @@ -99,11 +97,6 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { } } - private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( - ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), - ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() - )); - private static final String CENTRAL_REPO_INGEST_NAME = CentralRepoIngestModuleFactory.getModuleName().toUpperCase().trim(); private static final BlackboardAttribute.Type TYPE_COMMENT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_COMMENT); private static final BlackboardAttribute.Type TYPE_ASSOCIATED_ARTIFACT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT); @@ -118,39 +111,7 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { private static final String CASE_SEPARATOR = ","; private static final String PREFIX_END = ":"; - private final SleuthkitCaseProvider caseProvider; - private final java.util.logging.Logger logger; - - /** - * Main constructor. - */ - public PastCasesSummary() { - this( - SleuthkitCaseProvider.DEFAULT, - org.sleuthkit.autopsy.coreutils.Logger.getLogger(PastCasesSummary.class.getName()) - ); - - } - - /** - * Main constructor with external dependencies specified. This constructor - * is designed with unit testing in mind since mocked dependencies can be - * utilized. - * - * @param provider The object providing the current SleuthkitCase. - * @param logger The logger to use. - */ - public PastCasesSummary( - SleuthkitCaseProvider provider, - java.util.logging.Logger logger) { - - this.caseProvider = provider; - this.logger = logger; - } - - @Override - public Set getArtifactTypeIdsForRefresh() { - return ARTIFACT_UPDATE_TYPE_IDS; + private PastCasesSummary() { } /** @@ -225,7 +186,7 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { * @return The list of unique cases and their occurrences sorted from max to * min. */ - private List> getCaseCounts(Stream cases) { + private static List> getCaseCounts(Stream cases) { Collection> groupedCases = cases // group by case insensitive compare of cases .collect(Collectors.groupingBy((caseStr) -> caseStr.toUpperCase().trim())) @@ -250,21 +211,24 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { * * @return The artifact if found or null if not. * - * @throws SleuthkitCaseProviderException + * @throws NoCurrentCaseException */ - private BlackboardArtifact getParentArtifact(BlackboardArtifact artifact) throws SleuthkitCaseProviderException { + private static BlackboardArtifact getParentArtifact(BlackboardArtifact artifact) throws NoCurrentCaseException { Long parentId = DataSourceInfoUtilities.getLongOrNull(artifact, TYPE_ASSOCIATED_ARTIFACT); if (parentId == null) { return null; } - SleuthkitCase skCase = caseProvider.get(); try { - return skCase.getArtifactByArtifactId(parentId); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, - String.format("There was an error fetching the parent artifact of a TSK_INTERESTING_ARTIFACT_HIT (parent id: %d)", parentId), - ex); + return Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactByArtifactId(parentId); + } catch (TskCoreException ignore) { + /* + * I'm not certain why we ignore this, but it was previously simply + * logged as warning so I'm keeping the original logic + * logger.log(Level.WARNING, String.format("There was an error + * fetching the parent artifact of a TSK_INTERESTING_ARTIFACT_HIT + * (parent id: %d)", parentId), ex); + */ return null; } } @@ -276,9 +240,9 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { * * @return True if there is a device associated artifact. * - * @throws SleuthkitCaseProviderException + * @throws NoCurrentCaseException */ - private boolean hasDeviceAssociatedArtifact(BlackboardArtifact artifact) throws SleuthkitCaseProviderException { + private static boolean hasDeviceAssociatedArtifact(BlackboardArtifact artifact) throws NoCurrentCaseException { BlackboardArtifact parent = getParentArtifact(artifact); if (parent == null) { return false; @@ -294,17 +258,17 @@ public class PastCasesSummary implements DefaultArtifactUpdateGovernor { * * @return The retrieved data or null if null dataSource. * - * @throws SleuthkitCaseProviderException + * @throws NoCurrentCaseException * @throws TskCoreException */ - public PastCasesResult getPastCasesData(DataSource dataSource) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { + public static PastCasesResult getPastCasesData(DataSource dataSource) + throws NoCurrentCaseException, TskCoreException { if (dataSource == null) { return null; } - SleuthkitCase skCase = caseProvider.get(); + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); List deviceArtifactCases = new ArrayList<>(); List nonDeviceArtifactCases = new ArrayList<>(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummaryGetter.java new file mode 100644 index 0000000000..4d33ad6757 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummaryGetter.java @@ -0,0 +1,76 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 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.datasourcesummary.datamodel; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; +import org.sleuthkit.autopsy.contentutils.PastCasesSummary; +import org.sleuthkit.autopsy.contentutils.PastCasesSummary.PastCasesResult; +import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Wrapper class for converting org.sleuthkit.autopsy.contentutils.PastCasesSummary + * functionality into a DefaultArtifactUpdateGovernor used by PastCases tab. + */ +public class PastCasesSummaryGetter implements DefaultArtifactUpdateGovernor { + + private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( + ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), + ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() + )); + + public PastCasesSummaryGetter() { + } + + @Override + public Set getArtifactTypeIdsForRefresh() { + return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS); + } + + /** + * Returns the past cases data to be shown in the past cases tab. + * + * @param dataSource The data source. + * + * @return The retrieved data or null if null dataSource. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + */ + public PastCasesResult getPastCasesData(DataSource dataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { + + if (dataSource == null) { + return null; + } + + try { + return PastCasesSummary.getPastCasesData(dataSource); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index cdce933a1c..5886457530 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -22,8 +22,8 @@ import java.util.Arrays; import java.util.List; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.PastCasesResult; +import org.sleuthkit.autopsy.contentutils.PastCasesSummary.PastCasesResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummaryGetter; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; @@ -80,19 +80,19 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel(); private final DataFetcher pastCasesFetcher; - + public PastCasesPanel() { - this(new PastCasesSummary()); + this(new PastCasesSummaryGetter()); } /** * Creates new form PastCasesPanel */ - public PastCasesPanel(PastCasesSummary pastCaseData) { + public PastCasesPanel(PastCasesSummaryGetter pastCaseData) { super(pastCaseData); this.pastCasesFetcher = (dataSource) -> pastCaseData.getPastCasesData(dataSource); - + // set up data acquisition methods dataFetchComponents = Arrays.asList( new DataFetchWorker.DataFetchComponents<>( @@ -124,20 +124,6 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { onNewDataSource(dataFetchComponents, tables, dataSource); } - /* ELTODO - @Override - List getExports(DataSource dataSource) { - PastCasesResult result = getFetchResult(pastCasesFetcher, "Past cases sheets", dataSource); - if (result == null) { - return Collections.emptyList(); - } - - return Arrays.asList( - getTableExport(DEFAULT_TEMPLATE, Bundle.PastCasesPanel_notableFileTable_tabName(), result.getTaggedNotable()), - getTableExport(DEFAULT_TEMPLATE, Bundle.PastCasesPanel_sameIdsTable_tabName(), result.getSameIdsResults()) - ); - }*/ - @Override public void close() { ingestRunningLabel.unregister(); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index e66edab769..a0c9bb1d6e 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -33,6 +33,11 @@ ExportContainerInfo_export_timeZone=Time Zone: ExportContainerInfo_export_unallocatedSize=Unallocated Space: ExportContainerInfo_setFieldsForNonImageDataSource_na=N/A ExportContainerInfo_tabName=Container +ExportPastCases_caseColumn_title=Case +ExportPastCases_countColumn_title=Count +ExportPastCases_notableFileTable_tabName=Cases with Common Notable +ExportPastCases_onNoCrIngest_message=No results will be shown because the Central Repository module was not run. +ExportPastCases_sameIdsTable_tabName=Past Cases with the Same Devices ExportRecentFiles_attachmentsTable_tabName=Recent Attachments ExportRecentFiles_col_head_date=Date ExportRecentFiles_col_header_domain=Domain diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index 4524104515..50dd05a18c 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -97,6 +97,7 @@ class ExcelExportAction { "ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data", "ExcelExportAction_exportToXLSX_gatheringFileData=Fetching File and MIME Type Data", "ExcelExportAction_exportToXLSX_gatheringAnalysisData=Fetching Analysis Data", + "ExcelExportAction_exportToXLSX_gatheringPastData=Fetching Historical Data", "ExcelExportAction_exportToXLSX_writingToFile=Writing to File...",}) void exportToXLSX(ReportProgressPanel progressPanel, DataSource dataSource, String baseReportDir) @@ -148,6 +149,14 @@ class ExcelExportAction { if (exports != null) { sheetExports.addAll(exports); } + + // Export hash set hits, keyword hits, and interesting item hits + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringPastData()); + progressPanel.setProgress(6); + exports = ExportPastCases.getExports(dataSource); + if (exports != null) { + sheetExports.addAll(exports); + } progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_writingToFile()); progressPanel.setProgress(9); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java new file mode 100755 index 0000000000..6448adb369 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java @@ -0,0 +1,76 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.report.modules.datasourcesummaryexport; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.apache.commons.lang3.tuple.Pair; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.contentutils.PastCasesSummary; +import org.sleuthkit.autopsy.contentutils.PastCasesSummary.PastCasesResult; +import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getFetchResult; +import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getTableExport; +import org.sleuthkit.datamodel.DataSource; + +/** + * Class to export information about a datasource and how it pertains to other + * cases. + */ +@Messages({ + "ExportPastCases_caseColumn_title=Case", + "ExportPastCases_countColumn_title=Count", + "ExportPastCases_notableFileTable_tabName=Cases with Common Notable", + "ExportPastCases_sameIdsTable_tabName=Past Cases with the Same Devices",}) +class ExportPastCases { + + // model for column indicating the case + private static final ColumnModel, DefaultCellModel> CASE_COL = new ColumnModel<>( + Bundle.ExportPastCases_caseColumn_title(), + (pair) -> new DefaultCellModel<>(pair.getKey()), + 300 + ); + + // model for column indicating the count + private static final ColumnModel, DefaultCellModel> COUNT_COL = new ColumnModel<>( + Bundle.ExportPastCases_countColumn_title(), + (pair) -> new DefaultCellModel<>(pair.getValue()), + 100 + ); + + // the template for columns in both tables in this tab + private static List, DefaultCellModel>> DEFAULT_TEMPLATE + = Arrays.asList(CASE_COL, COUNT_COL); + + private ExportPastCases() { + } + + static List getExports(DataSource dataSource) { + DataFetcher pastCasesFetcher = (ds) -> PastCasesSummary.getPastCasesData(ds); + PastCasesResult result = getFetchResult(pastCasesFetcher, "Past cases sheets", dataSource); + if (result == null) { + return Collections.emptyList(); + } + + return Arrays.asList( + getTableExport(DEFAULT_TEMPLATE, Bundle.ExportPastCases_notableFileTable_tabName(), result.getTaggedNotable()), + getTableExport(DEFAULT_TEMPLATE, Bundle.ExportPastCases_sameIdsTable_tabName(), result.getSameIdsResults()) + ); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java index 5453a879c8..9253b5b09b 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java @@ -40,7 +40,7 @@ import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; /** - * Panel for displaying summary information on the known files present in the + * Class to export summary information on the known files present in the * specified DataSource. */ @Messages({ From 3d26fb30f0b3e24f061aa953d6307cc4b333d5c1 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Tue, 10 Aug 2021 10:05:24 -0400 Subject: [PATCH 22/76] Refactored UserActivity tab --- .../contentutils/Bundle.properties-MERGED | 2 + .../UserActivitySummary.java | 262 ++++++++---------- .../datamodel/UserActivitySummaryGetter.java | 237 ++++++++++++++++ .../ui/UserActivityPanel.java | 40 +-- .../Bundle.properties-MERGED | 25 +- .../ExcelExportAction.java | 11 +- .../ExportUserActivity.java | 248 +++++++++++++++++ .../UserActivitySummaryTests.java | 12 +- .../datamodel/UserActivitySummaryTest.java | 114 ++++---- 9 files changed, 709 insertions(+), 242 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/contentutils/Bundle.properties-MERGED rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/datamodel => contentutils}/UserActivitySummary.java (83%) mode change 100644 => 100755 create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryGetter.java create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentutils/Bundle.properties-MERGED new file mode 100755 index 0000000000..2e019a0248 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentutils/Bundle.properties-MERGED @@ -0,0 +1,2 @@ +DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=Call Log +DataSourceUserActivitySummary_getRecentAccounts_emailMessage=Email Message diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/UserActivitySummary.java old mode 100644 new mode 100755 similarity index 83% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java rename to Core/src/org/sleuthkit/autopsy/contentutils/UserActivitySummary.java index 5151617775..1d46523ebd --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/UserActivitySummary.java @@ -16,10 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.contentutils; import java.io.File; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -32,14 +31,13 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Function; -import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.DataSource; @@ -55,7 +53,7 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; * time, the data being provided for domains is fictitious and is done as a * placeholder. */ -public class UserActivitySummary implements DefaultArtifactUpdateGovernor { +public class UserActivitySummary { /** * Functions that determine the folder name of a list of path elements. If @@ -139,16 +137,6 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { .compareToIgnoreCase((b.getProgramName() == null ? "" : b.getProgramName())); }; - private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( - ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID(), - ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(), - ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(), - ARTIFACT_TYPE.TSK_CALLLOG.getTypeID(), - ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID(), - ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID(), - ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID() - )); - private static final Set DEVICE_EXCLUDE_LIST = new HashSet<>(Arrays.asList("ROOT_HUB", "ROOT_HUB20")); private static final Set DOMAIN_EXCLUDE_LIST = new HashSet<>(Arrays.asList("127.0.0.1", "LOCALHOST")); @@ -156,40 +144,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { private static final long DOMAIN_WINDOW_DAYS = 30; private static final long DOMAIN_WINDOW_MS = DOMAIN_WINDOW_DAYS * MS_PER_DAY; - private final SleuthkitCaseProvider caseProvider; - private final TextTranslationService translationService; - private final java.util.logging.Logger logger; - - /** - * Main constructor. - */ - public UserActivitySummary() { - this(SleuthkitCaseProvider.DEFAULT, TextTranslationService.getInstance(), - org.sleuthkit.autopsy.coreutils.Logger.getLogger(UserActivitySummary.class.getName())); - } - - /** - * Main constructor with external dependencies specified. This constructor - * is designed with unit testing in mind since mocked dependencies can be - * utilized. - * - * @param provider The object providing the current SleuthkitCase. - * @param translationService The translation service. - * @param logger The logger to use. - */ - public UserActivitySummary( - SleuthkitCaseProvider provider, - TextTranslationService translationService, - java.util.logging.Logger logger) { - - this.caseProvider = provider; - this.translationService = translationService; - this.logger = logger; - } - - @Override - public Set getArtifactTypeIdsForRefresh() { - return ARTIFACT_UPDATE_TYPE_IDS; + private UserActivitySummary() { } /** @@ -197,23 +152,57 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * * @param count The count being checked. */ - private void assertValidCount(int count) { + private static void assertValidCount(int count) { if (count <= 0) { throw new IllegalArgumentException("Count must be greater than 0"); } } + + /** + * Determines a short folder name if any. Otherwise, returns empty string. + * + * @param strPath The string path. + * @param applicationName The application name. + * + * @return The short folder name or empty string if not found. + */ + public static String getShortFolderName(String strPath, String applicationName) { + if (strPath == null) { + return ""; + } + + List pathEls = new ArrayList<>(Arrays.asList(applicationName)); + + File file = new File(strPath); + while (file != null && org.apache.commons.lang.StringUtils.isNotBlank(file.getName())) { + pathEls.add(file.getName()); + file = file.getParentFile(); + } + + Collections.reverse(pathEls); + + for (Function, String> matchEntry : SHORT_FOLDER_MATCHERS) { + String result = matchEntry.apply(pathEls); + if (org.apache.commons.lang.StringUtils.isNotBlank(result)) { + return result; + } + } + + return ""; + } /** * Gets a list of recent domains based on the datasource. * * @param dataSource The datasource to query for recent domains. - * @param count The max count of items to return. + * @param count The max count of items to return. * * @return The list of items retrieved from the database. * - * @throws InterruptedException + * @throws TskCoreException + * @throws NoCurrentCaseException */ - public List getRecentDomains(DataSource dataSource, int count) throws TskCoreException, SleuthkitCaseProviderException { + public static List getRecentDomains(DataSource dataSource, int count) throws TskCoreException, NoCurrentCaseException { assertValidCount(count); if (dataSource == null) { @@ -243,15 +232,15 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * Creates a TopDomainsResult from data or null if no visit date exists * within DOMAIN_WINDOW_MS of mostRecentMs. * - * @param domain The domain. - * @param visits The list of the artifact and its associated time in - * milliseconds. + * @param domain The domain. + * @param visits The list of the artifact and its associated time in + * milliseconds. * @param mostRecentMs The most recent visit of any domain. * * @return The TopDomainsResult or null if no visits to this domain within - * 30 days of mostRecentMs. + * 30 days of mostRecentMs. */ - private TopDomainsResult getDomainsResult(String domain, List> visits, long mostRecentMs) { + private static TopDomainsResult getDomainsResult(String domain, List> visits, long mostRecentMs) { long visitCount = 0; Long thisMostRecentMs = null; BlackboardArtifact thisMostRecentArtifact = null; @@ -289,15 +278,15 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * @param dataSource The datasource. * * @return A tuple where the first value is the latest web history accessed - * date in milliseconds and the second value maps normalized (lowercase; - * trimmed) domain names to when those domains were visited and the relevant - * artifact. + * date in milliseconds and the second value maps normalized + * (lowercase; trimmed) domain names to when those domains were + * visited and the relevant artifact. * * @throws TskCoreException - * @throws SleuthkitCaseProviderException + * @throws NoCurrentCaseException */ - private Pair>>> getDomainGroupsAndMostRecent(DataSource dataSource) throws TskCoreException, SleuthkitCaseProviderException { - List artifacts = DataSourceInfoUtilities.getArtifacts(caseProvider.get(), TYPE_WEB_HISTORY, + private static Pair>>> getDomainGroupsAndMostRecent(DataSource dataSource) throws TskCoreException, NoCurrentCaseException { + List artifacts = DataSourceInfoUtilities.getArtifacts(Case.getCurrentCaseThrows().getSleuthkitCase(), TYPE_WEB_HISTORY, dataSource, TYPE_DATETIME_ACCESSED, DataSourceInfoUtilities.SortOrder.DESCENDING, 0); Long mostRecentMs = null; @@ -358,7 +347,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * @param artifact The artifact. * * @return The TopWebSearchResult or null if the search string or date - * accessed cannot be determined. + * accessed cannot be determined. */ private static TopWebSearchResult getWebSearchResult(BlackboardArtifact artifact) { String searchString = DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_TEXT); @@ -373,16 +362,16 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * term. * * @param dataSource The data source. - * @param count The maximum number of records to be shown (must be > 0). + * @param count The maximum number of records to be shown (must be > + * 0). * * @return The list of most recent web searches where most recent search - * appears first. + * appears first. * - * @throws - * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws NoCurrentCaseException * @throws TskCoreException */ - public List getMostRecentWebSearches(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { + public static List getMostRecentWebSearches(DataSource dataSource, int count) throws NoCurrentCaseException, TskCoreException { assertValidCount(count); if (dataSource == null) { @@ -390,7 +379,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { } // get the artifacts - List webSearchArtifacts = caseProvider.get().getBlackboard() + List webSearchArtifacts = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard() .getArtifacts(ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID(), dataSource.getId()); // group by search string (case insensitive) @@ -417,6 +406,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { .collect(Collectors.toList()); // get translation if possible + TextTranslationService translationService = TextTranslationService.getInstance(); if (translationService.hasProvider()) { for (TopWebSearchResult result : results) { result.setTranslatedResult(getTranslationOrNull(result.getSearchString())); @@ -433,9 +423,10 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * @param original The original text. * * @return The translated text or null if no translation can be determined - * or exists. + * or exists. */ - private String getTranslationOrNull(String original) { + private static String getTranslationOrNull(String original) { + TextTranslationService translationService = TextTranslationService.getInstance(); if (!translationService.hasProvider() || StringUtils.isBlank(original)) { return null; } @@ -443,8 +434,9 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { String translated = null; try { translated = translationService.translate(original); - } catch (NoServiceProviderException | TranslationException ex) { - logger.log(Level.WARNING, String.format("There was an error translating text: '%s'", original), ex); + } catch (NoServiceProviderException | TranslationException ignore) { + // Original logic ignored this error and simply logged it as warning so i'm keeping the same logic + // logger.log(Level.WARNING, String.format("There was an error translating text: '%s'", original), ex); } // if there is no translation or the translation is the same as the original, return null. @@ -463,10 +455,11 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * * @param r1 A result. * @param r2 Another result. + * * @return The most recent one with a non-null date. */ - private TopDeviceAttachedResult getMostRecentDevice(TopDeviceAttachedResult r1, TopDeviceAttachedResult r2) { - if (r2.getLastAccessed()== null) { + private static TopDeviceAttachedResult getMostRecentDevice(TopDeviceAttachedResult r1, TopDeviceAttachedResult r2) { + if (r2.getLastAccessed() == null) { return r1; } @@ -481,23 +474,23 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * Retrieves most recent devices used by most recent date attached. * * @param dataSource The data source. - * @param count The maximum number of records to be shown (must be > 0). + * @param count The maximum number of records to be shown (must be > + * 0). * * @return The list of most recent devices attached where most recent device - * attached appears first. + * attached appears first. * - * @throws - * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws NoCurrentCaseException * @throws TskCoreException */ - public List getRecentDevices(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { + public static List getRecentDevices(DataSource dataSource, int count) throws NoCurrentCaseException, TskCoreException { assertValidCount(count); if (dataSource == null) { return Collections.emptyList(); } - Collection results = DataSourceInfoUtilities.getArtifacts(caseProvider.get(), TYPE_DEVICE_ATTACHED, + Collection results = DataSourceInfoUtilities.getArtifacts(Case.getCurrentCaseThrows().getSleuthkitCase(), TYPE_DEVICE_ATTACHED, dataSource, TYPE_DATETIME, DataSourceInfoUtilities.SortOrder.DESCENDING, 0) .stream() .map(artifact -> { @@ -529,7 +522,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * @param artifact The artifact. * * @return The TopAccountResult or null if the account type or message date - * cannot be determined. + * cannot be determined. */ private static TopAccountResult getMessageAccountResult(BlackboardArtifact artifact) { String type = DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_MESSAGE_TYPE); @@ -543,12 +536,12 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * Obtains a TopAccountResult from a blackboard artifact. The date is * maximum of any found dates for attribute types provided. * - * @param artifact The artifact. + * @param artifact The artifact. * @param messageType The type of message this is. - * @param dateAttrs The date attribute types. + * @param dateAttrs The date attribute types. * * @return The TopAccountResult or null if the account type or max date are - * not provided. + * not provided. */ private static TopAccountResult getAccountResult(BlackboardArtifact artifact, String messageType, BlackboardAttribute.Type... dateAttrs) { String type = messageType; @@ -572,30 +565,30 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * sent. * * @param dataSource The data source. - * @param count The maximum number of records to be shown (must be > 0). + * @param count The maximum number of records to be shown (must be > + * 0). * * @return The list of most recent accounts used where the most recent - * account by last message sent occurs first. + * account by last message sent occurs first. * - * @throws - * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws NoCurrentCaseException * @throws TskCoreException */ @Messages({ "DataSourceUserActivitySummary_getRecentAccounts_emailMessage=Email Message", "DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=Call Log",}) - public List getRecentAccounts(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { + public static List getRecentAccounts(DataSource dataSource, int count) throws NoCurrentCaseException, TskCoreException { assertValidCount(count); if (dataSource == null) { return Collections.emptyList(); } - Stream messageResults = caseProvider.get().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(), dataSource.getId()) + Stream messageResults = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(), dataSource.getId()) .stream() .map((art) -> getMessageAccountResult(art)); - Stream emailResults = caseProvider.get().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(), dataSource.getId()) + Stream emailResults = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(), dataSource.getId()) .stream() .map((art) -> { return getAccountResult( @@ -605,7 +598,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { TYPE_DATETIME_SENT); }); - Stream calllogResults = caseProvider.get().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_CALLLOG.getTypeID(), dataSource.getId()) + Stream calllogResults = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_CALLLOG.getTypeID(), dataSource.getId()) .stream() .map((art) -> { return getAccountResult( @@ -639,39 +632,6 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { .collect(Collectors.toList()); } - /** - * Determines a short folder name if any. Otherwise, returns empty string. - * - * @param strPath The string path. - * @param applicationName The application name. - * - * @return The short folder name or empty string if not found. - */ - public String getShortFolderName(String strPath, String applicationName) { - if (strPath == null) { - return ""; - } - - List pathEls = new ArrayList<>(Arrays.asList(applicationName)); - - File file = new File(strPath); - while (file != null && org.apache.commons.lang.StringUtils.isNotBlank(file.getName())) { - pathEls.add(file.getName()); - file = file.getParentFile(); - } - - Collections.reverse(pathEls); - - for (Function, String> matchEntry : SHORT_FOLDER_MATCHERS) { - String result = matchEntry.apply(pathEls); - if (org.apache.commons.lang.StringUtils.isNotBlank(result)) { - return result; - } - } - - return ""; - } - /** * Creates a TopProgramsResult from a TSK_PROG_RUN blackboard artifact. * @@ -679,7 +639,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * * @return The generated TopProgramsResult. */ - private TopProgramsResult getTopProgramsResult(BlackboardArtifact artifact) { + private static TopProgramsResult getTopProgramsResult(BlackboardArtifact artifact) { String programName = DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_PROG_NAME); // ignore items with no name or a ntos boot identifier @@ -731,7 +691,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * @param long2 Second possibly null long. * * @return Returns the compare value: 1,0,-1 favoring the higher non-null - * value. + * value. */ private static int nullableCompare(Long long1, Long long2) { if (long1 == null && long2 == null) { @@ -765,17 +725,17 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * be ignored and all items will be returned. * * @param dataSource The datasource. If the datasource is null, an empty - * list will be returned. - * @param count The number of results to return. This value must be > 0 or - * an IllegalArgumentException will be thrown. + * list will be returned. + * @param count The number of results to return. This value must be > 0 + * or an IllegalArgumentException will be thrown. * * @return The sorted list and limited to the count if last run or run count - * information is available on any item. + * information is available on any item. * - * @throws SleuthkitCaseProviderException + * @throws NoCurrentCaseException * @throws TskCoreException */ - public List getTopPrograms(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { + public static List getTopPrograms(DataSource dataSource, int count) throws NoCurrentCaseException, TskCoreException { assertValidCount(count); if (dataSource == null) { @@ -783,7 +743,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { } // Get TopProgramsResults for each TSK_PROG_RUN artifact - Collection results = caseProvider.get().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID(), dataSource.getId()) + Collection results = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID(), dataSource.getId()) .stream() // convert to a TopProgramsResult object or null if missing critical information .map((art) -> getTopProgramsResult(art)) @@ -841,7 +801,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * Main constructor. * * @param lastAccessed The date of last access. - * @param artifact The relevant blackboard artifact. + * @param artifact The relevant blackboard artifact. */ public LastAccessedArtifact(Date lastAccessed, BlackboardArtifact artifact) { this.lastAccessed = lastAccessed; @@ -876,7 +836,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * * @param searchString The search string. * @param dateAccessed The latest date searched. - * @param artifact The relevant blackboard artifact. + * @param artifact The relevant blackboard artifact. */ public TopWebSearchResult(String searchString, Date dateAccessed, BlackboardArtifact artifact) { super(dateAccessed, artifact); @@ -919,11 +879,11 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { /** * Main constructor. * - * @param deviceId The device id. + * @param deviceId The device id. * @param dateAccessed The date last attached. - * @param deviceMake The device make. - * @param deviceModel The device model. - * @param artifact The relevant blackboard artifact. + * @param deviceMake The device make. + * @param deviceModel The device model. + * @param artifact The relevant blackboard artifact. */ public TopDeviceAttachedResult(String deviceId, Date dateAccessed, String deviceMake, String deviceModel, BlackboardArtifact artifact) { super(dateAccessed, artifact); @@ -966,8 +926,8 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * Main constructor. * * @param accountType The account type. - * @param lastAccess The date the account was last accessed. - * @param artifact The artifact indicating last access. + * @param lastAccess The date the account was last accessed. + * @param artifact The artifact indicating last access. */ public TopAccountResult(String accountType, Date lastAccess, BlackboardArtifact artifact) { super(lastAccess, artifact); @@ -993,10 +953,10 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { /** * Describes a top domain result. * - * @param domain The domain. + * @param domain The domain. * @param visitTimes The number of times it was visited. - * @param lastVisit The date of the last visit. - * @param artifact The relevant blackboard artifact. + * @param lastVisit The date of the last visit. + * @param artifact The relevant blackboard artifact. */ public TopDomainsResult(String domain, Long visitTimes, Date lastVisit, BlackboardArtifact artifact) { super(lastVisit, artifact); @@ -1033,8 +993,8 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor { * * @param programName The name of the program. * @param programPath The path of the program. - * @param runTimes The number of runs. - * @param artifact The relevant blackboard artifact. + * @param runTimes The number of runs. + * @param artifact The relevant blackboard artifact. */ TopProgramsResult(String programName, String programPath, Long runTimes, Date lastRun, BlackboardArtifact artifact) { super(lastRun, artifact); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryGetter.java new file mode 100644 index 0000000000..73ac071470 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryGetter.java @@ -0,0 +1,237 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020-2021 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.datasourcesummary.datamodel; + +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopAccountResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDeviceAttachedResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDomainsResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopProgramsResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopWebSearchResult; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; + +/** + * Wrapper class for converting + * org.sleuthkit.autopsy.contentutils.UserActivitySummary functionality into a + * DefaultArtifactUpdateGovernor used by UserActivityPanel tab. + */ +public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor { + + private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( + ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID(), + ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(), + ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(), + ARTIFACT_TYPE.TSK_CALLLOG.getTypeID(), + ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID(), + ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID(), + ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID() + )); + + public UserActivitySummaryGetter() { + } + + @Override + public Set getArtifactTypeIdsForRefresh() { + return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS); + } + + /** + * Throws an IllegalArgumentException if count <= 0. + * + * @param count The count being checked. + */ + private void assertValidCount(int count) { + if (count <= 0) { + throw new IllegalArgumentException("Count must be greater than 0"); + } + } + + /** + * Gets a list of recent domains based on the datasource. + * + * @param dataSource The datasource to query for recent domains. + * @param count The max count of items to return. + * + * @return The list of items retrieved from the database. + * + * @throws InterruptedException + */ + public List getRecentDomains(DataSource dataSource, int count) throws TskCoreException, SleuthkitCaseProviderException { + assertValidCount(count); + + if (dataSource == null) { + return Collections.emptyList(); + } + + try { + return UserActivitySummary.getRecentDomains(dataSource, count); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } + + /** + * Retrieves most recent web searches by most recent date grouped by search + * term. + * + * @param dataSource The data source. + * @param count The maximum number of records to be shown (must be > + * 0). + * + * @return The list of most recent web searches where most recent search + * appears first. + * + * @throws + * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws TskCoreException + */ + public List getMostRecentWebSearches(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { + assertValidCount(count); + + if (dataSource == null) { + return Collections.emptyList(); + } + + try { + return UserActivitySummary.getMostRecentWebSearches(dataSource, count); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } + + /** + * Retrieves most recent devices used by most recent date attached. + * + * @param dataSource The data source. + * @param count The maximum number of records to be shown (must be > + * 0). + * + * @return The list of most recent devices attached where most recent device + * attached appears first. + * + * @throws + * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws TskCoreException + */ + public List getRecentDevices(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { + assertValidCount(count); + + if (dataSource == null) { + return Collections.emptyList(); + } + + try { + return UserActivitySummary.getRecentDevices(dataSource, count); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } + + /** + * Retrieves most recent account used by most recent date for a message + * sent. + * + * @param dataSource The data source. + * @param count The maximum number of records to be shown (must be > + * 0). + * + * @return The list of most recent accounts used where the most recent + * account by last message sent occurs first. + * + * @throws + * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws TskCoreException + */ + @Messages({ + "DataSourceUserActivitySummary_getRecentAccounts_emailMessage=Email Message", + "DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=Call Log",}) + public List getRecentAccounts(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { + assertValidCount(count); + + if (dataSource == null) { + return Collections.emptyList(); + } + + try { + return UserActivitySummary.getRecentAccounts(dataSource, count); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } + + /** + * Determines a short folder name if any. Otherwise, returns empty string. + * + * @param strPath The string path. + * @param applicationName The application name. + * + * @return The short folder name or empty string if not found. + */ + public String getShortFolderName(String strPath, String applicationName) { + if (strPath == null) { + return ""; + } + + return UserActivitySummary.getShortFolderName(strPath, applicationName); + } + + /** + * Retrieves the top programs results for the given data source limited to + * the count provided as a parameter. The highest run times are at the top + * of the list. If that information isn't available the last run date is + * used. If both, the last run date and the number of run times are + * unavailable, the programs will be sorted alphabetically, the count will + * be ignored and all items will be returned. + * + * @param dataSource The datasource. If the datasource is null, an empty + * list will be returned. + * @param count The number of results to return. This value must be > 0 + * or an IllegalArgumentException will be thrown. + * + * @return The sorted list and limited to the count if last run or run count + * information is available on any item. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + */ + public List getTopPrograms(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { + assertValidCount(count); + + if (dataSource == null) { + return Collections.emptyList(); + } + + try { + return UserActivitySummary.getTopPrograms(dataSource, count); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index 2d58c09742..c6d13260b9 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -28,13 +28,13 @@ import java.util.Locale; import java.util.function.Function; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.LastAccessedArtifact; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopAccountResult; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDeviceAttachedResult; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopWebSearchResult; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopProgramsResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.LastAccessedArtifact; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopAccountResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDeviceAttachedResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDomainsResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopProgramsResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopWebSearchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; @@ -261,22 +261,22 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel(); private final List> dataFetchComponents; - private final UserActivitySummary userActivityData; + private final UserActivitySummaryGetter userActivityData; /** * Creates a new UserActivityPanel. */ public UserActivityPanel() { - this(new UserActivitySummary()); + this(new UserActivitySummaryGetter()); } /** * Creates a new UserActivityPanel. * * @param userActivityData Class from which to obtain remaining user - * activity data. + * activity data. */ - public UserActivityPanel(UserActivitySummary userActivityData) { + public UserActivityPanel(UserActivitySummaryGetter userActivityData) { super(userActivityData); this.userActivityData = userActivityData; @@ -328,7 +328,8 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { * @param record The LastAccessedArtifact instance. * * @return The menu items list containing one action or navigating to the - * appropriate artifact and closing the data source summary dialog if open. + * appropriate artifact and closing the data source summary dialog + * if open. */ private List getPopup(LastAccessedArtifact record) { return record == null ? null : Arrays.asList(getArtifactNavigateItem(record.getArtifact())); @@ -337,7 +338,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { /** * Queries DataSourceTopProgramsSummary instance for short folder name. * - * @param path The path for the application. + * @param path The path for the application. * @param appName The application name. * * @return The underlying short folder name if one exists. @@ -362,19 +363,6 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { super.close(); } - /* ELTODO - @Override - List getExports(DataSource dataSource) { - return Stream.of( - getTableExport(topProgramsFetcher, topProgramsTemplate, Bundle.UserActivityPanel_TopProgramsTableModel_tabName(), dataSource), - getTableExport(topDomainsFetcher, topDomainsTemplate, Bundle.UserActivityPanel_TopDomainsTableModel_tabName(), dataSource), - getTableExport(topWebSearchesFetcher, topWebSearchesTemplate, Bundle.UserActivityPanel_TopWebSearchTableModel_tabName(), dataSource), - getTableExport(topDevicesAttachedFetcher, topDevicesTemplate, Bundle.UserActivityPanel_TopDeviceAttachedTableModel_tabName(), dataSource), - getTableExport(topAccountsFetcher, topAccountsTemplate, Bundle.UserActivityPanel_TopAccountTableModel_tabName(), dataSource)) - .filter(sheet -> sheet != null) - .collect(Collectors.toList()); - }*/ - /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index a0c9bb1d6e..d6ca349440 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -7,8 +7,10 @@ ExcelExportAction_exportToXLSX_beginExport=Beginning Export... ExcelExportAction_exportToXLSX_gatheringAnalysisData=Fetching Analysis Data ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data ExcelExportAction_exportToXLSX_gatheringFileData=Fetching File and MIME Type Data +ExcelExportAction_exportToXLSX_gatheringPastData=Fetching Historical Data ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data +ExcelExportAction_exportToXLSX_gatheringUserData=Fetching User Activity Data ExcelExportAction_exportToXLSX_writingToFile=Writing to File... ExcelExportAction_getXLSXPath_directory=DataSourceSummary ExcelExportAction_moduleName=Data Source Summary @@ -36,7 +38,6 @@ ExportContainerInfo_tabName=Container ExportPastCases_caseColumn_title=Case ExportPastCases_countColumn_title=Count ExportPastCases_notableFileTable_tabName=Cases with Common Notable -ExportPastCases_onNoCrIngest_message=No results will be shown because the Central Repository module was not run. ExportPastCases_sameIdsTable_tabName=Past Cases with the Same Devices ExportRecentFiles_attachmentsTable_tabName=Recent Attachments ExportRecentFiles_col_head_date=Date @@ -64,6 +65,28 @@ ExportTypes_filesByCategoryTable_unallocatedRow_title=Unallocated Files ExportTypes_osLabel_title=OS ExportTypes_sizeLabel_title=Size ExportTypes_usageLabel_title=Usage +ExportUserActivity_noDataExists=No communication data exists +ExportUserActivity_tab_title=User Activity +ExportUserActivity_TopAccountTableModel_accountType_header=Account Type +ExportUserActivity_TopAccountTableModel_lastAccess_header=Last Accessed +ExportUserActivity_TopAccountTableModel_tabName=Recent Account Types Used +ExportUserActivity_TopDeviceAttachedTableModel_dateAccessed_header=Last Accessed +ExportUserActivity_TopDeviceAttachedTableModel_deviceId_header=Device Id +ExportUserActivity_TopDeviceAttachedTableModel_makeModel_header=Make and Model +ExportUserActivity_TopDeviceAttachedTableModel_tabName=Recent Devices Attached +ExportUserActivity_TopDomainsTableModel_count_header=Visits +ExportUserActivity_TopDomainsTableModel_domain_header=Domain +ExportUserActivity_TopDomainsTableModel_lastAccess_header=Last Accessed +ExportUserActivity_TopDomainsTableModel_tabName=Recent Domains +ExportUserActivity_TopProgramsTableModel_count_header=Run Times +ExportUserActivity_TopProgramsTableModel_folder_header=Folder +ExportUserActivity_TopProgramsTableModel_lastrun_header=Last Run +ExportUserActivity_TopProgramsTableModel_name_header=Program +ExportUserActivity_TopProgramsTableModel_tabName=Recent Programs +ExportUserActivity_TopWebSearchTableModel_dateAccessed_header=Date Accessed +ExportUserActivity_TopWebSearchTableModel_searchString_header=Search String +ExportUserActivity_TopWebSearchTableModel_tabName=Recent Web Searches +ExportUserActivity_TopWebSearchTableModel_translatedResult_header=Translated SizeRepresentationUtil_units_bytes=bytes SizeRepresentationUtil_units_gigabytes=GB SizeRepresentationUtil_units_kilobytes=KB diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index 50dd05a18c..44879e741f 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -98,6 +98,7 @@ class ExcelExportAction { "ExcelExportAction_exportToXLSX_gatheringFileData=Fetching File and MIME Type Data", "ExcelExportAction_exportToXLSX_gatheringAnalysisData=Fetching Analysis Data", "ExcelExportAction_exportToXLSX_gatheringPastData=Fetching Historical Data", + "ExcelExportAction_exportToXLSX_gatheringUserData=Fetching User Activity Data", "ExcelExportAction_exportToXLSX_writingToFile=Writing to File...",}) void exportToXLSX(ReportProgressPanel progressPanel, DataSource dataSource, String baseReportDir) @@ -157,7 +158,15 @@ class ExcelExportAction { if (exports != null) { sheetExports.addAll(exports); } - + + // Export user activity + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringUserData()); + progressPanel.setProgress(6); + exports = ExportUserActivity.getExports(dataSource); + if (exports != null) { + sheetExports.addAll(exports); + } + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_writingToFile()); progressPanel.setProgress(9); ExcelExport.writeExcel(sheetExports, reportFile); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java new file mode 100755 index 0000000000..c89c4f996a --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java @@ -0,0 +1,248 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.report.modules.datasourcesummaryexport; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.lang.StringUtils; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.LastAccessedArtifact; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopAccountResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDeviceAttachedResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDomainsResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopProgramsResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopWebSearchResult; +import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getTableExport; + +/** + * A panel to display user activity. + */ +@Messages({ + "ExportUserActivity_tab_title=User Activity", + "ExportUserActivity_TopProgramsTableModel_tabName=Recent Programs", + "ExportUserActivity_TopDomainsTableModel_tabName=Recent Domains", + "ExportUserActivity_TopWebSearchTableModel_tabName=Recent Web Searches", + "ExportUserActivity_TopDeviceAttachedTableModel_tabName=Recent Devices Attached", + "ExportUserActivity_TopAccountTableModel_tabName=Recent Account Types Used", + "ExportUserActivity_TopProgramsTableModel_name_header=Program", + "ExportUserActivity_TopProgramsTableModel_folder_header=Folder", + "ExportUserActivity_TopProgramsTableModel_count_header=Run Times", + "ExportUserActivity_TopProgramsTableModel_lastrun_header=Last Run", + "ExportUserActivity_TopDomainsTableModel_domain_header=Domain", + "ExportUserActivity_TopDomainsTableModel_count_header=Visits", + "ExportUserActivity_TopDomainsTableModel_lastAccess_header=Last Accessed", + "ExportUserActivity_TopWebSearchTableModel_searchString_header=Search String", + "ExportUserActivity_TopWebSearchTableModel_dateAccessed_header=Date Accessed", + "ExportUserActivity_TopWebSearchTableModel_translatedResult_header=Translated", + "ExportUserActivity_TopDeviceAttachedTableModel_deviceId_header=Device Id", + "ExportUserActivity_TopDeviceAttachedTableModel_makeModel_header=Make and Model", + "ExportUserActivity_TopDeviceAttachedTableModel_dateAccessed_header=Last Accessed", + "ExportUserActivity_TopAccountTableModel_accountType_header=Account Type", + "ExportUserActivity_TopAccountTableModel_lastAccess_header=Last Accessed", + "ExportUserActivity_noDataExists=No communication data exists"}) +class ExportUserActivity { + + private static final String DATETIME_FORMAT_STR = "yyyy/MM/dd HH:mm:ss"; + private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat(DATETIME_FORMAT_STR, Locale.getDefault()); + private static final int TOP_PROGS_COUNT = 10; + private static final int TOP_DOMAINS_COUNT = 10; + private static final int TOP_SEARCHES_COUNT = 10; + private static final int TOP_ACCOUNTS_COUNT = 5; + private static final int TOP_DEVICES_COUNT = 10; + + // set up recent programs + private static final List>> topProgramsTemplate = Arrays.asList( + // program name column + new ColumnModel<>( + Bundle.ExportUserActivity_TopProgramsTableModel_name_header(), + (prog) -> { + return new DefaultCellModel<>(prog.getProgramName()); + }, + 250), + // program folder column + new ColumnModel<>( + Bundle.ExportUserActivity_TopProgramsTableModel_folder_header(), + (prog) -> { + return new DefaultCellModel<>( + getShortFolderName( + prog.getProgramPath(), + prog.getProgramName())); + }, + 150), + // run count column + new ColumnModel<>( + Bundle.ExportUserActivity_TopProgramsTableModel_count_header(), + (prog) -> { + return new DefaultCellModel<>(prog.getRunTimes(), (num) -> num == null ? "" : num.toString()); + }, + 80), + // last run date column + new ColumnModel<>( + Bundle.ExportUserActivity_TopProgramsTableModel_lastrun_header(), + getDateFunct(), + 150) + ); + + // set up recent domains + private static final List>> topDomainsTemplate = Arrays.asList( + // domain column + new ColumnModel<>( + Bundle.ExportUserActivity_TopDomainsTableModel_domain_header(), + (recentDomain) -> { + return new DefaultCellModel<>(recentDomain.getDomain()); + }, + 250), + // count column + new ColumnModel<>( + Bundle.ExportUserActivity_TopDomainsTableModel_count_header(), + (recentDomain) -> { + return new DefaultCellModel<>(recentDomain.getVisitTimes(), (num) -> num == null ? "" : num.toString()); + }, + 100), + // last accessed column + new ColumnModel<>( + Bundle.ExportUserActivity_TopDomainsTableModel_lastAccess_header(), + getDateFunct(), + 150) + ); + + // top web searches + private static final List>> topWebSearchesTemplate = Arrays.asList( + // search string column + new ColumnModel<>( + Bundle.ExportUserActivity_TopWebSearchTableModel_searchString_header(), + (webSearch) -> { + return new DefaultCellModel<>(webSearch.getSearchString()); + }, + 250 + ), + // last accessed + new ColumnModel<>( + Bundle.ExportUserActivity_TopWebSearchTableModel_dateAccessed_header(), + getDateFunct(), + 150 + ), + // translated value + new ColumnModel<>( + Bundle.ExportUserActivity_TopWebSearchTableModel_translatedResult_header(), + (webSearch) -> { + return new DefaultCellModel<>(webSearch.getTranslatedResult()); + }, + 250 + ) + ); + + // top devices attached + private static final List>> topDevicesTemplate = Arrays.asList( + // device id column + new ColumnModel<>( + Bundle.ExportUserActivity_TopDeviceAttachedTableModel_deviceId_header(), + (device) -> { + return new DefaultCellModel<>(device.getDeviceId()); + }, + 250 + ), + // last accessed + new ColumnModel<>( + Bundle.ExportUserActivity_TopDeviceAttachedTableModel_dateAccessed_header(), + getDateFunct(), + 150 + ), + // make and model + new ColumnModel<>( + Bundle.ExportUserActivity_TopDeviceAttachedTableModel_makeModel_header(), + (device) -> { + String make = StringUtils.isBlank(device.getDeviceMake()) ? "" : device.getDeviceMake().trim(); + String model = StringUtils.isBlank(device.getDeviceModel()) ? "" : device.getDeviceModel().trim(); + String makeModelString = (make.isEmpty() || model.isEmpty()) + ? make + model + : String.format("%s - %s", make, model); + return new DefaultCellModel<>(makeModelString); + }, + 250 + ) + ); + + // top accounts + private static final List>> topAccountsTemplate = Arrays.asList( + // account type column + new ColumnModel<>( + Bundle.ExportUserActivity_TopAccountTableModel_accountType_header(), + (account) -> { + return new DefaultCellModel<>(account.getAccountType()); + }, + 250 + ), + // last accessed + new ColumnModel<>( + Bundle.ExportUserActivity_TopAccountTableModel_lastAccess_header(), + getDateFunct(), + 150 + ) + ); + + private ExportUserActivity() { + } + + private static Function> getDateFunct() { + return (T lastAccessed) -> { + Function dateParser = (dt) -> dt == null ? "" : DATETIME_FORMAT.format(dt); + return new DefaultCellModel<>(lastAccessed.getLastAccessed(), dateParser, DATETIME_FORMAT_STR); + }; + } + + /** + * Queries DataSourceTopProgramsSummary instance for short folder name. + * + * @param path The path for the application. + * @param appName The application name. + * + * @return The underlying short folder name if one exists. + */ + private static String getShortFolderName(String path, String appName) { + return UserActivitySummary.getShortFolderName(path, appName); + } + + static List getExports(DataSource dataSource) { + + DataFetcher> topProgramsFetcher = (ds) -> UserActivitySummary.getTopPrograms(ds, TOP_PROGS_COUNT); + DataFetcher> topDomainsFetcher = (ds) -> UserActivitySummary.getRecentDomains(ds, TOP_DOMAINS_COUNT); + DataFetcher> topWebSearchesFetcher = (ds) -> UserActivitySummary.getMostRecentWebSearches(ds, TOP_SEARCHES_COUNT); + DataFetcher> topDevicesAttachedFetcher = (ds) -> UserActivitySummary.getRecentDevices(ds, TOP_DEVICES_COUNT); + DataFetcher> topAccountsFetcher = (ds) -> UserActivitySummary.getRecentAccounts(ds, TOP_ACCOUNTS_COUNT); + + return Stream.of( + getTableExport(topProgramsFetcher, topProgramsTemplate, Bundle.ExportUserActivity_TopProgramsTableModel_tabName(), dataSource), + getTableExport(topDomainsFetcher, topDomainsTemplate, Bundle.ExportUserActivity_TopDomainsTableModel_tabName(), dataSource), + getTableExport(topWebSearchesFetcher, topWebSearchesTemplate, Bundle.ExportUserActivity_TopWebSearchTableModel_tabName(), dataSource), + getTableExport(topDevicesAttachedFetcher, topDevicesTemplate, Bundle.ExportUserActivity_TopDeviceAttachedTableModel_tabName(), dataSource), + getTableExport(topAccountsFetcher, topAccountsTemplate, Bundle.ExportUserActivity_TopAccountTableModel_tabName(), dataSource)) + .filter(sheet -> sheet != null) + .collect(Collectors.toList()); + } +} diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java index 14455b27c9..10c42eebbb 100644 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java @@ -26,8 +26,8 @@ import java.util.stream.Collectors; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter.TopDomainsResult; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; @@ -36,14 +36,14 @@ import org.sleuthkit.autopsy.integrationtesting.IntegrationTest; import org.sleuthkit.autopsy.integrationtesting.IntegrationTestGroup; /** - * Tests for the UserActivitySummary class. + * Tests for the UserActivitySummaryGetter class. */ @ServiceProvider(service = IntegrationTestGroup.class) public class UserActivitySummaryTests implements IntegrationTestGroup { /** - * Runs UserActivitySummary.getRecentDomains for all data sources found in - * the current case. + * Runs UserActivitySummaryGetter.getRecentDomains for all data sources found in + the current case. * * @return A map where the key is the data source name and the value are the * results of that method. @@ -52,7 +52,7 @@ public class UserActivitySummaryTests implements IntegrationTestGroup { public Map>> getRecentDomainsTest() throws NoCurrentCaseException, TskCoreException, SleuthkitCaseProviderException { - UserActivitySummary userActivitySummary = new UserActivitySummary(); + UserActivitySummaryGetter userActivitySummary = new UserActivitySummaryGetter(); Map>> toRet = new HashMap<>(); for (Content c : Case.getCurrentCaseThrows().getDataSources()) { if (c instanceof DataSource) { diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java index 2b6a1c6600..216b1b99c5 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java @@ -44,11 +44,11 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceSummaryMockUtils.getArtifactsTSKMock; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopAccountResult; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDeviceAttachedResult; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopProgramsResult; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopWebSearchResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter.TopAccountResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter.TopDeviceAttachedResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter.TopDomainsResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter.TopProgramsResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter.TopWebSearchResult; import org.sleuthkit.autopsy.testutils.TskMockUtils; import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException; import org.sleuthkit.autopsy.texttranslation.TextTranslationService; @@ -63,27 +63,27 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; /** - * Tests for UserActivitySummary. + * Tests for UserActivitySummaryGetter. */ public class UserActivitySummaryTest { /** - * Function to retrieve data from UserActivitySummary with the provided - * arguments. + * Function to retrieve data from UserActivitySummaryGetter with the provided + arguments. */ private interface DataFunction { /** - * A UserActivitySummary method encapsulated in a uniform manner. + * A UserActivitySummaryGetter method encapsulated in a uniform manner. * - * @param userActivitySummary The UserActivitySummary class to use. + * @param userActivitySummary The UserActivitySummaryGetter class to use. * @param datasource The data source. * @param count The count. * @return The list of objects to return. * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - List retrieve(UserActivitySummary userActivitySummary, DataSource datasource, int count) throws + List retrieve(UserActivitySummaryGetter userActivitySummary, DataSource datasource, int count) throws SleuthkitCaseProviderException, TskCoreException; } @@ -119,21 +119,21 @@ public class UserActivitySummaryTest { } /** - * Gets a UserActivitySummary class to test. + * Gets a UserActivitySummaryGetter class to test. * * @param tskCase The SleuthkitCase. * @param hasTranslation Whether the translation service is functional. * @param translateFunction Function for translation. * - * @return The UserActivitySummary class to use for testing. + * @return The UserActivitySummaryGetter class to use for testing. * * @throws NoServiceProviderException * @throws TranslationException */ - private static UserActivitySummary getTestClass(SleuthkitCase tskCase, boolean hasTranslation, Function translateFunction) + private static UserActivitySummaryGetter getTestClass(SleuthkitCase tskCase, boolean hasTranslation, Function translateFunction) throws NoServiceProviderException, TranslationException { - return new UserActivitySummary( + return new UserActivitySummaryGetter( () -> tskCase, TskMockUtils.getTextTranslationService(translateFunction, hasTranslation), TskMockUtils.getJavaLogger("UNIT TEST LOGGER") @@ -145,7 +145,7 @@ public class UserActivitySummaryTest { for (int count : new int[]{0, -1}) { Pair tskPair = getArtifactsTSKMock(null); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); try { funct.retrieve(summary, TskMockUtils.getDataSource(1), -1); @@ -183,7 +183,7 @@ public class UserActivitySummaryTest { throws TskCoreException, NoServiceProviderException, TranslationException, SleuthkitCaseProviderException { Pair tskPair = getArtifactsTSKMock(null); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List retArr = funct.retrieve(summary, null, 10); verify(tskPair.getRight(), never() .description(String.format("Expected method %s to return empty list for null data source and not call SleuthkitCase", id))) @@ -216,7 +216,7 @@ public class UserActivitySummaryTest { long dataSourceId = 1; int count = 10; Pair tskPair = getArtifactsTSKMock(new ArrayList<>()); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List retArr = funct.retrieve(summary, TskMockUtils.getDataSource(dataSourceId), count); Assert.assertTrue(String.format("Expected non null empty list returned from %s", id), retArr != null); @@ -290,7 +290,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); Pair tskPair = getArtifactsTSKMock(artifacts); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getRecentDevices(ds, count); @@ -304,8 +304,8 @@ public class UserActivitySummaryTest { } /** - * Ensures that UserActivitySummary.getRecentDevices limits returned entries - * to count provided. + * Ensures that UserActivitySummaryGetter.getRecentDevices limits returned entries + to count provided. * * @throws TskCoreException * @throws NoServiceProviderException @@ -327,7 +327,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); Pair tskPair = getArtifactsTSKMock(returnedArtifacts); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getRecentDevices(dataSource, countRequested); verifyCalled(tskPair.getRight(), ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID(), dataSourceId, @@ -348,7 +348,7 @@ public class UserActivitySummaryTest { BlackboardArtifact item3 = getRecentDeviceArtifact(1003, dataSource, "ID1", "MAKE1", "MODEL1", DAY_SECONDS + 2); Pair tskPair = getArtifactsTSKMock(Arrays.asList(item1, item2, item3)); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getRecentDevices(dataSource, 10); @@ -396,7 +396,7 @@ public class UserActivitySummaryTest { List artList = Arrays.asList(art1a, art2a, art2b, art1b, art1c); Pair tskPair = getArtifactsTSKMock(artList); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getMostRecentWebSearches(ds, 10); verifyCalled(tskPair.getRight(), ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID(), dataSourceId, "Expected getRecentDevices to call getArtifacts with correct arguments."); @@ -433,7 +433,7 @@ public class UserActivitySummaryTest { // set up a mock TextTranslationService returning a translation TextTranslationService translationService = TskMockUtils.getTextTranslationService(translator, hasProvider); - UserActivitySummary summary = new UserActivitySummary( + UserActivitySummaryGetter summary = new UserActivitySummaryGetter( () -> tskPair.getLeft(), translationService, TskMockUtils.getJavaLogger("UNIT TEST LOGGER") @@ -473,8 +473,8 @@ public class UserActivitySummaryTest { } /** - * Verify that UserActivitySummary.getMostRecentWebSearches handles - * translation appropriately. + * Verify that UserActivitySummaryGetter.getMostRecentWebSearches handles + translation appropriately. * * @throws SleuthkitCaseProviderException * @throws TskCoreException @@ -502,8 +502,8 @@ public class UserActivitySummaryTest { } /** - * Ensure that UserActivitySummary.getMostRecentWebSearches results limited - * to count. + * Ensure that UserActivitySummaryGetter.getMostRecentWebSearches results limited + to count. * * @throws TskCoreException * @throws NoServiceProviderException @@ -525,7 +525,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); Pair tskPair = getArtifactsTSKMock(returnedArtifacts); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getMostRecentWebSearches(dataSource, countRequested); verifyCalled(tskPair.getRight(), ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID(), dataSourceId, @@ -558,8 +558,8 @@ public class UserActivitySummaryTest { private static final long DOMAIN_WINDOW_DAYS = 30; /** - * UserActivitySummary.getRecentDomains should return results within 30 days - * of the most recent access. + * UserActivitySummaryGetter.getRecentDomains should return results within 30 days + of the most recent access. * * @throws TskCoreException * @throws SleuthkitCaseProviderException @@ -589,7 +589,7 @@ public class UserActivitySummaryTest { Pair tskPair = getArtifactsTSKMock(retArr); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List domains = summary.getRecentDomains(dataSource, 10); @@ -633,7 +633,7 @@ public class UserActivitySummaryTest { Pair tskPair = getArtifactsTSKMock(retArr); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List domains = summary.getRecentDomains(dataSource, 10); @@ -670,7 +670,7 @@ public class UserActivitySummaryTest { List retArr = Arrays.asList(artifact1, artifact1a, artifact2, artifact2a, artifact2b); Pair tskPair = getArtifactsTSKMock(retArr); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List domains = summary.getRecentDomains(dataSource, 10); @@ -689,8 +689,8 @@ public class UserActivitySummaryTest { } /** - * Ensure that UserActivitySummary.getRecentDomains limits to count - * appropriately. + * Ensure that UserActivitySummaryGetter.getRecentDomains limits to count + appropriately. * * @throws TskCoreException * @throws NoServiceProviderException @@ -719,7 +719,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); Pair tskPair = getArtifactsTSKMock(returnedArtifacts); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getRecentDomains(dataSource, countRequested); verifyCalled(tskPair.getRight(), ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID(), dataSourceId, @@ -818,7 +818,7 @@ public class UserActivitySummaryTest { } /** - * Performs a test on UserActivitySummary.getRecentAccounts. + * Performs a test on UserActivitySummaryGetter.getRecentAccounts. * * @param dataSource The datasource to use as parameter. * @param count The count to use as a parameter. @@ -849,7 +849,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); }); - UserActivitySummary summary = getTestClass(mockCase, false, null); + UserActivitySummaryGetter summary = getTestClass(mockCase, false, null); List receivedResults = summary.getRecentAccounts(dataSource, count); @@ -880,8 +880,8 @@ public class UserActivitySummaryTest { } /** - * Verify that UserActivitySummary.getRecentAccounts attempts to find a date - * but if none present, the artifact is excluded. + * Verify that UserActivitySummaryGetter.getRecentAccounts attempts to find a date + but if none present, the artifact is excluded. * * @throws TskCoreException * @throws NoServiceProviderException @@ -950,8 +950,8 @@ public class UserActivitySummaryTest { } /** - * Verifies that UserActivitySummary.getRecentAccounts groups appropriately - * by account type. + * Verifies that UserActivitySummaryGetter.getRecentAccounts groups appropriately + by account type. * * @throws TskCoreException * @throws NoServiceProviderException @@ -986,8 +986,8 @@ public class UserActivitySummaryTest { } /** - * Verifies that UserActivitySummary.getRecentAccounts properly limits - * results returned. + * Verifies that UserActivitySummaryGetter.getRecentAccounts properly limits + results returned. * * @throws TskCoreException * @throws NoServiceProviderException @@ -1007,7 +1007,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); Pair tskPair = getArtifactsTSKMock(returnedArtifacts); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getRecentAccounts(dataSource, countRequested); verifyCalled(tskPair.getRight(), ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(), dataSource.getId(), @@ -1044,7 +1044,7 @@ public class UserActivitySummaryTest { expected.put("/Other Path/Item/Item.exe", ""); Pair tskPair = getArtifactsTSKMock(null); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); for (Entry path : expected.entrySet()) { Assert.assertTrue(path.getValue().equalsIgnoreCase(summary.getShortFolderName(path.getKey(), "Item.exe"))); @@ -1112,7 +1112,7 @@ public class UserActivitySummaryTest { successful, successful2 )); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getTopPrograms(ds1, 10); Assert.assertEquals(2, results.size()); @@ -1150,7 +1150,7 @@ public class UserActivitySummaryTest { prog2, prog2a, prog2b, prog3, prog3a, prog3b )); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getTopPrograms(ds1, 10); Assert.assertEquals(3, results.size()); @@ -1174,7 +1174,7 @@ public class UserActivitySummaryTest { throws TskCoreException, NoServiceProviderException, TranslationException, SleuthkitCaseProviderException { Pair tskPair = getArtifactsTSKMock(artifacts); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getTopPrograms(ds1, 10); Assert.assertEquals(programNamesReturned.size(), results.size()); @@ -1184,8 +1184,8 @@ public class UserActivitySummaryTest { } /** - * Ensure that UserActivitySummary.getTopPrograms properly orders results - * (first by run count, then date, then program name). + * Ensure that UserActivitySummaryGetter.getTopPrograms properly orders results + (first by run count, then date, then program name). * * @throws TskCoreException * @throws NoServiceProviderException @@ -1214,8 +1214,8 @@ public class UserActivitySummaryTest { } /** - * Ensure that UserActivitySummary.getTopPrograms properly limits results - * (if no run count and no run date, then no limit). + * Ensure that UserActivitySummaryGetter.getTopPrograms properly limits results + (if no run count and no run date, then no limit). * * @throws TskCoreException * @throws NoServiceProviderException @@ -1239,7 +1239,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); Pair tskPair = getArtifactsTSKMock(returnedArtifacts); - UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getTopPrograms(dataSource, countRequested); verifyCalled(tskPair.getRight(), ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID(), dataSourceId, @@ -1253,7 +1253,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); Pair tskPairAlphabetical = getArtifactsTSKMock(returnedArtifactsAlphabetical); - UserActivitySummary summaryAlphabetical = getTestClass(tskPairAlphabetical.getLeft(), false, null); + UserActivitySummaryGetter summaryAlphabetical = getTestClass(tskPairAlphabetical.getLeft(), false, null); List resultsAlphabetical = summaryAlphabetical.getTopPrograms(dataSource, countRequested); verifyCalled(tskPairAlphabetical.getRight(), ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID(), dataSourceId, From f36c6913a1dd569325aa70d504597bc6c375bc12 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Tue, 10 Aug 2021 12:11:37 -0400 Subject: [PATCH 23/76] Refactored GeolocationTab --- .../CityRecord.java | 4 +- .../ClosestCityMapper.java | 56 +++-- .../GeolocationSummary.java | 145 ++++++------ .../datamodel => contentutils}/LatLngMap.java | 15 +- .../worldcities.csv | 0 .../datamodel/GeolocationSummaryGetter.java | 81 +++++++ .../ui/GeolocationPanel.java | 58 ++--- .../Bundle.properties-MERGED | 6 + .../ExcelExportAction.java | 9 + .../ExportGeolocation.java | 223 ++++++++++++++++++ .../ExportUserActivity.java | 2 +- .../UserActivitySummaryTests.java | 2 +- .../datamodel/UserActivitySummaryTest.java | 22 +- 13 files changed, 463 insertions(+), 160 deletions(-) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/datamodel => contentutils}/CityRecord.java (96%) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/datamodel => contentutils}/ClosestCityMapper.java (84%) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/datamodel => contentutils}/GeolocationSummary.java (81%) mode change 100644 => 100755 rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/datamodel => contentutils}/LatLngMap.java (95%) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/datamodel => contentutils}/worldcities.csv (100%) create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummaryGetter.java create mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/CityRecord.java b/Core/src/org/sleuthkit/autopsy/contentutils/CityRecord.java similarity index 96% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/CityRecord.java rename to Core/src/org/sleuthkit/autopsy/contentutils/CityRecord.java index d2a1182e6a..562fc1758d 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/CityRecord.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/CityRecord.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.contentutils; import java.util.Objects; import org.sleuthkit.autopsy.geolocation.KdTree; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ClosestCityMapper.java b/Core/src/org/sleuthkit/autopsy/contentutils/ClosestCityMapper.java similarity index 84% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ClosestCityMapper.java rename to Core/src/org/sleuthkit/autopsy/contentutils/ClosestCityMapper.java index 4427d25f23..3e39852c79 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ClosestCityMapper.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/ClosestCityMapper.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.contentutils; import java.io.BufferedReader; import java.io.IOException; @@ -60,10 +60,14 @@ class ClosestCityMapper { // singleton instance of this class private static ClosestCityMapper instance = null; + // the logger + private static final java.util.logging.Logger logger = Logger.getLogger(ClosestCityMapper.class.getName()); + /** * Retrieves singleton instance of this class. * * @return The singleton instance of this class. + * * @throws IOException */ static ClosestCityMapper getInstance() throws IOException { @@ -75,10 +79,7 @@ class ClosestCityMapper { } // data structure housing cities - private LatLngMap latLngMap = null; - - // the logger - private final java.util.logging.Logger logger; + private static LatLngMap latLngMap = null; /** * Main Constructor. @@ -86,21 +87,19 @@ class ClosestCityMapper { * @throws IOException */ private ClosestCityMapper() throws IOException { - this( - GeolocationSummary.class.getResourceAsStream(CITIES_CSV_FILENAME), - Logger.getLogger(ClosestCityMapper.class.getName())); + this(ClosestCityMapper.class.getResourceAsStream(CITIES_CSV_FILENAME)); } /** * Main Constructor loading from an input stream. * * @param citiesInputStream The input stream for the csv text file - * containing the cities. - * @param logger The logger to be used with this. + * containing the cities. + * @param logger The logger to be used with this. + * * @throws IOException */ - private ClosestCityMapper(InputStream citiesInputStream, java.util.logging.Logger logger) throws IOException { - this.logger = logger; + private ClosestCityMapper(InputStream citiesInputStream) throws IOException { latLngMap = new LatLngMap(parseCsvLines(citiesInputStream, true)); } @@ -109,9 +108,10 @@ class ClosestCityMapper { * city can be determined. * * @param point The point to locate. + * * @return The closest city or null if no close city can be found. */ - CityRecord findClosest(CityRecord point) { + static CityRecord findClosest(CityRecord point) { return latLngMap.findClosest(point); } @@ -120,9 +120,10 @@ class ClosestCityMapper { * returned. * * @param s The string to parse. + * * @return The double value or null if value cannot be parsed. */ - private Double tryParse(String s) { + private static Double tryParse(String s) { if (s == null) { return null; } @@ -138,11 +139,12 @@ class ClosestCityMapper { * Parses a country name and transforms values like "last, first" to "first * last" (i.e. "Korea, South" becomes "South Korea"). * - * @param orig The original string value. + * @param orig The original string value. * @param lineNum The line number that this country was found. + * * @return The country name. */ - private String parseCountryName(String orig, int lineNum) { + private static String parseCountryName(String orig, int lineNum) { if (StringUtils.isBlank(orig)) { logger.log(Level.WARNING, String.format("No country name determined for line %d.", lineNum)); return null; @@ -159,12 +161,13 @@ class ClosestCityMapper { /** * Parses a row from the csv creating a city record. * - * @param csvRow The row of data where each item in the list is each column - * in the row. + * @param csvRow The row of data where each item in the list is each column + * in the row. * @param lineNum The line number for this csv row. + * * @return The parsed CityRecord or null if none can be determined. */ - private CityRecord getCsvCityRecord(List csvRow, int lineNum) { + private static CityRecord getCsvCityRecord(List csvRow, int lineNum) { if (csvRow == null || csvRow.size() <= MAX_IDX) { logger.log(Level.WARNING, String.format("Row at line number %d is required to have at least %d elements and does not.", lineNum, (MAX_IDX + 1))); return null; @@ -199,11 +202,12 @@ class ClosestCityMapper { /** * Parses a row of the csv into individual column values. * - * @param line The line to parse. + * @param line The line to parse. * @param lineNum The line number in the csv where this line is. + * * @return The list of column values. */ - private List parseCsvLine(String line, int lineNum) { + private static List parseCsvLine(String line, int lineNum) { if (line == null || line.length() <= 0) { logger.log(Level.INFO, String.format("Line at %d had no content", lineNum)); return null; @@ -222,13 +226,15 @@ class ClosestCityMapper { * Parses all lines in the csv file input stream into a list of city * records. * - * @param csvInputStream The csv file input stream. + * @param csvInputStream The csv file input stream. * @param ignoreHeaderRow Whether or not there is a header row in the csv - * file. + * file. + * * @return The list of city records. + * * @throws IOException */ - private List parseCsvLines(InputStream csvInputStream, boolean ignoreHeaderRow) throws IOException { + private static List parseCsvLines(InputStream csvInputStream, boolean ignoreHeaderRow) throws IOException { List cityRecords = new ArrayList<>(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(csvInputStream, "UTF-8"))) { int lineNum = 1; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/GeolocationSummary.java old mode 100644 new mode 100755 similarity index 81% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummary.java rename to Core/src/org/sleuthkit/autopsy/contentutils/GeolocationSummary.java index d66bbaf30a..81b21b69d6 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummary.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/GeolocationSummary.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.contentutils; import java.io.IOException; import java.util.ArrayList; @@ -31,8 +31,8 @@ import java.util.concurrent.BlockingQueue; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.geolocation.AbstractWaypointFetcher; import org.sleuthkit.autopsy.geolocation.GeoFilter; import org.sleuthkit.autopsy.geolocation.MapWaypoint; @@ -45,7 +45,7 @@ import org.sleuthkit.datamodel.DataSource; /** * Gathers summary data about Geolocation information for a data source. */ -public class GeolocationSummary implements DefaultArtifactUpdateGovernor { +public class GeolocationSummary { /** * A count of hits for a particular city. @@ -59,8 +59,8 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { * Main constructor. * * @param cityRecord The record for the city including name, country, - * and location. - * @param count The number of hits in proximity to that city. + * and location. + * @param count The number of hits in proximity to that city. */ CityRecordCount(CityRecord cityRecord, int count) { this.cityRecord = cityRecord; @@ -69,7 +69,7 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { /** * @return The record for the city including name, country, and - * location. + * location. */ public CityRecord getCityRecord() { return cityRecord; @@ -96,8 +96,8 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { /** * Main constructor. * - * @param mostCommon The list of most common cities seen. - * @param mostRecent The list of most recent cities seen. + * @param mostCommon The list of most common cities seen. + * @param mostRecent The list of most recent cities seen. * @param mostRecentSeen */ CityData(CityCountsList mostCommon, CityCountsList mostRecent, Long mostRecentSeen) { @@ -122,7 +122,7 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { /** * @return The time stamp in seconds from epoch of the most recently - * seen city + * seen city */ public Long getMostRecentSeen() { return mostRecentSeen; @@ -142,10 +142,10 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { /** * Main constructor. * - * @param counts The list of cities and the count of how many points are - * closest to that city. + * @param counts The list of cities and the count of how many points + * are closest to that city. * @param otherCount The count of points where no closest city was - * determined due to not being close enough. + * determined due to not being close enough. */ CityCountsList(List counts, int otherCount) { this.counts = Collections.unmodifiableList(new ArrayList<>(counts)); @@ -154,7 +154,7 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { /** * @return The list of cities and the count of how many points are - * closest to that city. + * closest to that city. */ public List getCounts() { return counts; @@ -162,7 +162,7 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { /** * @return The count of points where no closest city was determined due - * to not being close enough. + * to not being close enough. */ public int getOtherCount() { return otherCount; @@ -183,10 +183,10 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { * Main constructor. * * @param mapWaypoints The way points found for the data source. - * @param tracks A list of sets where each set is a track in the data - * source. - * @param areas A list of areas where each set is an area in the data - * source. + * @param tracks A list of sets where each set is a track in the + * data source. + * @param areas A list of areas where each set is an area in the + * data source. */ private GeoResult(Set mapWaypoints, List> tracks, List> areas) { this.mapWaypoints = mapWaypoints; @@ -238,8 +238,7 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { private static final long DAY_SECS = 24 * 60 * 60; - private final SleuthkitCaseProvider provider; - private final SupplierWithException cityMapper; + private static final SupplierWithException cityMapper = () -> ClosestCityMapper.getInstance(); /** * A supplier of an item T that can throw an exception of type E. @@ -250,40 +249,24 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { * A supplier method that can throw an exception of E. * * @return The object type. + * * @throws E The exception type. */ T get() throws E; } - /** - * Default constructor. - */ - public GeolocationSummary() { - this(() -> ClosestCityMapper.getInstance(), SleuthkitCaseProvider.DEFAULT); - } - - /** - * Main constructor. - * - * @param cityMapper A means of acquiring a ClosestCityMapper that can throw - * an IOException. - * @param provider A means of acquiring a SleuthkitCaseProvider. - */ - public GeolocationSummary(SupplierWithException cityMapper, SleuthkitCaseProvider provider) { - this.cityMapper = cityMapper; - this.provider = provider; + private GeolocationSummary() { } /** * @return Returns all the geolocation artifact types. */ - public List getGeoTypes() { + public static List getGeoTypes() { return GPS_ARTIFACT_TYPES; } - @Override - public Set getArtifactTypeIdsForRefresh() { - return GPS_ARTIFACT_TYPE_IDS; + public static Set getArtifactTypeIdsForRefresh() { + return Collections.unmodifiableSet(GPS_ARTIFACT_TYPE_IDS); } /** @@ -291,13 +274,14 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { * the event where either time is null. * * @param minTime The minimum time. If null is provided, this function will - * return false. - * @param time The time to check. If null is provided and the min time is - * non-null, then this function will return false. + * return false. + * @param time The time to check. If null is provided and the min time is + * non-null, then this function will return false. + * * @return If minTime == null then false. If minTime != null && time == null - * then false. Otherwise time >= minTime. + * then false. Otherwise time >= minTime. */ - private boolean greaterThanOrEqual(Long minTime, Long time) { + private static boolean greaterThanOrEqual(Long minTime, Long time) { if (minTime != null && time != null && time >= minTime) { return true; } else { @@ -310,12 +294,13 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { * a total of waypoints whose time stamp is greater than or equal to * minTime. * - * @param points The list of way points. + * @param points The list of way points. * @param minTime The minimum time for most recent points count. + * * @return A pair where the left value is the total count of way points and - * the right is the total list of way points that are >= minTime. + * the right is the total list of way points that are >= minTime. */ - private Pair getCounts(List points, Long minTime) { + private static Pair getCounts(List points, Long minTime) { if (points == null) { return EMPTY_COUNT; } @@ -332,10 +317,11 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { * the point is null, null is returned. * * @param cityMapper The means of mapping a point to the closest city. - * @param pt The geolocation point. + * @param pt The geolocation point. + * * @return A tuple of the closest city and timestamp in seconds from epoch. */ - private Pair getClosestWithTime(ClosestCityMapper cityMapper, MapWaypoint pt) { + private static Pair getClosestWithTime(ClosestCityMapper cityMapper, MapWaypoint pt) { if (pt == null) { return null; } @@ -351,12 +337,14 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { * into a stream of the unique cities identified in this grouping and the * latest time stamp for each grouping. * - * @param points The points in the grouping. + * @param points The points in the grouping. * @param cityMapper The means of mapping a point to the closest city. + * * @return A stream of tuples where each tuple will be a unique city (or - * null if a closest is not determined) and the latest timestamp for each. + * null if a closest is not determined) and the latest timestamp for + * each. */ - private Stream> reduceGrouping(Set points, ClosestCityMapper cityMapper) { + private static Stream> reduceGrouping(Set points, ClosestCityMapper cityMapper) { if (points == null) { return Stream.empty(); } @@ -367,7 +355,7 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { if (pair == null) { continue; } - + CityRecord city = pair.getLeft(); Long prevTime = timeMapping.get(city); Long curTime = pair.getRight(); @@ -375,7 +363,7 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { timeMapping.put(city, curTime); } } - + return timeMapping.entrySet().stream() .map(e -> Pair.of(e.getKey(), e.getValue())); } @@ -385,20 +373,22 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { * of tuples where each tuple represents a point with the closest city and * the time stamp in seconds from epoch. * - * @param geoResult The result from the Geolocation API. + * @param geoResult The result from the Geolocation API. * @param cityMapper The means of mapping a point to the closest city. + * * @return A list of tuples where each tuple represents a point to be - * counted with a combination of the closest city and the timestamp. + * counted with a combination of the closest city and the timestamp. + * * @throws IOException */ - private Stream> processGeoResult(GeoResult geoResult, ClosestCityMapper cityMapper) { + private static Stream> processGeoResult(GeoResult geoResult, ClosestCityMapper cityMapper) { if (geoResult == null) { return Stream.empty(); } List> areas = (geoResult.getAreas() == null) ? Collections.emptyList() : geoResult.getAreas(); List> tracks = (geoResult.getTracks() == null) ? Collections.emptyList() : geoResult.getTracks(); - + Stream> reducedGroupings = Stream.of(areas, tracks) .flatMap((groupingList) -> groupingList.stream()) .flatMap((grouping) -> reduceGrouping(grouping, cityMapper)); @@ -407,7 +397,7 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { .flatMap((groupingList) -> groupingList.stream()) .flatMap((group) -> group.stream()) .collect(Collectors.toSet()); - + Set pointSet = geoResult.getMapWaypoints() == null ? Collections.emptySet() : geoResult.getMapWaypoints(); Stream> citiesForPoints = pointSet.stream() // it appears that AbstractWaypointFetcher.handleFilteredWaypointSet returns all points @@ -423,19 +413,19 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { * number of found hits (i.e. most hits is first index). * * @param dataSource The data source. - * @param daysCount Number of days to go back. - * @param maxCount Maximum number of results. + * @param daysCount Number of days to go back. + * @param maxCount Maximum number of results. * * @return The sorted list. * - * @throws SleuthkitCaseProviderException + * @throws NoCurrentCaseException * @throws GeoLocationDataException * @throws InterruptedException */ - public CityData getCityCounts(DataSource dataSource, int daysCount, int maxCount) - throws SleuthkitCaseProviderException, GeoLocationDataException, InterruptedException, IOException { + public static CityData getCityCounts(DataSource dataSource, int daysCount, int maxCount) + throws NoCurrentCaseException, GeoLocationDataException, InterruptedException, IOException { - ClosestCityMapper closestCityMapper = this.cityMapper.get(); + ClosestCityMapper closestCityMapper = cityMapper.get(); GeoResult geoResult = getGeoResult(dataSource); List> dataSourcePoints = processGeoResult(geoResult, closestCityMapper) .collect(Collectors.toList()); @@ -507,9 +497,10 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { * Main constructor. * * @param asyncResult Geolocation fetches results in a callback which is - * already handled by other mechanisms in data source summary. The - * BlockingQueue blocks until a result is received from geolocation. - * @param filters The applicable filters for geolocation. + * already handled by other mechanisms in data source + * summary. The BlockingQueue blocks until a result + * is received from geolocation. + * @param filters The applicable filters for geolocation. */ public PointFetcher(BlockingQueue asyncResult, GeoFilter filters) { super(filters); @@ -531,13 +522,15 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { * Fetches all GPS data for the data source from the current case. * * @param dataSource The data source. + * * @return The GPS data pertaining to the data source. - * @throws SleuthkitCaseProviderException + * + * @throws NoCurrentCaseException * @throws GeoLocationDataException * @throws InterruptedException */ - private GeoResult getGeoResult(DataSource dataSource) - throws SleuthkitCaseProviderException, GeoLocationDataException, InterruptedException { + private static GeoResult getGeoResult(DataSource dataSource) + throws NoCurrentCaseException, GeoLocationDataException, InterruptedException { // make asynchronous callback synchronous (the callback nature will be handled in a different level) // see the following: https://stackoverflow.com/questions/20659961/java-synchronous-callback @@ -545,7 +538,7 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor { GeoFilter geoFilter = new GeoFilter(true, false, 0, Arrays.asList(dataSource), GPS_ARTIFACT_TYPES); - WaypointBuilder.getAllWaypoints(provider.get(), + WaypointBuilder.getAllWaypoints(Case.getCurrentCaseThrows().getSleuthkitCase(), Arrays.asList(dataSource), GPS_ARTIFACT_TYPES, true, diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/LatLngMap.java b/Core/src/org/sleuthkit/autopsy/contentutils/LatLngMap.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/LatLngMap.java rename to Core/src/org/sleuthkit/autopsy/contentutils/LatLngMap.java index 01032f61da..9d026ab11d 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/LatLngMap.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/LatLngMap.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.contentutils; import java.util.Collection; import java.util.List; @@ -64,8 +64,8 @@ class LatLngMap { * Main contructor. * * @param pointsToAdd The points to be added to the data structure. - * @param bucketSize The size of a grid square in kilometers. So, if this - * value is 100, each sqaure will be a 100 x 100 km. + * @param bucketSize The size of a grid square in kilometers. So, if this + * value is 100, each sqaure will be a 100 x 100 km. */ LatLngMap(List pointsToAdd, double bucketSize) { this.bucketSize = bucketSize; @@ -86,6 +86,7 @@ class LatLngMap { * closest neighboring buckets. * * @param point The point to calculate the bucket location pair. + * * @return The pair that was determined. */ private Pair getBucketLocation(XYZPoint point) { @@ -106,6 +107,7 @@ class LatLngMap { * Finds closest point within (.5 * bucketSize) distance. * * @param point The point for which to find closest. + * * @return Returns the found point. */ E findClosest(E point) { @@ -132,9 +134,10 @@ class LatLngMap { /** * Within the specific bucket, finds the closest point if any exists. * - * @param x The x axis bucket. - * @param y The y axis bucket. + * @param x The x axis bucket. + * @param y The y axis bucket. * @param point The point to search for. + * * @return The point, if any, that was found. */ private E findClosestInBucket(int x, int y, E point) { diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/worldcities.csv b/Core/src/org/sleuthkit/autopsy/contentutils/worldcities.csv similarity index 100% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/worldcities.csv rename to Core/src/org/sleuthkit/autopsy/contentutils/worldcities.csv diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummaryGetter.java new file mode 100644 index 0000000000..9165f43561 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummaryGetter.java @@ -0,0 +1,81 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020-2021 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.datasourcesummary.datamodel; + +import java.io.IOException; +import java.util.List; +import java.util.Set; +import org.sleuthkit.autopsy.contentutils.GeolocationSummary; +import org.sleuthkit.autopsy.contentutils.GeolocationSummary.CityData; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; +import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException; +import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; + +/** + * Wrapper class for converting + * org.sleuthkit.autopsy.contentutils.GeolocationSummary functionality into a + * DefaultArtifactUpdateGovernor used by GeolocationPanel tab. + */ +public class GeolocationSummaryGetter implements DefaultArtifactUpdateGovernor { + + /** + * Default constructor. + */ + public GeolocationSummaryGetter() { + } + + /** + * @return Returns all the geolocation artifact types. + */ + public List getGeoTypes() { + return GeolocationSummary.getGeoTypes(); + } + + @Override + public Set getArtifactTypeIdsForRefresh() { + return GeolocationSummary.getArtifactTypeIdsForRefresh(); + } + + /** + * Get this list of hits per city where the list is sorted descending by + * number of found hits (i.e. most hits is first index). + * + * @param dataSource The data source. + * @param daysCount Number of days to go back. + * @param maxCount Maximum number of results. + * + * @return The sorted list. + * + * @throws SleuthkitCaseProviderException + * @throws GeoLocationDataException + * @throws InterruptedException + */ + public CityData getCityCounts(DataSource dataSource, int daysCount, int maxCount) + throws SleuthkitCaseProviderException, GeoLocationDataException, InterruptedException, IOException { + + try { + return GeolocationSummary.getCityCounts(dataSource, daysCount, maxCount); + } catch (NoCurrentCaseException ex) { + throw new SleuthkitCaseProviderException("No currently open case.", ex); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java index 595209f064..3e5687255e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java @@ -34,11 +34,11 @@ import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityCountsList; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityData; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityRecordCount; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.CityRecord; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummaryGetter; +import org.sleuthkit.autopsy.contentutils.GeolocationSummary.CityCountsList; +import org.sleuthkit.autopsy.contentutils.GeolocationSummary.CityData; +import org.sleuthkit.autopsy.contentutils.GeolocationSummary.CityRecordCount; +import org.sleuthkit.autopsy.contentutils.CityRecord; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; @@ -78,9 +78,9 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel { * Main constructor. * * @param mostRecentData The data to be displayed in the most recent - * table. + * table. * @param mostCommonData The data to be displayed in the most common - * table. + * table. */ GeolocationViewModel(List> mostRecentData, List> mostCommonData) { this.mostRecentData = mostRecentData; @@ -146,7 +146,7 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel { private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel(); - private final GeolocationSummary whereUsedData; + private final GeolocationSummaryGetter whereUsedData; private final DataFetcher geolocationFetcher; @@ -154,15 +154,15 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel { * Main constructor. */ public GeolocationPanel() { - this(new GeolocationSummary()); + this(new GeolocationSummaryGetter()); } /** * Main constructor. * - * @param whereUsedData The GeolocationSummary instance to use. + * @param whereUsedData The GeolocationSummaryGetter instance to use. */ - public GeolocationPanel(GeolocationSummary whereUsedData) { + public GeolocationPanel(GeolocationSummaryGetter whereUsedData) { super(whereUsedData); this.whereUsedData = whereUsedData; @@ -182,7 +182,7 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel { * Means of rendering data to be shown in the tables. * * @param result The result of fetching data for a data source and - * processing into view model data. + * processing into view model data. */ private void handleData(DataFetchResult result) { showCityContent(DataFetchResult.getSubResult(result, (dr) -> dr.getMostCommonData()), mostCommonTable, commonViewInGeolocationBtn); @@ -193,6 +193,7 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel { * Retrieves the city name to display from the record. * * @param record The record for the city to display. + * * @return The display name (city, country). */ private static String getCityName(CityRecord record) { @@ -220,6 +221,7 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel { * formats the city name). * * @param cityCount The CityRecordCount representing a row. + * * @return The city/count pair to be displayed as a row. */ private Pair formatRecord(CityRecordCount cityCount) { @@ -238,7 +240,8 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel { * 'unknown'). * * @param countsList The CityCountsList object representing the data to be - * displayed in the table. + * displayed in the table. + * * @return The list of city/count tuples to be displayed as a row. */ private List> formatList(CityCountsList countsList) { @@ -262,10 +265,11 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel { } /** - * Converts CityData from GeolocationSummary into data that can be directly - * put into table in this panel. + * Converts CityData from GeolocationSummaryGetter into data that can be + * directly put into table in this panel. * * @param cityData The city data. + * * @return The view model data. */ private GeolocationViewModel convertToViewModel(CityData cityData) { @@ -279,8 +283,8 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel { /** * Shows data in a particular table. * - * @param result The result to be displayed in the table. - * @param table The table where the data will be displayed. + * @param result The result to be displayed in the table. + * @param table The table where the data will be displayed. * @param goToGeolocation The corresponding geolocation navigation button. */ private void showCityContent(DataFetchResult>> result, JTablePanel> table, JButton goToGeolocation) { @@ -295,9 +299,9 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel { * Action to open the geolocation window. * * @param dataSource The data source for which the window should filter. - * @param daysLimit The limit for how recently the waypoints should be (for - * most recent table) or null for most recent filter to not be set (for most - * common table). + * @param daysLimit The limit for how recently the waypoints should be (for + * most recent table) or null for most recent filter to + * not be set (for most common table). */ private void openGeolocationWindow(DataSource dataSource, Integer daysLimit) { // notify dialog (if in dialog) should close. @@ -348,20 +352,6 @@ public class GeolocationPanel extends BaseDataSourceSummaryPanel { onNewDataSource(dataFetchComponents, tables, dataSource); } - /* ELTODO - @Override - List getExports(DataSource dataSource) { - GeolocationViewModel model = getFetchResult(geolocationFetcher, "Geolocation sheets", dataSource); - if (model == null) { - return Collections.emptyList(); - } - - return Arrays.asList( - getTableExport(DEFAULT_TEMPLATE, Bundle.GeolocationPanel_mostRecent_tabName(), model.getMostRecentData()), - getTableExport(DEFAULT_TEMPLATE, Bundle.GeolocationPanel_mostCommon_tabName(), model.getMostCommonData()) - ); - }*/ - @Override public void close() { ingestRunningLabel.unregister(); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index d6ca349440..1465a25316 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -7,6 +7,7 @@ ExcelExportAction_exportToXLSX_beginExport=Beginning Export... ExcelExportAction_exportToXLSX_gatheringAnalysisData=Fetching Analysis Data ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data ExcelExportAction_exportToXLSX_gatheringFileData=Fetching File and MIME Type Data +ExcelExportAction_exportToXLSX_gatheringGeoData=Fetching Geolocation Data ExcelExportAction_exportToXLSX_gatheringPastData=Fetching Historical Data ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data @@ -35,6 +36,11 @@ ExportContainerInfo_export_timeZone=Time Zone: ExportContainerInfo_export_unallocatedSize=Unallocated Space: ExportContainerInfo_setFieldsForNonImageDataSource_na=N/A ExportContainerInfo_tabName=Container +ExportGeolocation_cityColumn_title=Closest City +ExportGeolocation_countColumn_title=Count +ExportGeolocation_mostCommon_tabName=Most Common Cities +ExportGeolocation_mostRecent_tabName=Most Recent Cities +ExportGeolocation_unknownRow_title=Unknown ExportPastCases_caseColumn_title=Case ExportPastCases_countColumn_title=Count ExportPastCases_notableFileTable_tabName=Cases with Common Notable diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index 44879e741f..676b7086a1 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -99,6 +99,7 @@ class ExcelExportAction { "ExcelExportAction_exportToXLSX_gatheringAnalysisData=Fetching Analysis Data", "ExcelExportAction_exportToXLSX_gatheringPastData=Fetching Historical Data", "ExcelExportAction_exportToXLSX_gatheringUserData=Fetching User Activity Data", + "ExcelExportAction_exportToXLSX_gatheringGeoData=Fetching Geolocation Data", "ExcelExportAction_exportToXLSX_writingToFile=Writing to File...",}) void exportToXLSX(ReportProgressPanel progressPanel, DataSource dataSource, String baseReportDir) @@ -167,6 +168,14 @@ class ExcelExportAction { sheetExports.addAll(exports); } + // Export geolocation data + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringGeoData()); + progressPanel.setProgress(7); + exports = ExportGeolocation.getExports(dataSource); + if (exports != null) { + sheetExports.addAll(exports); + } + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_writingToFile()); progressPanel.setProgress(9); ExcelExport.writeExcel(sheetExports, reportFile); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java new file mode 100755 index 0000000000..1ea449b073 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java @@ -0,0 +1,223 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.report.modules.datasourcesummaryexport; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.contentutils.GeolocationSummary.CityCountsList; +import org.sleuthkit.autopsy.contentutils.GeolocationSummary.CityData; +import org.sleuthkit.autopsy.contentutils.GeolocationSummary.CityRecordCount; +import org.sleuthkit.autopsy.contentutils.CityRecord; +import org.sleuthkit.autopsy.contentutils.GeolocationSummary; +import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getFetchResult; +import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getTableExport; +import org.sleuthkit.datamodel.DataSource; + +/** + * Class to export information about a data source's geolocation data. + */ +@Messages({ + "ExportGeolocation_cityColumn_title=Closest City", + "ExportGeolocation_countColumn_title=Count", + "ExportGeolocation_unknownRow_title=Unknown", + "ExportGeolocation_mostCommon_tabName=Most Common Cities", + "ExportGeolocation_mostRecent_tabName=Most Recent Cities",}) +class ExportGeolocation { + + /** + * Object encapsulating geolocation data. + */ + private static class GeolocationData { + + private final List> mostRecentData; + private final List> mostCommonData; + + /** + * Main constructor. + * + * @param mostRecentData The data to be displayed in the most recent + * tab. + * @param mostCommonData The data to be displayed in the most common + * tab. + */ + GeolocationData(List> mostRecentData, List> mostCommonData) { + this.mostRecentData = mostRecentData; + this.mostCommonData = mostCommonData; + } + + /** + * Returns the data to be displayed in the most recent tab. + * + * @return The data to be displayed in the most recent tab. + */ + List> getMostRecentData() { + return mostRecentData; + } + + /** + * Returns the data to be displayed in the most common tab. + * + * @return The data to be displayed in the most common tab. + */ + List> getMostCommonData() { + return mostCommonData; + } + } + + private static final int DAYS_COUNT = 30; + private static final int MAX_COUNT = 10; + + // The column indicating the city + private static final ColumnModel, DefaultCellModel> CITY_COL = new ColumnModel<>( + Bundle.ExportGeolocation_cityColumn_title(), + (pair) -> new DefaultCellModel<>(pair.getLeft()), + 300 + ); + + // The column indicating the count of points seen close to that city + private static final ColumnModel, DefaultCellModel> COUNT_COL = new ColumnModel<>( + Bundle.ExportGeolocation_countColumn_title(), + (pair) -> new DefaultCellModel<>(pair.getRight()), + 100 + ); + + private static final List, DefaultCellModel>> DEFAULT_TEMPLATE = Arrays.asList( + CITY_COL, + COUNT_COL + ); + + private ExportGeolocation() { + } + + /** + * Retrieves the city name to display from the record. + * + * @param record The record for the city to display. + * + * @return The display name (city, country). + */ + private static String getCityName(CityRecord record) { + if (record == null) { + return null; + } + + List cityIdentifiers = Stream.of(record.getCityName(), record.getState(), record.getCountry()) + .filter(StringUtils::isNotBlank) + .collect(Collectors.toList()); + + if (cityIdentifiers.size() == 1) { + return cityIdentifiers.get(0); + } else if (cityIdentifiers.size() == 2) { + return String.format("%s, %s", cityIdentifiers.get(0), cityIdentifiers.get(1)); + } else if (cityIdentifiers.size() >= 3) { + return String.format("%s, %s; %s", cityIdentifiers.get(0), cityIdentifiers.get(1), cityIdentifiers.get(2)); + } + + return null; + } + + /** + * Formats one record to be displayed as a row in the tab (specifically, + * formats the city name). + * + * @param cityCount The CityRecordCount representing a row. + * + * @return The city/count pair to be displayed as a row. + */ + private static Pair formatRecord(CityRecordCount cityCount) { + if (cityCount == null) { + return null; + } + + String cityName = getCityName(cityCount.getCityRecord()); + int count = cityCount.getCount(); + return Pair.of(cityName, count); + } + + /** + * Formats a list of records to be displayed in a tab (specifically, + * includes the count of points where no closest city could be determined as + * 'unknown'). + * + * @param countsList The CityCountsList object representing the data to be + * displayed in the tab. + * + * @return The list of city/count tuples to be displayed as a row. + */ + private static List> formatList(CityCountsList countsList) { + if (countsList == null) { + return Collections.emptyList(); + } + + Stream countsStream = ((countsList.getCounts() == null) + ? new ArrayList() + : countsList.getCounts()).stream(); + + Stream> pairStream = countsStream.map((r) -> formatRecord(r)); + + Pair unknownRecord = Pair.of(Bundle.ExportGeolocation_unknownRow_title(), countsList.getOtherCount()); + + return Stream.concat(pairStream, Stream.of(unknownRecord)) + .filter((p) -> p != null && p.getRight() != null && p.getRight() > 0) + .sorted((a, b) -> -Integer.compare(a.getRight(), b.getRight())) + .limit(MAX_COUNT) + .collect(Collectors.toList()); + } + + /** + * Converts CityData from GeolocationSummaryGetter into data that can be + * directly put into tab in this panel. + * + * @param cityData The city data. + * + * @return The geolocation data. + */ + private static GeolocationData convertToViewModel(CityData cityData) { + if (cityData == null) { + return new GeolocationData(Collections.emptyList(), Collections.emptyList()); + } else { + return new GeolocationData(formatList(cityData.getMostRecent()), formatList(cityData.getMostCommon())); + } + } + + static List getExports(DataSource dataSource) { + + DataFetcher geolocationFetcher = (ds) -> convertToViewModel(GeolocationSummary.getCityCounts(ds, DAYS_COUNT, MAX_COUNT)); + + GeolocationData model + = getFetchResult(geolocationFetcher, "Geolocation sheets", dataSource); + if (model == null) { + return Collections.emptyList(); + } + + return Arrays.asList(getTableExport(DEFAULT_TEMPLATE, + Bundle.ExportGeolocation_mostRecent_tabName(), model.getMostRecentData()), + getTableExport(DEFAULT_TEMPLATE, + Bundle.ExportGeolocation_mostCommon_tabName(), model.getMostCommonData()) + ); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java index c89c4f996a..ba9ff135ce 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java @@ -40,7 +40,7 @@ import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopWebSearchResult import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getTableExport; /** - * A panel to display user activity. + * Class to export user activity present in the specified DataSource. */ @Messages({ "ExportUserActivity_tab_title=User Activity", diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java index 10c42eebbb..eb14d53e51 100644 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java @@ -27,7 +27,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter.TopDomainsResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDomainsResult; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java index 216b1b99c5..787153543c 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java @@ -44,11 +44,11 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceSummaryMockUtils.getArtifactsTSKMock; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter.TopAccountResult; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter.TopDeviceAttachedResult; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter.TopDomainsResult; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter.TopProgramsResult; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter.TopWebSearchResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopAccountResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDeviceAttachedResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDomainsResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopProgramsResult; +import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopWebSearchResult; import org.sleuthkit.autopsy.testutils.TskMockUtils; import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException; import org.sleuthkit.autopsy.texttranslation.TextTranslationService; @@ -133,11 +133,7 @@ public class UserActivitySummaryTest { private static UserActivitySummaryGetter getTestClass(SleuthkitCase tskCase, boolean hasTranslation, Function translateFunction) throws NoServiceProviderException, TranslationException { - return new UserActivitySummaryGetter( - () -> tskCase, - TskMockUtils.getTextTranslationService(translateFunction, hasTranslation), - TskMockUtils.getJavaLogger("UNIT TEST LOGGER") - ); + return new UserActivitySummaryGetter(); } private void testMinCount(DataFunction funct, String id) @@ -433,11 +429,7 @@ public class UserActivitySummaryTest { // set up a mock TextTranslationService returning a translation TextTranslationService translationService = TskMockUtils.getTextTranslationService(translator, hasProvider); - UserActivitySummaryGetter summary = new UserActivitySummaryGetter( - () -> tskPair.getLeft(), - translationService, - TskMockUtils.getJavaLogger("UNIT TEST LOGGER") - ); + UserActivitySummaryGetter summary = new UserActivitySummaryGetter(); List results = summary.getMostRecentWebSearches(ds, queries.size()); From a08847583ccd71302949d966c2cef499752cfe09 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Tue, 10 Aug 2021 14:28:44 -0400 Subject: [PATCH 24/76] Refactored ingest history tab --- .../contentutils/GeolocationSummary.java | 4 +- .../ui/Bundle.properties-MERGED | 6 -- .../datasourcesummary/ui/TypesPanel.java | 61 ------------------- .../Bundle.properties-MERGED | 7 +++ .../ExcelExportAction.java | 9 +++ .../ExportIngestHistory.java} | 40 ++++++------ 6 files changed, 37 insertions(+), 90 deletions(-) rename Core/src/org/sleuthkit/autopsy/{datasourcesummary/ui/IngestJobExcelExport.java => report/modules/datasourcesummaryexport/ExportIngestHistory.java} (86%) diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/GeolocationSummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/GeolocationSummary.java index 81b21b69d6..ea3ffec08c 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/GeolocationSummary.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/GeolocationSummary.java @@ -243,7 +243,7 @@ public class GeolocationSummary { /** * A supplier of an item T that can throw an exception of type E. */ - public interface SupplierWithException { + interface SupplierWithException { /** * A supplier method that can throw an exception of E. @@ -502,7 +502,7 @@ public class GeolocationSummary { * is received from geolocation. * @param filters The applicable filters for geolocation. */ - public PointFetcher(BlockingQueue asyncResult, GeoFilter filters) { + PointFetcher(BlockingQueue asyncResult, GeoFilter filters) { super(filters); this.asyncResult = asyncResult; } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED index b3c57b15dc..27a706c4a0 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -62,12 +62,6 @@ GeolocationPanel_mostCommon_tabName=Most Common Cities GeolocationPanel_mostRecent_tabName=Most Recent Cities GeolocationPanel_onNoCrIngest_message=No results will be shown because the GPX Parser was not run. GeolocationPanel_unknownRow_title=Unknown -IngestJobExcelExport_endTimeColumn=End Time -IngestJobExcelExport_ingestStatusTimeColumn=Ingest Status -IngestJobExcelExport_moduleNameTimeColumn=Module Name -IngestJobExcelExport_sheetName=Ingest History -IngestJobExcelExport_startTimeColumn=Start Time -IngestJobExcelExport_versionColumn=Module Version PastCasesPanel_caseColumn_title=Case PastCasesPanel_countColumn_title=Count PastCasesPanel_notableFileTable_tabName=Cases with Common Notable diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index a5040a355e..d892b4a9c4 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -327,67 +327,6 @@ class TypesPanel extends BaseDataSourceSummaryPanel { } } - /** - * Returns a key value pair to be exported in a sheet. - * - * @param fetcher The means of fetching the data. - * @param key The key to use. - * @param dataSource The data source containing the data. - * @return The key value pair to be exported. - */ - /* ELTODO private static KeyValueItemExportable getStrExportable(DataFetcher fetcher, String key, DataSource dataSource) { - String result = getFetchResult(fetcher, "Types", dataSource); - return (result == null) ? null : new KeyValueItemExportable(key, new DefaultCellModel<>(result)); - } - - /** - * Returns a key value pair to be exported in a sheet formatting the long - * with commas separated by orders of 1000. - * - * @param fetcher The means of fetching the data. - * @param key The string key for this key value pair. - * @param dataSource The data source. - * @return The key value pair. - */ - /* ELTODOprivate static KeyValueItemExportable getCountExportable(DataFetcher fetcher, String key, DataSource dataSource) { - Long count = getFetchResult(fetcher, "Types", dataSource); - return (count == null) ? null : new KeyValueItemExportable(key, - new DefaultCellModel(count, COMMA_FORMATTER::format, COMMA_FORMAT_STR)); - } - - /* ELTODO - @Override - List getExports(DataSource dataSource) { - if (dataSource == null) { - return Collections.emptyList(); - } - - // Retrieve data to create the types pie chart - TypesPieChartData typesData = TypesPanel.getFetchResult(typesFetcher, "Types", dataSource); - PieChartExport typesChart = (typesData == null || !typesData.isUsefulContent()) ? null : - new PieChartExport( - Bundle.TypesPanel_fileMimeTypesChart_title(), - Bundle.TypesPanel_fileMimeTypesChart_valueLabel(), - "#,###", - Bundle.TypesPanel_fileMimeTypesChart_title(), - typesData.getPieSlices()); - - return Arrays.asList(new ExcelSpecialFormatExport(Bundle.TypesPanel_excelTabName(), - Stream.of( - getStrExportable(usageFetcher, Bundle.TypesPanel_usageLabel_title(), dataSource), - getStrExportable(osFetcher, Bundle.TypesPanel_osLabel_title(), dataSource), - new KeyValueItemExportable(Bundle.TypesPanel_sizeLabel_title(), - SizeRepresentationUtil.getBytesCell(getFetchResult(sizeFetcher, "Types", dataSource))), - typesChart, - getCountExportable(allocatedFetcher, Bundle.TypesPanel_filesByCategoryTable_allocatedRow_title(), dataSource), - getCountExportable(unallocatedFetcher, Bundle.TypesPanel_filesByCategoryTable_unallocatedRow_title(), dataSource), - getCountExportable(slackFetcher, Bundle.TypesPanel_filesByCategoryTable_slackRow_title(), dataSource), - getCountExportable(directoriesFetcher, Bundle.TypesPanel_filesByCategoryTable_directoryRow_title(), dataSource)) - .filter(sheet -> sheet != null) - .collect(Collectors.toList()) - )); - }*/ - /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index 1465a25316..e9991129ff 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -8,6 +8,7 @@ ExcelExportAction_exportToXLSX_gatheringAnalysisData=Fetching Analysis Data ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data ExcelExportAction_exportToXLSX_gatheringFileData=Fetching File and MIME Type Data ExcelExportAction_exportToXLSX_gatheringGeoData=Fetching Geolocation Data +ExcelExportAction_exportToXLSX_gatheringIngestData=Fetching Ingest History Data ExcelExportAction_exportToXLSX_gatheringPastData=Fetching Historical Data ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data @@ -41,6 +42,12 @@ ExportGeolocation_countColumn_title=Count ExportGeolocation_mostCommon_tabName=Most Common Cities ExportGeolocation_mostRecent_tabName=Most Recent Cities ExportGeolocation_unknownRow_title=Unknown +ExportIngestHistory_endTimeColumn=End Time +ExportIngestHistory_ingestStatusTimeColumn=Ingest Status +ExportIngestHistory_moduleNameTimeColumn=Module Name +ExportIngestHistory_sheetName=Ingest History +ExportIngestHistory_startTimeColumn=Start Time +ExportIngestHistory_versionColumn=Module Version ExportPastCases_caseColumn_title=Case ExportPastCases_countColumn_title=Count ExportPastCases_notableFileTable_tabName=Cases with Common Notable diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index 676b7086a1..d6a408766f 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -100,6 +100,7 @@ class ExcelExportAction { "ExcelExportAction_exportToXLSX_gatheringPastData=Fetching Historical Data", "ExcelExportAction_exportToXLSX_gatheringUserData=Fetching User Activity Data", "ExcelExportAction_exportToXLSX_gatheringGeoData=Fetching Geolocation Data", + "ExcelExportAction_exportToXLSX_gatheringIngestData=Fetching Ingest History Data", "ExcelExportAction_exportToXLSX_writingToFile=Writing to File...",}) void exportToXLSX(ReportProgressPanel progressPanel, DataSource dataSource, String baseReportDir) @@ -176,6 +177,14 @@ class ExcelExportAction { sheetExports.addAll(exports); } + // Export ingest history + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringIngestData()); + progressPanel.setProgress(8); + exports = ExportIngestHistory.getExports(dataSource); + if (exports != null) { + sheetExports.addAll(exports); + } + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_writingToFile()); progressPanel.setProgress(9); ExcelExport.writeExcel(sheetExports, reportFile); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/IngestJobExcelExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportIngestHistory.java similarity index 86% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/IngestJobExcelExport.java rename to Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportIngestHistory.java index 5ec92353e2..95c38f2162 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/IngestJobExcelExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportIngestHistory.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.ui; +package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -34,25 +34,24 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; +import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelSheetExport; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; import org.sleuthkit.datamodel.IngestModuleInfo; import org.sleuthkit.datamodel.TskCoreException; /** - * Class that handles exporting information in IngestJobInfoPanel to excel. + * Class that handles exporting ingest job information to excel. */ @Messages({ - "IngestJobExcelExport_startTimeColumn=Start Time", - "IngestJobExcelExport_endTimeColumn=End Time", - "IngestJobExcelExport_ingestStatusTimeColumn=Ingest Status", - "IngestJobExcelExport_moduleNameTimeColumn=Module Name", - "IngestJobExcelExport_versionColumn=Module Version", - "IngestJobExcelExport_sheetName=Ingest History" + "ExportIngestHistory_startTimeColumn=Start Time", + "ExportIngestHistory_endTimeColumn=End Time", + "ExportIngestHistory_ingestStatusTimeColumn=Ingest Status", + "ExportIngestHistory_moduleNameTimeColumn=Module Name", + "ExportIngestHistory_versionColumn=Module Version", + "ExportIngestHistory_sheetName=Ingest History" }) -class IngestJobExcelExport { // ELTODO remove this class +class ExportIngestHistory { /** * An entry to display in an excel export. @@ -118,26 +117,26 @@ class IngestJobExcelExport { // ELTODO remove this class } } - private static final Logger logger = Logger.getLogger(IngestJobExcelExport.class.getName()); + private static final Logger logger = Logger.getLogger(ExportIngestHistory.class.getName()); private static final String DATETIME_FORMAT_STR = "yyyy/MM/dd HH:mm:ss"; private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat(DATETIME_FORMAT_STR, Locale.getDefault()); // columns in the excel export table to be created. private static final List>> COLUMNS = Arrays.asList( new ColumnModel<>( - Bundle.IngestJobExcelExport_startTimeColumn(), + Bundle.ExportIngestHistory_startTimeColumn(), (entry) -> getDateCell(entry.getStartTime())), new ColumnModel<>( - Bundle.IngestJobExcelExport_endTimeColumn(), + Bundle.ExportIngestHistory_endTimeColumn(), (entry) -> getDateCell(entry.getEndTime())), new ColumnModel<>( - Bundle.IngestJobExcelExport_ingestStatusTimeColumn(), + Bundle.ExportIngestHistory_ingestStatusTimeColumn(), (entry) -> new DefaultCellModel<>(entry.getStatus())), new ColumnModel<>( - Bundle.IngestJobExcelExport_moduleNameTimeColumn(), + Bundle.ExportIngestHistory_moduleNameTimeColumn(), (entry) -> new DefaultCellModel<>(entry.getIngestModule())), new ColumnModel<>( - Bundle.IngestJobExcelExport_versionColumn(), + Bundle.ExportIngestHistory_versionColumn(), (entry) -> new DefaultCellModel<>(entry.getIngestModuleVersion())) ); @@ -209,7 +208,6 @@ class IngestJobExcelExport { // ELTODO remove this class * @param dataSource The data source. * @return The list of sheets to be included in an export. */ - /* ELTODO static List getExports(DataSource dataSource) { if (dataSource == null) { return Collections.emptyList(); @@ -244,9 +242,9 @@ class IngestJobExcelExport { // ELTODO remove this class .filter(item -> item != null) .collect(Collectors.toList()); - return Arrays.asList(new ExcelTableExport<>(Bundle.IngestJobExcelExport_sheetName(), COLUMNS, toDisplay)); - }*/ + return Arrays.asList(new ExcelTableExport<>(Bundle.ExportIngestHistory_sheetName(), COLUMNS, toDisplay)); + } - private IngestJobExcelExport() { + private ExportIngestHistory() { } } From 64bfc659e1fb9197a0800fd083abe0fda314c128 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 10 Aug 2021 14:29:35 -0400 Subject: [PATCH 25/76] Initializing JFileChooser in background --- .../autopsy/casemodule/CaseOpenAction.java | 8 +- .../autopsy/casemodule/ImageFilePanel.java | 38 ++++--- .../autopsy/casemodule/LocalDiskPanel.java | 8 +- .../casemodule/MissingImageDialog.java | 32 +++--- .../casemodule/NewCaseVisualPanel1.java | 8 +- .../UnpackagePortableCaseDialog.java | 2 +- .../autopsy/contentviewers/PListViewer.java | 7 +- .../autopsy/contentviewers/SQLiteViewer.java | 7 +- .../corecomponents/AutopsyOptionsPanel.java | 42 ++++--- .../datasourceprocessors/RawDSInputPanel.java | 40 ++++--- .../XRYDataSourceProcessorConfigPanel.java | 7 +- .../AddExternalViewerRulePanel.java | 18 ++- .../directorytree/ExportCSVAction.java | 7 +- .../ExternalViewerGlobalSettingsPanel.java | 15 ++- .../actionhelpers/ExtractActionHelper.java | 10 +- .../geolocation/GeolocationSettingsPanel.java | 9 +- .../JFileChooserHelper.java | 87 +++++++++++++++ .../healthmonitor/HealthMonitorDashboard.java | 8 +- .../configuration/ConfigVisualPanel1.java | 7 +- .../logicalimager/dsp/LogicalImagerPanel.java | 7 +- .../HashDbCreateDatabaseDialog.java | 105 +++++++++++------- .../HashDbImportDatabaseDialog.java | 30 ++--- .../modules/hashdatabase/HashDbManager.java | 8 +- .../stix/STIXReportModuleConfigPanel.java | 7 +- 24 files changed, 360 insertions(+), 157 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserHelper.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java index 0ba92c7bce..c32cf6f87f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -43,6 +43,7 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.Version; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; /** * The action associated with the Case/Open Case menu item via the layer.xml @@ -64,6 +65,8 @@ public final class CaseOpenAction extends CallableSystemAction implements Action private static final Logger LOGGER = Logger.getLogger(CaseOpenAction.class.getName()); private final FileFilter caseMetadataFileFilter; + private final JFileChooserHelper fileChooserHelper; + /** * Constructs the action associated with the Case/Open Case menu item via * the layer.xml file, a toolbar button, and the Open Case button of the @@ -72,6 +75,7 @@ public final class CaseOpenAction extends CallableSystemAction implements Action */ public CaseOpenAction() { caseMetadataFileFilter = new FileNameExtensionFilter(NbBundle.getMessage(CaseOpenAction.class, "CaseOpenAction.autFilter.title", Version.getName(), CaseMetadata.getFileExtension()), CaseMetadata.getFileExtension().substring(1)); + fileChooserHelper = JFileChooserHelper.getHelper(); } /** @@ -80,7 +84,7 @@ public final class CaseOpenAction extends CallableSystemAction implements Action * to open the case described by the file. */ void openCaseSelectionWindow() { - JFileChooser fileChooser = new JFileChooser(); + JFileChooser fileChooser = fileChooserHelper.getChooser(); fileChooser.setDragEnabled(false); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); fileChooser.setMultiSelectionEnabled(false); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 4c6126fcb7..9f2a313ae3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.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"); @@ -35,6 +35,7 @@ import org.sleuthkit.autopsy.coreutils.DriveUtils; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; import org.sleuthkit.datamodel.HashUtility; /** @@ -48,8 +49,10 @@ public class ImageFilePanel extends JPanel implements DocumentListener { private static final long serialVersionUID = 1L; private static final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH"; //NON-NLS private static final String[] SECTOR_SIZE_CHOICES = {"Auto Detect", "512", "1024", "2048", "4096"}; - private final JFileChooser fileChooser = new JFileChooser(); + private final JFileChooserHelper fileChooserHelper = JFileChooserHelper.getHelper(); + private JFileChooser fileChooser; private final String contextName; + private final List fileChooserFilters; /** * Creates new form ImageFilePanel @@ -73,14 +76,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { sectorSizeComboBox.setSelectedIndex(0); errorLabel.setVisible(false); - - fileChooser.setDragEnabled(false); - fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - fileChooser.setMultiSelectionEnabled(false); - fileChooserFilters.forEach(fileChooser::addChoosableFileFilter); - if (fileChooserFilters.isEmpty() == false) { - fileChooser.setFileFilter(fileChooserFilters.get(0)); - } + this.fileChooserFilters = fileChooserFilters; } /** @@ -132,6 +128,21 @@ public class ImageFilePanel extends JPanel implements DocumentListener { private JTextField getSha256TextField() { return sha256HashTextField; } + + private JFileChooser getChooser() { + if(fileChooser == null) { + fileChooser = fileChooserHelper.getChooser(); + fileChooser.setDragEnabled(false); + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + fileChooser.setMultiSelectionEnabled(false); + fileChooserFilters.forEach(fileChooser::addChoosableFileFilter); + if (fileChooserFilters.isEmpty() == false) { + fileChooser.setFileFilter(fileChooserFilters.get(0)); + } + } + + return fileChooser; + } /** * This method is called from within the constructor to initialize the form. @@ -298,12 +309,13 @@ public class ImageFilePanel extends JPanel implements DocumentListener { String oldText = getContentPaths(); // set the current directory of the FileChooser if the ImagePath Field is valid File currentDir = new File(oldText); + JFileChooser chooser = getChooser(); if (currentDir.exists()) { - fileChooser.setCurrentDirectory(currentDir); + chooser.setCurrentDirectory(currentDir); } - if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { - String path = fileChooser.getSelectedFile().getPath(); + if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + String path = chooser.getSelectedFile().getPath(); if (path.endsWith(".001")) { String zeroX3_path = StringUtils.removeEnd(path, ".001") + ".000"; if (new File(zeroX3_path).exists()) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java index 469b93da66..60f3bd4156 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.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"); @@ -32,6 +32,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings; /** @@ -58,7 +59,8 @@ final class LocalDiskPanel extends JPanel { private static final long serialVersionUID = 1L; private LocalDisk localDisk; private boolean enableNext = false; - private final JFileChooser fc = new JFileChooser(); + private JFileChooser fc; + private final JFileChooserHelper chooserHelper; /** * Creates new form LocalDiskPanel @@ -68,6 +70,7 @@ final class LocalDiskPanel extends JPanel { customInit(); createTimeZoneList(); createSectorSizeList(); + chooserHelper = JFileChooserHelper.getHelper(); } /** @@ -261,6 +264,7 @@ final class LocalDiskPanel extends JPanel { }//GEN-LAST:event_pathTextFieldKeyReleased private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed + fc = chooserHelper.getChooser(); String oldText = pathTextField.getText(); // set the current directory of the FileChooser if the ImagePath Field is valid File currentFile = new File(oldText); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java index 201d25ecef..2e4f772baf 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012-2018 Basis Technology Corp. + * Copyright 2012-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,6 +32,7 @@ import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.DriveUtils; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -45,7 +46,8 @@ class MissingImageDialog extends javax.swing.JDialog { long obj_id; SleuthkitCase db; - private final JFileChooser fileChooser = new JFileChooser(); + private JFileChooser fileChooser; + private final JFileChooserHelper chooserHelper; /** * Instantiate a MissingImageDialog. @@ -58,17 +60,8 @@ class MissingImageDialog extends javax.swing.JDialog { this.obj_id = obj_id; this.db = db; initComponents(); - - fileChooser.setDragEnabled(false); - fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - fileChooser.setMultiSelectionEnabled(false); - - List fileFiltersList = ImageDSProcessor.getFileFiltersList(); - for (FileFilter fileFilter : fileFiltersList) { - fileChooser.addChoosableFileFilter(fileFilter); - } - fileChooser.setFileFilter(fileFiltersList.get(0)); - + + chooserHelper = JFileChooserHelper.getHelper(); selectButton.setEnabled(false); } @@ -270,6 +263,19 @@ class MissingImageDialog extends javax.swing.JDialog { private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed + if(fileChooser == null) { + fileChooser = chooserHelper.getChooser(); + fileChooser.setDragEnabled(false); + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + fileChooser.setMultiSelectionEnabled(false); + + List fileFiltersList = ImageDSProcessor.getFileFiltersList(); + for (FileFilter fileFilter : fileFiltersList) { + fileChooser.addChoosableFileFilter(fileFilter); + } + fileChooser.setFileFilter(fileFiltersList.get(0)); + } + String oldText = pathNameTextField.getText(); lbWarning.setText(""); // set the current directory of the FileChooser if the ImagePath Field is valid diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java index 32812b56ce..bb518a92df 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2020 Basis Technology Corp. + * Copyright 2011-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,6 +30,7 @@ import javax.swing.event.DocumentListener; import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; /** * The JPanel for the first page of the new case wizard. @@ -37,7 +38,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil; @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { - private final JFileChooser fileChooser = new JFileChooser(); + private final JFileChooserHelper fileChooserHelper = JFileChooserHelper.getHelper(); private final NewCaseWizardPanel1 wizPanel; /** @@ -353,8 +354,9 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { * @param evt the action event */ private void caseDirBrowseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_caseDirBrowseButtonActionPerformed + JFileChooser fileChooser = fileChooserHelper.getChooser(); fileChooser.setDragEnabled(false); - if (!caseParentDirTextField.getText().trim().equals("")) { + if (!caseParentDirTextField.getText().trim().isEmpty()) { fileChooser.setCurrentDirectory(new File(caseParentDirTextField.getText())); } fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/UnpackagePortableCaseDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/UnpackagePortableCaseDialog.java index 3b86909953..94c708fdbb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/UnpackagePortableCaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/UnpackagePortableCaseDialog.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index f73cb6350f..3547c5d8b2 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018-2019 Basis Technology Corp. + * Copyright 2018-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -56,6 +56,7 @@ import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; import org.sleuthkit.datamodel.TskCoreException; import org.xml.sax.SAXException; @@ -75,6 +76,8 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer private ExplorerManager explorerManager; private NSObject rootDict; + + private final JFileChooserHelper fileChooserHelper = JFileChooserHelper.getHelper(); /** * Creates new form PListViewer @@ -203,7 +206,7 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer return; } - final JFileChooser fileChooser = new JFileChooser(); + final JFileChooser fileChooser = fileChooserHelper.getChooser(); fileChooser.setCurrentDirectory(new File(openCase.getExportDirectory())); fileChooser.setFileFilter(new FileNameExtensionFilter("XML file", "xml")); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java index 7772be7d29..b4e6fdcf05 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018-2019 Basis Technology Corp. + * Copyright 2018-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -49,6 +49,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.autopsy.coreutils.SQLiteTableReader; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; /** * A file content viewer for SQLite database files. @@ -74,6 +75,8 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { private int currPage = 0; // curr page of rows being displayed SwingWorker worker; + + private final JFileChooserHelper chooserHelper = JFileChooserHelper.getHelper(); /** * Constructs a file content viewer for SQLite database files. @@ -280,7 +283,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { private void exportCsvButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportCsvButtonActionPerformed Case openCase = Case.getCurrentCase(); File caseDirectory = new File(openCase.getExportDirectory()); - JFileChooser fileChooser = new JFileChooser(); + JFileChooser fileChooser = chooserHelper.getChooser(); fileChooser.setDragEnabled(false); fileChooser.setCurrentDirectory(caseDirectory); //Set a filter to let the filechooser only work for csv files diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java index 56ff4a0993..91413334cb 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java @@ -55,6 +55,7 @@ import org.sleuthkit.autopsy.machinesettings.UserMachinePreferencesException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.Version; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; import org.sleuthkit.autopsy.machinesettings.UserMachinePreferences.TempDirChoice; import org.sleuthkit.autopsy.report.ReportBranding; @@ -82,8 +83,8 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; private static final String DEFAULT_HEAP_DUMP_FILE_FIELD = ""; - private final JFileChooser logoFileChooser; - private final JFileChooser tempDirChooser; + private JFileChooser logoFileChooser; + private JFileChooser tempDirChooser; private static final String ETC_FOLDER_NAME = "etc"; private static final String CONFIG_FILE_EXTENSION = ".conf"; private static final long ONE_BILLION = 1000000000L; //used to roughly convert system memory from bytes to gigabytes @@ -94,27 +95,17 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { private String initialMemValue = Long.toString(Runtime.getRuntime().maxMemory() / ONE_BILLION); private final ReportBranding reportBranding; - private final JFileChooser heapFileChooser; + private JFileChooser heapFileChooser; + + private final JFileChooserHelper logoChooserHelper = JFileChooserHelper.getHelper(); + private final JFileChooserHelper heapChooserHelper = JFileChooserHelper.getHelper(); + private final JFileChooserHelper tempChooserHelper = JFileChooserHelper.getHelper(); /** * Instantiate the Autopsy options panel. */ AutopsyOptionsPanel() { initComponents(); - logoFileChooser = new JFileChooser(); - logoFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - logoFileChooser.setMultiSelectionEnabled(false); - logoFileChooser.setAcceptAllFileFilterUsed(false); - logoFileChooser.setFileFilter(new GeneralFilter(GeneralFilter.GRAPHIC_IMAGE_EXTS, GeneralFilter.GRAPHIC_IMG_DECR)); - - tempDirChooser = new JFileChooser(); - tempDirChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - tempDirChooser.setMultiSelectionEnabled(false); - - heapFileChooser = new JFileChooser(); - heapFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - heapFileChooser.setMultiSelectionEnabled(false); - if (!isJVMHeapSettingsCapable()) { //32 bit JVM has a max heap size of 1.4 gb to 4 gb depending on OS //So disabling the setting of heap size when the JVM is not 64 bit @@ -1242,6 +1233,11 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { "# {0} - path", "AutopsyOptionsPanel_tempDirectoryBrowseButtonActionPerformed_onInvalidPath_description=Unable to create temporary directory within specified path: {0}",}) private void tempDirectoryBrowseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tempDirectoryBrowseButtonActionPerformed + if(tempDirChooser == null) { + tempDirChooser = tempChooserHelper.getChooser(); + tempDirChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + tempDirChooser.setMultiSelectionEnabled(false); + } int returnState = tempDirChooser.showOpenDialog(this); if (returnState == JFileChooser.APPROVE_OPTION) { String specifiedPath = tempDirChooser.getSelectedFile().getPath(); @@ -1318,6 +1314,13 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { }//GEN-LAST:event_defaultLogoRBActionPerformed private void browseLogosButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseLogosButtonActionPerformed + if(logoFileChooser == null) { + logoFileChooser = logoChooserHelper.getChooser(); + logoFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + logoFileChooser.setMultiSelectionEnabled(false); + logoFileChooser.setAcceptAllFileFilterUsed(false); + logoFileChooser.setFileFilter(new GeneralFilter(GeneralFilter.GRAPHIC_IMAGE_EXTS, GeneralFilter.GRAPHIC_IMG_DECR)); + } String oldLogoPath = agencyLogoPathField.getText(); int returnState = logoFileChooser.showOpenDialog(this); if (returnState == JFileChooser.APPROVE_OPTION) { @@ -1360,6 +1363,11 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { "AutopsyOptionsPanel_heapDumpBrowseButtonActionPerformed_fileAlreadyExistsMessage=File already exists. Please select a new location." }) private void heapDumpBrowseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_heapDumpBrowseButtonActionPerformed + if(heapFileChooser == null) { + heapFileChooser = heapChooserHelper.getChooser(); + heapFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + heapFileChooser.setMultiSelectionEnabled(false); + } String oldHeapPath = heapDumpFileField.getText(); if (!StringUtils.isBlank(oldHeapPath)) { heapFileChooser.setCurrentDirectory(new File(oldHeapPath)); diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java index 1a02f65060..6646525997 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.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"); @@ -32,6 +32,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; /** * Allows examiner to supply a raw data source. @@ -41,7 +42,8 @@ final class RawDSInputPanel extends JPanel implements DocumentListener { private static final long TWO_GB = 2000000000L; private static final long serialVersionUID = 1L; //default private final String PROP_LASTINPUT_PATH = "LBL_LastInputFile_PATH"; - private final JFileChooser fc = new JFileChooser(); + private JFileChooser fc; + private JFileChooserHelper chooserHelper = JFileChooserHelper.getHelper(); // Externally supplied name is used to store settings private final String contextName; /** @@ -51,11 +53,6 @@ final class RawDSInputPanel extends JPanel implements DocumentListener { initComponents(); errorLabel.setVisible(false); - - fc.setDragEnabled(false); - fc.setFileSelectionMode(JFileChooser.FILES_ONLY); - fc.setMultiSelectionEnabled(false); - this.contextName = context; } @@ -200,18 +197,25 @@ final class RawDSInputPanel extends JPanel implements DocumentListener { }// //GEN-END:initComponents @SuppressWarnings("deprecation") private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed - String oldText = pathTextField.getText(); - // set the current directory of the FileChooser if the ImagePath Field is valid - File currentDir = new File(oldText); - if (currentDir.exists()) { - fc.setCurrentDirectory(currentDir); - } + if (fc == null) { + fc = chooserHelper.getChooser(); + fc.setDragEnabled(false); + fc.setFileSelectionMode(JFileChooser.FILES_ONLY); + fc.setMultiSelectionEnabled(false); + } - int retval = fc.showOpenDialog(this); - if (retval == JFileChooser.APPROVE_OPTION) { - String path = fc.getSelectedFile().getPath(); - pathTextField.setText(path); - } + String oldText = pathTextField.getText(); + // set the current directory of the FileChooser if the ImagePath Field is valid + File currentDir = new File(oldText); + if (currentDir.exists()) { + fc.setCurrentDirectory(currentDir); + } + + int retval = fc.showOpenDialog(this); + if (retval == JFileChooser.APPROVE_OPTION) { + String path = fc.getSelectedFile().getPath(); + pathTextField.setText(path); + } }//GEN-LAST:event_browseButtonActionPerformed private void j2GBBreakupRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_j2GBBreakupRadioButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessorConfigPanel.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessorConfigPanel.java index a641ea1f73..898e4cdef4 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessorConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessorConfigPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,6 +30,7 @@ import javax.swing.JPanel; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; /** * Allows an examiner to configure the XRY Data source processor. @@ -49,6 +50,8 @@ final class XRYDataSourceProcessorConfigPanel extends JPanel { //panel will indicate when it is ready for an update. private final PropertyChangeSupport pcs; + private final JFileChooserHelper chooserHelper = JFileChooserHelper.getHelper(); + /** * Creates new form XRYDataSourceConfigPanel. * Prevent direct instantiation. @@ -191,7 +194,7 @@ final class XRYDataSourceProcessorConfigPanel extends JPanel { * report folder. */ private void fileBrowserButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileBrowserButtonActionPerformed - JFileChooser fileChooser = new JFileChooser(); + JFileChooser fileChooser = chooserHelper.getChooser(); fileChooser.setMultiSelectionEnabled(false); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); Optional lastUsedPath = getLastUsedPath(); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/AddExternalViewerRulePanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/AddExternalViewerRulePanel.java index 3cf1d2445a..34e1c24a3d 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/AddExternalViewerRulePanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/AddExternalViewerRulePanel.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"); @@ -26,6 +26,7 @@ import javax.swing.event.DocumentListener; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.GeneralFilter; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; /** @@ -35,7 +36,9 @@ import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; class AddExternalViewerRulePanel extends javax.swing.JPanel { private static final Logger logger = Logger.getLogger(AddExternalViewerRulePanel.class.getName()); - private final JFileChooser fc = new JFileChooser(); + private static final long serialVersionUID = 1L; + private JFileChooser fc; + private final JFileChooserHelper chooserHelper = JFileChooserHelper.getHelper(); private static final GeneralFilter exeFilter = new GeneralFilter(GeneralFilter.EXECUTABLE_EXTS, GeneralFilter.EXECUTABLE_DESC); enum EVENT { @@ -47,10 +50,6 @@ class AddExternalViewerRulePanel extends javax.swing.JPanel { */ AddExternalViewerRulePanel() { initComponents(); - fc.setDragEnabled(false); - fc.setFileSelectionMode(JFileChooser.FILES_ONLY); - fc.setMultiSelectionEnabled(false); - fc.setFileFilter(exeFilter); customize(); } @@ -260,6 +259,13 @@ class AddExternalViewerRulePanel extends javax.swing.JPanel { }// //GEN-END:initComponents private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed + if(fc == null) { + fc = chooserHelper.getChooser(); + fc.setDragEnabled(false); + fc.setFileSelectionMode(JFileChooser.FILES_ONLY); + fc.setMultiSelectionEnabled(false); + fc.setFileFilter(exeFilter); + } int returnState = fc.showOpenDialog(this); if (returnState == JFileChooser.APPROVE_OPTION) { String path = fc.getSelectedFile().getPath(); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java index 7b312211c4..904b423343 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -51,6 +51,7 @@ import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFileProp import org.openide.nodes.Node; import org.openide.nodes.Node.PropertySet; import org.openide.nodes.Node.Property; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; /** * Exports CSV version of result nodes to a location selected by the user. @@ -68,6 +69,8 @@ public final class ExportCSVAction extends AbstractAction { // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every // node in the array returns a reference to the same action object from Node.getActions(boolean). private static ExportCSVAction instance; + + private static final JFileChooserHelper chooserHelper = JFileChooserHelper.getHelper(); /** * Get an instance of the Action. See above for why @@ -125,7 +128,7 @@ public final class ExportCSVAction extends AbstractAction { // Set up the file chooser with a default name and either the Export // folder or the last used folder. String fileName = getDefaultOutputFileName(nodesToExport.iterator().next().getParentNode()); - JFileChooser fileChooser = new JFileChooser(); + JFileChooser fileChooser = chooserHelper.getChooser(); fileChooser.setCurrentDirectory(new File(getExportDirectory(Case.getCurrentCaseThrows()))); fileChooser.setSelectedFile(new File(fileName)); fileChooser.setFileFilter(new FileNameExtensionFilter("csv file", "csv")); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index 0cfbd7d5e5..4af306e58d 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.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"); @@ -33,6 +33,7 @@ import org.netbeans.spi.options.OptionsPanelController; import org.sleuthkit.autopsy.casemodule.GeneralFilter; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; /** * An options panel for the user to create, edit, and delete associations for @@ -42,9 +43,13 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil; @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel implements OptionsPanel { - private ExternalViewerGlobalSettingsTableModel tableModel; + private static final long serialVersionUID = 1L; - public ExternalViewerGlobalSettingsPanel() { + private ExternalViewerGlobalSettingsTableModel tableModel; + + private final JFileChooserHelper chooserHelper = JFileChooserHelper.getHelper(); + + ExternalViewerGlobalSettingsPanel() { this(new ExternalViewerGlobalSettingsTableModel(new String[] { "Mime type/Extension", "Application"})); } @@ -52,7 +57,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme /** * Creates new form ExternalViewerGlobalSettingsPanel */ - public ExternalViewerGlobalSettingsPanel(ExternalViewerGlobalSettingsTableModel tableModel) { + ExternalViewerGlobalSettingsPanel(ExternalViewerGlobalSettingsTableModel tableModel) { initComponents(); this.tableModel = tableModel; customizeComponents(tableModel); @@ -335,7 +340,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme }//GEN-LAST:event_deleteRuleButtonActionPerformed private void browseHxDDirectoryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseHxDDirectoryActionPerformed - JFileChooser fileWindow = new JFileChooser(); + JFileChooser fileWindow = chooserHelper.getChooser(); fileWindow.setFileSelectionMode(JFileChooser.FILES_ONLY); GeneralFilter exeFilter = new GeneralFilter(GeneralFilter.EXECUTABLE_EXTS, GeneralFilter.EXECUTABLE_DESC); File HxDPathFile = new File(HxDPath.getText()); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java index 5bdec7daa6..3ef6a79f21 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2019 Basis Technology Corp. + * Copyright 2013-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -42,6 +42,7 @@ import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; import org.sleuthkit.datamodel.AbstractFile; /** @@ -51,6 +52,9 @@ public class ExtractActionHelper { private final Logger logger = Logger.getLogger(ExtractActionHelper.class.getName()); private String userDefinedExportPath; + + private final JFileChooserHelper extractFileHelper = JFileChooserHelper.getHelper(); + private final JFileChooserHelper extractFilesHelper = JFileChooserHelper.getHelper(); /** * Extract the specified collection of files with an event specified for @@ -89,7 +93,7 @@ public class ExtractActionHelper { logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS return; } - JFileChooser fileChooser = new JFileChooser(); + JFileChooser fileChooser = extractFileHelper.getChooser(); fileChooser.setCurrentDirectory(new File(getExportDirectory(openCase))); // If there is an attribute name, change the ":". Otherwise the extracted file will be hidden fileChooser.setSelectedFile(new File(FileUtil.escapeFileName(selectedFile.getName()))); @@ -117,7 +121,7 @@ public class ExtractActionHelper { logger.log(Level.INFO, "Exception while getting open case.", ex); //NON-NLS return; } - JFileChooser folderChooser = new JFileChooser(); + JFileChooser folderChooser = extractFilesHelper.getChooser(); folderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); folderChooser.setCurrentDirectory(new File(getExportDirectory(openCase))); if (folderChooser.showSaveDialog((Component) event.getSource()) == JFileChooser.APPROVE_OPTION) { diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationSettingsPanel.java index 6043ff1a46..3e97344db5 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationSettingsPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,6 +35,7 @@ import org.sleuthkit.autopsy.casemodule.GeneralFilter; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; /** * A panel to allow the user to set the custom properties of the geolocation @@ -46,6 +47,8 @@ final class GeolocationSettingsPanel extends javax.swing.JPanel implements Optio private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(GeolocationSettingsPanel.class.getName()); + + private static final JFileChooserHelper chooserHelper = JFileChooserHelper.getHelper(); /** * Creates new GeolocationSettingsPanel @@ -313,7 +316,7 @@ final class GeolocationSettingsPanel extends javax.swing.JPanel implements Optio }// //GEN-END:initComponents private void zipFileBrowseBntActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zipFileBrowseBntActionPerformed - JFileChooser fileWindow = new JFileChooser(); + JFileChooser fileWindow = chooserHelper.getChooser(); fileWindow.setFileSelectionMode(JFileChooser.FILES_ONLY); GeneralFilter fileFilter = new GeneralFilter(Arrays.asList(".zip"), "Zips (*.zip)"); //NON-NLS fileWindow.setDragEnabled(false); @@ -374,7 +377,7 @@ final class GeolocationSettingsPanel extends javax.swing.JPanel implements Optio }//GEN-LAST:event_mbtilesRBtnActionPerformed private void mbtilesBrowseBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mbtilesBrowseBtnActionPerformed - JFileChooser fileWindow = new JFileChooser(); + JFileChooser fileWindow = chooserHelper.getChooser(); fileWindow.setFileSelectionMode(JFileChooser.FILES_ONLY); GeneralFilter fileFilter = new GeneralFilter(Arrays.asList(".mbtiles"), "MBTiles (*.mbtiles)"); //NON-NLS fileWindow.setDragEnabled(false); diff --git a/Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserHelper.java b/Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserHelper.java new file mode 100755 index 0000000000..3d7cdb78b8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserHelper.java @@ -0,0 +1,87 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.guicomponeontutils; + +import java.awt.Cursor; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; +import javax.swing.JFileChooser; +import org.openide.windows.WindowManager; + +/** + * Helper class that will initialize JFileChooser instances in background threads. + * + * On windows JFileChooser can take a long time to initialize. This helper class + * takes the work of initializing the JFileChooser off of the EDT so that in + * theory the when the chooser is needed initialized and ready to be displayed + * to the user. + * + * https://stackoverflow.com/questions/49792375/jfilechooser-is-very-slow-when-using-windows-look-and-feel + */ +public final class JFileChooserHelper { + private final FutureTask futureFileChooser = new FutureTask<>(JFileChooser::new); + private JFileChooser chooser; + + /** + * Get a helper instance. + * + * @return + */ + public static JFileChooserHelper getHelper() { + return new JFileChooserHelper(); + } + + /** + * Create a new instance of the helper class. The constructor will + * kick of an executor to that will execute the task of initializing the + * JFileChooser. + */ + private JFileChooserHelper() { + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.execute(futureFileChooser); + } + + /** + * Return and instance of JFileChooser to the caller. + * + * This call may block the EDT if the JFileChooser initialization has not + * completed. + * + * @return + */ + public JFileChooser getChooser() { + if (chooser == null) { + // In case this takes a moment show the wait cursor. + WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + try { + // get() will only return when the initilization of the + // JFileChooser has completed. + chooser = futureFileChooser.get(); + } catch (InterruptedException | ExecutionException ex) { + // If an exception occured create a new instance of JFileChooser. + chooser = new JFileChooser(); + } + WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + + return chooser; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java index 81fbd99d69..f52c2aaf77 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018 Basis Technology Corp. + * Copyright 2018-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -61,6 +61,7 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; /** * Dashboard for viewing metrics and controlling the health monitor. @@ -86,6 +87,8 @@ public class HealthMonitorDashboard { private JDialog dialog = null; private final Container parentWindow; + private final JFileChooserHelper chooserHelper; + /** * Create an instance of the dashboard. * Call display() after creation to show the dashboard. @@ -95,6 +98,7 @@ public class HealthMonitorDashboard { timingData = new HashMap<>(); userData = new ArrayList<>(); parentWindow = parent; + chooserHelper = JFileChooserHelper.getHelper(); } /** @@ -495,7 +499,7 @@ public class HealthMonitorDashboard { reportButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { - JFileChooser reportFileChooser = new JFileChooser(); + JFileChooser reportFileChooser = chooserHelper.getChooser(); reportFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); reportFileChooser.setCurrentDirectory(new File(UserPreferences.getHealthMonitorReportPath())); final DateFormat csvTimestampFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java index a5fdfd3bfc..7cc36dfad3 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java @@ -1,7 +1,7 @@ /* * Autopsy * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -50,6 +50,7 @@ import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; import org.sleuthkit.autopsy.logicalimager.dsp.DriveListUtils; /** @@ -63,6 +64,7 @@ final class ConfigVisualPanel1 extends JPanel { private static final String DEFAULT_CONFIG_FILE_NAME = "logical-imager-config.json"; private static final String UPDATE_UI_EVENT_NAME = "UPDATE_UI"; private String configFilename; + private final JFileChooserHelper chooserHelper; /** * Creates new form ConfigVisualPanel1 @@ -74,6 +76,7 @@ final class ConfigVisualPanel1 extends JPanel { refreshDriveList(); updateControls(); }); + chooserHelper = JFileChooserHelper.getHelper(); } @NbBundle.Messages({ @@ -332,7 +335,7 @@ final class ConfigVisualPanel1 extends JPanel { "ConfigVisualPanel1.configurationError=Configuration error",}) private void chooseFile(String title) { final String jsonExt = ".json"; // NON-NLS - JFileChooser fileChooser = new JFileChooser(); + JFileChooser fileChooser = chooserHelper.getChooser(); fileChooser.setDialogTitle(title); fileChooser.setDragEnabled(false); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java index 6a1198ea63..7142e04781 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java @@ -1,7 +1,7 @@ /* * Autopsy * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -44,6 +44,7 @@ import javax.swing.table.TableColumn; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; /** * Panel for adding an logical image file from drive letters. Allows the user to @@ -64,10 +65,10 @@ final class LogicalImagerPanel extends JPanel implements DocumentListener { private static final int NUMBER_OF_VISIBLE_COLUMNS = 2; private static final String[] EMPTY_LIST_DATA = {}; - private final JFileChooser fileChooser = new JFileChooser(); private final Pattern regex = Pattern.compile("Logical_Imager_(.+)_(\\d{4})(\\d{2})(\\d{2})_(\\d{2})_(\\d{2})_(\\d{2})"); private Path manualImageDirPath; private DefaultTableModel imageTableModel; + private final JFileChooserHelper chooserHelper; /** * Creates new form LogicalImagerPanel @@ -80,6 +81,7 @@ final class LogicalImagerPanel extends JPanel implements DocumentListener { configureImageTable(); jScrollPane1.setBorder(null); clearImageTable(); + chooserHelper = JFileChooserHelper.getHelper(); } /** @@ -316,6 +318,7 @@ final class LogicalImagerPanel extends JPanel implements DocumentListener { "LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS" }) private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed + JFileChooser fileChooser = chooserHelper.getChooser(); imageTable.clearSelection(); manualImageDirPath = null; setErrorMessage(NO_IMAGE_SELECTED); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java index 63a8c84e93..d2252aff94 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2020 Basis Technology Corp. + * Copyright 2013-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,15 +18,21 @@ */ package org.sleuthkit.autopsy.modules.hashdatabase; +import java.awt.Cursor; import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; import java.util.logging.Level; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; import org.apache.commons.io.FilenameUtils; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; @@ -56,12 +62,14 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { private static final String DEFAULT_FILE_NAME = NbBundle .getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.defaultFileName"); + private static final long serialVersionUID = 1L; private JFileChooser fileChooser = null; private HashDb newHashDb = null; private final static String LAST_FILE_PATH_KEY = "HashDbCreate_Path"; private CentralRepoOrganization selectedOrg = null; private List orgs = null; static final String HASH_DATABASE_DIR_NAME = "HashDatabases"; + private final FutureTask futureFileChooser = new FutureTask<>(CustomFileChooser::new); /** * Displays a dialog that allows a user to create a new hash database and @@ -70,10 +78,12 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { */ HashDbCreateDatabaseDialog() { super((JFrame) WindowManager.getDefault().getMainWindow(), NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.createHashDbMsg"), true); - initFileChooser(); initComponents(); enableComponents(); display(); + + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.execute(futureFileChooser); } /** @@ -84,43 +94,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { HashDb getHashDatabase() { return newHashDb; } - - private void initFileChooser() { - fileChooser = new JFileChooser() { - @Override - public void approveSelection() { - File selectedFile = getSelectedFile(); - if (!FilenameUtils.getExtension(selectedFile.getName()).equalsIgnoreCase(HashDbManager.getHashDatabaseFileExtension())) { - if (JOptionPane.showConfirmDialog(this, - NbBundle.getMessage(this.getClass(), - "HashDbCreateDatabaseDialog.hashDbMustHaveFileExtensionMsg", - HashDbManager.getHashDatabaseFileExtension()), - NbBundle.getMessage(this.getClass(), - "HashDbCreateDatabaseDialog.fileNameErr"), - JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) { - cancelSelection(); - } - return; - } - if (selectedFile.exists()) { - if (JOptionPane.showConfirmDialog(this, - NbBundle.getMessage(this.getClass(), - "HashDbCreateDatabaseDialog.fileNameAlreadyExistsMsg"), - NbBundle.getMessage(this.getClass(), - "HashDbCreateDatabaseDialog.fileExistsErr"), - JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) { - cancelSelection(); - } - return; - } - super.approveSelection(); - } - }; - fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - fileChooser.setDragEnabled(false); - fileChooser.setMultiSelectionEnabled(false); - } - + private void display() { setLocationRelativeTo(getOwner()); setVisible(true); @@ -169,6 +143,43 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { Logger.getLogger(ImportCentralRepoDbProgressDialog.class.getName()).log(Level.SEVERE, "Failure loading organizations", ex); } } + + /** + * Customize the JFileChooser. + */ + private class CustomFileChooser extends JFileChooser { + + private static final long serialVersionUID = 1L; + + @Override + public void approveSelection() { + File selectedFile = getSelectedFile(); + if (!FilenameUtils.getExtension(selectedFile.getName()).equalsIgnoreCase(HashDbManager.getHashDatabaseFileExtension())) { + if (JOptionPane.showConfirmDialog(this, + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.hashDbMustHaveFileExtensionMsg", + HashDbManager.getHashDatabaseFileExtension()), + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.fileNameErr"), + JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) { + cancelSelection(); + } + return; + } + if (selectedFile.exists()) { + if (JOptionPane.showConfirmDialog(this, + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.fileNameAlreadyExistsMsg"), + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.fileExistsErr"), + JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) { + cancelSelection(); + } + return; + } + super.approveSelection(); + } + } /** * This method is called from within the constructor to initialize the form. @@ -435,6 +446,22 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { path.append(File.separator).append(DEFAULT_FILE_NAME); } path.append(".").append(HashDbManager.getHashDatabaseFileExtension()); + + if(fileChooser == null) { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + try { + fileChooser = futureFileChooser.get(); + } catch (InterruptedException | ExecutionException ex) { + fileChooser = new CustomFileChooser(); + } + + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + fileChooser.setDragEnabled(false); + fileChooser.setMultiSelectionEnabled(false); + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + + fileChooser.setSelectedFile(new File(path.toString())); if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { File databaseFile = fileChooser.getSelectedFile(); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index c854cb165d..55051cd3f0 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2020 Basis Technology Corp. + * Copyright 2013-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -43,6 +43,7 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDbManagerExc import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.featureaccess.FeatureAccessUtils; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; /** * Instances of this class allow a user to select an existing hash database and @@ -52,12 +53,13 @@ import org.sleuthkit.autopsy.featureaccess.FeatureAccessUtils; @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives final class HashDbImportDatabaseDialog extends javax.swing.JDialog { - private final JFileChooser fileChooser; + private JFileChooser fileChooser; private String selectedFilePath = ""; private HashDb selectedHashDb = null; private final static String LAST_FILE_PATH_KEY = "HashDbImport_Path"; private CentralRepoOrganization selectedOrg = null; private List orgs = null; + private final JFileChooserHelper chooserHelper; /** * Displays a dialog that allows a user to select an existing hash database @@ -68,10 +70,9 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { super((JFrame) WindowManager.getDefault().getMainWindow(), NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.importHashDbMsg"), true); - this.fileChooser = new JFileChooser(); + chooserHelper = JFileChooserHelper.getHelper(); initComponents(); enableComponents(); - initFileChooser(); display(); } @@ -84,16 +85,6 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { return selectedHashDb; } - private void initFileChooser() { - fileChooser.setDragEnabled(false); - fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - String[] EXTENSION = new String[]{"txt", "kdb", "idx", "hash", "Hash", "hsh"}; //NON-NLS - FileNameExtensionFilter filter = new FileNameExtensionFilter( - NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.fileNameExtFilter.text"), EXTENSION); - fileChooser.setFileFilter(filter); - fileChooser.setMultiSelectionEnabled(false); - } - private void display() { setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); setVisible(true); @@ -421,6 +412,17 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { }// //GEN-END:initComponents private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed + if(fileChooser == null) { + fileChooser = chooserHelper.getChooser(); + fileChooser.setDragEnabled(false); + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + String[] EXTENSION = new String[]{"txt", "kdb", "idx", "hash", "Hash", "hsh"}; //NON-NLS + FileNameExtensionFilter filter = new FileNameExtensionFilter( + NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.fileNameExtFilter.text"), EXTENSION); + fileChooser.setFileFilter(filter); + fileChooser.setMultiSelectionEnabled(false); + } + String lastBaseDirectory = Paths.get(PlatformUtil.getUserConfigDirectory(), HashDbCreateDatabaseDialog.HASH_DATABASE_DIR_NAME).toString(); if (ModuleSettings.settingExists(ModuleSettings.MAIN_SETTINGS, LAST_FILE_PATH_KEY)) { lastBaseDirectory = ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, LAST_FILE_PATH_KEY); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index 40544c5485..1ff46b95c8 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.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"); @@ -65,6 +65,7 @@ import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; /** @@ -93,6 +94,8 @@ public class HashDbManager implements PropertyChangeListener { private static final String DB_NAME_PARAM = "dbName"; private static final String KNOWN_STATUS_PARAM = "knownStatus"; private static final Pattern OFFICIAL_FILENAME = Pattern.compile("(?<" + DB_NAME_PARAM + ">.+?)\\.(?<" + KNOWN_STATUS_PARAM + ">.+?)\\." + KDB_EXT); + + private final JFileChooserHelper chooserHelper; private static final FilenameFilter DEFAULT_KDB_FILTER = new FilenameFilter() { @Override @@ -136,6 +139,7 @@ public class HashDbManager implements PropertyChangeListener { } private HashDbManager() { + chooserHelper = JFileChooserHelper.getHelper(); loadHashsetsConfiguration(); } @@ -870,7 +874,7 @@ public class HashDbManager implements PropertyChangeListener { private String searchForFile() { String filePath = null; - JFileChooser fc = new JFileChooser(); + JFileChooser fc = chooserHelper.getChooser(); fc.setDragEnabled(false); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); String[] EXTENSION = new String[]{"txt", "idx", "hash", "Hash", "kdb"}; //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModuleConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModuleConfigPanel.java index 5a7d5b9b35..bb23320c87 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModuleConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModuleConfigPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2018 Basis Technology Corp. + * Copyright 2013-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.report.modules.stix; import java.io.File; import javax.swing.JFileChooser; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; /** * Configuration panel for STIX report generation. @@ -29,6 +30,7 @@ public class STIXReportModuleConfigPanel extends javax.swing.JPanel { String stixFile = null; boolean showAllResults; + private final JFileChooserHelper chooserHelper; /** * Creates new form STIXReportModuleConfigPanel @@ -37,6 +39,7 @@ public class STIXReportModuleConfigPanel extends javax.swing.JPanel { initComponents(); showAllResults = false; jCheckBox1.setSelected(false); + chooserHelper = JFileChooserHelper.getHelper(); } void setConfiguration(STIXReportModuleSettings settings) { @@ -138,7 +141,7 @@ public class STIXReportModuleConfigPanel extends javax.swing.JPanel { private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed - JFileChooser fileChooser = new JFileChooser(); + JFileChooser fileChooser = chooserHelper.getChooser(); fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); File currentSelection = new File(jStixFileTextField.getText()); From 9ad3567c7ce1a152f3ba59560ca7d236fc365553 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Tue, 10 Aug 2021 14:55:31 -0400 Subject: [PATCH 26/76] Minor --- .../datasourcesummaryexport/ExportIngestHistory.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportIngestHistory.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportIngestHistory.java index 95c38f2162..4c355f10aa 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportIngestHistory.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportIngestHistory.java @@ -67,10 +67,10 @@ class ExportIngestHistory { /** * Main constructor. * - * @param startTime The ingest start time. - * @param endTime The ingest stop time. - * @param status The ingest status. - * @param ingestModule The ingest module. + * @param startTime The ingest start time. + * @param endTime The ingest stop time. + * @param status The ingest status. + * @param ingestModule The ingest module. * @param ingestModuleVersion The ingest module version. */ IngestJobEntry(Date startTime, Date endTime, String status, String ingestModule, String ingestModuleVersion) { @@ -144,6 +144,7 @@ class ExportIngestHistory { * Retrieves data for a date cell. * * @param date The date. + * * @return The data cell to be used in the excel export. */ private static DefaultCellModel getDateCell(Date date) { @@ -155,6 +156,7 @@ class ExportIngestHistory { * Retrieves all the ingest job modules and versions for a job. * * @param job The ingest job. + * * @return All of the corresponding entries sorted by module name. */ private static List getEntries(IngestJobInfo job) { @@ -187,6 +189,7 @@ class ExportIngestHistory { * to null. * * @param list The list of entries for an ingest job. + * * @return The stream of entries to be displayed. */ private static Stream showFirstRowOnly(List list) { @@ -206,6 +209,7 @@ class ExportIngestHistory { * Returns a list of sheets to be exported for the Ingest History tab. * * @param dataSource The data source. + * * @return The list of sheets to be included in an export. */ static List getExports(DataSource dataSource) { From 323f5913234a8d16dce2b1fdcaadc3ee9e518442 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 11 Aug 2021 10:38:41 -0400 Subject: [PATCH 27/76] Removed excel related parameters from datasourcesummary package --- .../ui/RecentFilesPanel.java | 2 +- .../ui/SizeRepresentationUtil.java | 30 ++++++------------- .../ui/UserActivityPanel.java | 4 +-- .../uiutils/DefaultCellModel.java | 22 ++------------ 4 files changed, 14 insertions(+), 44 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index e2f38b38b6..87e934dcc1 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -141,7 +141,7 @@ public final class RecentFilesPanel extends BaseDataSourceSummaryPanel { private Function> getDateFunct() { return (T lastAccessed) -> { Function dateParser = (dt) -> dt == null ? "" : DATETIME_FORMAT.format(dt); - return new DefaultCellModel<>(new Date(lastAccessed.getDateAsLong() * 1000), dateParser, DATETIME_FORMAT_STR) + return new DefaultCellModel<>(new Date(lastAccessed.getDateAsLong() * 1000), dateParser) .setPopupMenuRetriever(getPopupFunct(lastAccessed)); }; } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SizeRepresentationUtil.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SizeRepresentationUtil.java index 3c48da8db0..b1b0433588 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SizeRepresentationUtil.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SizeRepresentationUtil.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -43,28 +43,23 @@ public final class SizeRepresentationUtil { "SizeRepresentationUtil_units_petabytes=PB" }) enum SizeUnit { - BYTES(Bundle.SizeRepresentationUtil_units_bytes(), "#", 0), - KB(Bundle.SizeRepresentationUtil_units_kilobytes(), "#,##0.00,", 1), - MB(Bundle.SizeRepresentationUtil_units_megabytes(), "#,##0.00,,", 2), - GB(Bundle.SizeRepresentationUtil_units_gigabytes(), "#,##0.00,,,", 3), - TB(Bundle.SizeRepresentationUtil_units_terabytes(), "#,##0.00,,,,", 4), - PB(Bundle.SizeRepresentationUtil_units_petabytes(), "#,##0.00,,,,,", 5); + BYTES(Bundle.SizeRepresentationUtil_units_bytes(), 0), + KB(Bundle.SizeRepresentationUtil_units_kilobytes(), 1), + MB(Bundle.SizeRepresentationUtil_units_megabytes(), 2), + GB(Bundle.SizeRepresentationUtil_units_gigabytes(), 3), + TB(Bundle.SizeRepresentationUtil_units_terabytes(), 4), + PB(Bundle.SizeRepresentationUtil_units_petabytes(), 5); private final String suffix; - private final String excelFormatString; // ELTODO private final long divisor; /** * Main constructor. * @param suffix The string suffix to use for size unit. - * @param excelFormatString The excel format string to use for this size unit. * @param power The power of 1000 of bytes for this size unit. */ - SizeUnit(String suffix, String excelFormatString, int power) { + SizeUnit(String suffix, int power) { this.suffix = suffix; - - // based on https://www.mrexcel.com/board/threads/how-do-i-format-cells-to-show-gb-mb-kb.140135/ - this.excelFormatString = String.format("%s \"%s\"", excelFormatString, suffix); this.divisor = (long) Math.pow(SIZE_CONVERSION_CONSTANT, power); } @@ -75,13 +70,6 @@ public final class SizeRepresentationUtil { return suffix; } - /** - * @return The excel format string to use for this size unit. - */ - public String getExcelFormatString() { - return excelFormatString; - } - /** * @return The divisor to convert from bytes to this unit. */ @@ -171,7 +159,7 @@ public final class SizeRepresentationUtil { unit = SizeUnit.BYTES; } - return new DefaultCellModel(bytes, SizeRepresentationUtil::getSizeString, unit.getExcelFormatString()); + return new DefaultCellModel(bytes, SizeRepresentationUtil::getSizeString); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index c6d13260b9..9a6cf1ee42 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -316,7 +316,7 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { private Function> getDateFunct() { return (T lastAccessed) -> { Function dateParser = (dt) -> dt == null ? "" : DATETIME_FORMAT.format(dt); - return new DefaultCellModel<>(lastAccessed.getLastAccessed(), dateParser, DATETIME_FORMAT_STR) + return new DefaultCellModel<>(lastAccessed.getLastAccessed(), dateParser) .setPopupMenu(getPopup(lastAccessed)); }; } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultCellModel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultCellModel.java index 3d2e4e6a5a..81c176954a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultCellModel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DefaultCellModel.java @@ -35,7 +35,6 @@ public class DefaultCellModel implements GuiCellModel { private CellModel.HorizontalAlign horizontalAlignment; private List popupMenu; private Supplier> menuItemSupplier; - private final String excelFormatString; // ELTODO /** * Main constructor. @@ -43,18 +42,7 @@ public class DefaultCellModel implements GuiCellModel { * @param data The data to be displayed in the cell. */ public DefaultCellModel(T data) { - this(data, null, null); - } - - /** - * Constructor. - * - * @param data The data to be displayed in the cell. - * @param stringConverter The means of converting that data to a string or - * null to use .toString method on object. - */ - public DefaultCellModel(T data, Function stringConverter) { - this(data, stringConverter, null); + this(data, null); } /** @@ -63,15 +51,9 @@ public class DefaultCellModel implements GuiCellModel { * @param data The data to be displayed in the cell. * @param stringConverter The means of converting that data to a string or * null to use .toString method on object. - * @param excelFormatString The apache poi excel format string to use with - * the data. - * - * NOTE: Only certain data types can be exported. See - * ExcelTableExport.createCell() for types. */ - public DefaultCellModel(T data, Function stringConverter, String excelFormatString) { + public DefaultCellModel(T data, Function stringConverter) { this.data = data; - this.excelFormatString = excelFormatString; if (stringConverter == null) { text = this.data == null ? "" : this.data.toString(); From 0c9892437a00cc65e401313db56b6d5db8119d3a Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 11 Aug 2021 10:50:52 -0400 Subject: [PATCH 28/76] Refactoring --- .../autopsy/contentutils/PastCasesSummary.java | 4 ++-- .../datasourcesummary/ui/SizeRepresentationUtil.java | 10 ++-------- .../SizeRepresentationUtil.java | 5 ++--- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/PastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/contentutils/PastCasesSummary.java index d50f2b44d5..c82bb2b2b8 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/PastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/contentutils/PastCasesSummary.java @@ -86,14 +86,14 @@ public class PastCasesSummary { * @return Data for the cases with same id table. */ public List> getSameIdsResults() { - return sameIdsResults; + return Collections.unmodifiableList(sameIdsResults); } /** * @return Data for the tagged notable table. */ public List> getTaggedNotable() { - return taggedNotable; + return Collections.unmodifiableList(taggedNotable); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SizeRepresentationUtil.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SizeRepresentationUtil.java index b1b0433588..65f7402b04 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SizeRepresentationUtil.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SizeRepresentationUtil.java @@ -100,8 +100,7 @@ public final class SizeRepresentationUtil { return SizeUnit.values()[0]; } - for (int unitsIndex = 0; unitsIndex < SizeUnit.values().length; unitsIndex++) { - SizeUnit unit = SizeUnit.values()[unitsIndex]; + for (SizeUnit unit : SizeUnit.values()) { long result = size / unit.getDivisor(); if (result < SIZE_CONVERSION_CONSTANT) { return unit; @@ -154,12 +153,7 @@ public final class SizeRepresentationUtil { if (bytes == null) { return new DefaultCellModel<>(""); } else { - SizeUnit unit = SizeRepresentationUtil.getSizeUnit(bytes); - if (unit == null) { - unit = SizeUnit.BYTES; - } - - return new DefaultCellModel(bytes, SizeRepresentationUtil::getSizeString); + return new DefaultCellModel<>(bytes, SizeRepresentationUtil::getSizeString); } } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/SizeRepresentationUtil.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/SizeRepresentationUtil.java index 664401c684..7c9018c9ff 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/SizeRepresentationUtil.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/SizeRepresentationUtil.java @@ -111,8 +111,7 @@ final class SizeRepresentationUtil { return SizeUnit.values()[0]; } - for (int unitsIndex = 0; unitsIndex < SizeUnit.values().length; unitsIndex++) { - SizeUnit unit = SizeUnit.values()[unitsIndex]; + for (SizeUnit unit : SizeUnit.values()) { long result = size / unit.getDivisor(); if (result < SIZE_CONVERSION_CONSTANT) { return unit; @@ -170,7 +169,7 @@ final class SizeRepresentationUtil { unit = SizeUnit.BYTES; } - return new DefaultCellModel(bytes, SizeRepresentationUtil::getSizeString, unit.getExcelFormatString()); + return new DefaultCellModel<>(bytes, SizeRepresentationUtil::getSizeString, unit.getExcelFormatString()); } } From 89e23972da0c101e8bbfae3aedcea812d48fc3e9 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 12 Aug 2021 17:38:39 -0400 Subject: [PATCH 29/76] Changed class name and handled review comments --- .../autopsy/casemodule/CaseOpenAction.java | 6 +- .../autopsy/casemodule/ImageFilePanel.java | 4 +- .../autopsy/casemodule/LocalDiskPanel.java | 6 +- .../casemodule/MissingImageDialog.java | 6 +- .../casemodule/NewCaseVisualPanel1.java | 4 +- .../autopsy/contentviewers/PListViewer.java | 4 +- .../autopsy/contentviewers/SQLiteViewer.java | 4 +- .../corecomponents/AutopsyOptionsPanel.java | 8 +- .../datasourceprocessors/RawDSInputPanel.java | 4 +- .../XRYDataSourceProcessorConfigPanel.java | 4 +- .../AddExternalViewerRulePanel.java | 4 +- .../directorytree/ExportCSVAction.java | 4 +- .../ExternalViewerGlobalSettingsPanel.java | 4 +- .../directorytree/ExtractUnallocAction.java | 27 +--- .../actionhelpers/ExtractActionHelper.java | 6 +- .../geolocation/GeolocationSettingsPanel.java | 4 +- .../JFileChooserFactory.java | 146 ++++++++++++++++++ .../JFileChooserHelper.java | 87 ----------- .../healthmonitor/HealthMonitorDashboard.java | 6 +- .../configuration/ConfigVisualPanel1.java | 6 +- .../logicalimager/dsp/LogicalImagerPanel.java | 6 +- .../HashDbCreateDatabaseDialog.java | 22 +-- .../HashDbImportDatabaseDialog.java | 6 +- .../modules/hashdatabase/HashDbManager.java | 6 +- .../stix/STIXReportModuleConfigPanel.java | 6 +- 25 files changed, 213 insertions(+), 177 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserFactory.java delete mode 100755 Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserHelper.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java index c32cf6f87f..81143091d4 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java @@ -43,7 +43,7 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.Version; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; /** * The action associated with the Case/Open Case menu item via the layer.xml @@ -65,7 +65,7 @@ public final class CaseOpenAction extends CallableSystemAction implements Action private static final Logger LOGGER = Logger.getLogger(CaseOpenAction.class.getName()); private final FileFilter caseMetadataFileFilter; - private final JFileChooserHelper fileChooserHelper; + private final JFileChooserFactory fileChooserHelper; /** * Constructs the action associated with the Case/Open Case menu item via @@ -75,7 +75,7 @@ public final class CaseOpenAction extends CallableSystemAction implements Action */ public CaseOpenAction() { caseMetadataFileFilter = new FileNameExtensionFilter(NbBundle.getMessage(CaseOpenAction.class, "CaseOpenAction.autFilter.title", Version.getName(), CaseMetadata.getFileExtension()), CaseMetadata.getFileExtension().substring(1)); - fileChooserHelper = JFileChooserHelper.getHelper(); + fileChooserHelper = new JFileChooserFactory(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 9f2a313ae3..20770a2c00 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.coreutils.DriveUtils; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; import org.sleuthkit.datamodel.HashUtility; /** @@ -49,7 +49,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { private static final long serialVersionUID = 1L; private static final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH"; //NON-NLS private static final String[] SECTOR_SIZE_CHOICES = {"Auto Detect", "512", "1024", "2048", "4096"}; - private final JFileChooserHelper fileChooserHelper = JFileChooserHelper.getHelper(); + private final JFileChooserFactory fileChooserHelper = new JFileChooserFactory(); private JFileChooser fileChooser; private final String contextName; private final List fileChooserFilters; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java index 60f3bd4156..4759ce1177 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java @@ -32,7 +32,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings; /** @@ -60,7 +60,7 @@ final class LocalDiskPanel extends JPanel { private LocalDisk localDisk; private boolean enableNext = false; private JFileChooser fc; - private final JFileChooserHelper chooserHelper; + private final JFileChooserFactory chooserHelper; /** * Creates new form LocalDiskPanel @@ -70,7 +70,7 @@ final class LocalDiskPanel extends JPanel { customInit(); createTimeZoneList(); createSectorSizeList(); - chooserHelper = JFileChooserHelper.getHelper(); + chooserHelper = new JFileChooserFactory(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java index 2e4f772baf..ffcbc7792f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java @@ -32,7 +32,7 @@ import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.DriveUtils; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -47,7 +47,7 @@ class MissingImageDialog extends javax.swing.JDialog { SleuthkitCase db; private JFileChooser fileChooser; - private final JFileChooserHelper chooserHelper; + private final JFileChooserFactory chooserHelper; /** * Instantiate a MissingImageDialog. @@ -61,7 +61,7 @@ class MissingImageDialog extends javax.swing.JDialog { this.db = db; initComponents(); - chooserHelper = JFileChooserHelper.getHelper(); + chooserHelper = new JFileChooserFactory(); selectButton.setEnabled(false); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java index bb518a92df..aa0ec43316 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java @@ -30,7 +30,7 @@ import javax.swing.event.DocumentListener; import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; /** * The JPanel for the first page of the new case wizard. @@ -38,7 +38,7 @@ import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives final class NewCaseVisualPanel1 extends JPanel implements DocumentListener { - private final JFileChooserHelper fileChooserHelper = JFileChooserHelper.getHelper(); + private final JFileChooserFactory fileChooserHelper = new JFileChooserFactory(); private final NewCaseWizardPanel1 wizPanel; /** diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index 3547c5d8b2..4d2aae6760 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -56,7 +56,7 @@ import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; import org.sleuthkit.datamodel.TskCoreException; import org.xml.sax.SAXException; @@ -77,7 +77,7 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer private NSObject rootDict; - private final JFileChooserHelper fileChooserHelper = JFileChooserHelper.getHelper(); + private final JFileChooserFactory fileChooserHelper = new JFileChooserFactory(); /** * Creates new form PListViewer diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java index b4e6fdcf05..61066c0137 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java @@ -49,7 +49,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.autopsy.coreutils.SQLiteTableReader; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; /** * A file content viewer for SQLite database files. @@ -76,7 +76,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { SwingWorker worker; - private final JFileChooserHelper chooserHelper = JFileChooserHelper.getHelper(); + private final JFileChooserFactory chooserHelper = new JFileChooserFactory(); /** * Constructs a file content viewer for SQLite database files. diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java index 91413334cb..6470161459 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java @@ -55,7 +55,7 @@ import org.sleuthkit.autopsy.machinesettings.UserMachinePreferencesException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.Version; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; import org.sleuthkit.autopsy.machinesettings.UserMachinePreferences.TempDirChoice; import org.sleuthkit.autopsy.report.ReportBranding; @@ -97,9 +97,9 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { private final ReportBranding reportBranding; private JFileChooser heapFileChooser; - private final JFileChooserHelper logoChooserHelper = JFileChooserHelper.getHelper(); - private final JFileChooserHelper heapChooserHelper = JFileChooserHelper.getHelper(); - private final JFileChooserHelper tempChooserHelper = JFileChooserHelper.getHelper(); + private final JFileChooserFactory logoChooserHelper = new JFileChooserFactory(); + private final JFileChooserFactory heapChooserHelper = new JFileChooserFactory(); + private final JFileChooserFactory tempChooserHelper = new JFileChooserFactory(); /** * Instantiate the Autopsy options panel. diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java index 6646525997..80acf8a8a1 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java @@ -32,7 +32,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; /** * Allows examiner to supply a raw data source. @@ -43,7 +43,7 @@ final class RawDSInputPanel extends JPanel implements DocumentListener { private static final long serialVersionUID = 1L; //default private final String PROP_LASTINPUT_PATH = "LBL_LastInputFile_PATH"; private JFileChooser fc; - private JFileChooserHelper chooserHelper = JFileChooserHelper.getHelper(); + private JFileChooserFactory chooserHelper = new JFileChooserFactory(); // Externally supplied name is used to store settings private final String contextName; /** diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessorConfigPanel.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessorConfigPanel.java index 898e4cdef4..88c2c34bf3 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessorConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessorConfigPanel.java @@ -30,7 +30,7 @@ import javax.swing.JPanel; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.ModuleSettings; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; /** * Allows an examiner to configure the XRY Data source processor. @@ -50,7 +50,7 @@ final class XRYDataSourceProcessorConfigPanel extends JPanel { //panel will indicate when it is ready for an update. private final PropertyChangeSupport pcs; - private final JFileChooserHelper chooserHelper = JFileChooserHelper.getHelper(); + private final JFileChooserFactory chooserHelper = new JFileChooserFactory(); /** * Creates new form XRYDataSourceConfigPanel. diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/AddExternalViewerRulePanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/AddExternalViewerRulePanel.java index 34e1c24a3d..473270811e 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/AddExternalViewerRulePanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/AddExternalViewerRulePanel.java @@ -26,7 +26,7 @@ import javax.swing.event.DocumentListener; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.GeneralFilter; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; /** @@ -38,7 +38,7 @@ class AddExternalViewerRulePanel extends javax.swing.JPanel { private static final Logger logger = Logger.getLogger(AddExternalViewerRulePanel.class.getName()); private static final long serialVersionUID = 1L; private JFileChooser fc; - private final JFileChooserHelper chooserHelper = JFileChooserHelper.getHelper(); + private final JFileChooserFactory chooserHelper = new JFileChooserFactory(); private static final GeneralFilter exeFilter = new GeneralFilter(GeneralFilter.EXECUTABLE_EXTS, GeneralFilter.EXECUTABLE_DESC); enum EVENT { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java index 904b423343..e1c95361e5 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java @@ -51,7 +51,7 @@ import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFileProp import org.openide.nodes.Node; import org.openide.nodes.Node.PropertySet; import org.openide.nodes.Node.Property; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; /** * Exports CSV version of result nodes to a location selected by the user. @@ -70,7 +70,7 @@ public final class ExportCSVAction extends AbstractAction { // node in the array returns a reference to the same action object from Node.getActions(boolean). private static ExportCSVAction instance; - private static final JFileChooserHelper chooserHelper = JFileChooserHelper.getHelper(); + private static final JFileChooserFactory chooserHelper = new JFileChooserFactory(); /** * Get an instance of the Action. See above for why diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index 4af306e58d..b13a149fc6 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -33,7 +33,7 @@ import org.netbeans.spi.options.OptionsPanelController; import org.sleuthkit.autopsy.casemodule.GeneralFilter; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; /** * An options panel for the user to create, edit, and delete associations for @@ -47,7 +47,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme private ExternalViewerGlobalSettingsTableModel tableModel; - private final JFileChooserHelper chooserHelper = JFileChooserHelper.getHelper(); + private final JFileChooserFactory chooserHelper = new JFileChooserFactory(); ExternalViewerGlobalSettingsPanel() { this(new ExternalViewerGlobalSettingsTableModel(new String[] { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java index dcb55e5655..8b9f5af58d 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java @@ -33,9 +33,6 @@ import java.util.List; import java.util.Set; import java.util.HashSet; import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.FutureTask; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.JFileChooser; @@ -50,6 +47,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; import org.sleuthkit.datamodel.AbstractContent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; @@ -78,9 +76,7 @@ final class ExtractUnallocAction extends AbstractAction { private final Volume volume; private final Image image; - private final FutureTask futureFileChooser = new FutureTask<>(CustomFileChooser::new); - - private JFileChooser fileChooser = null; + private final JFileChooserFactory chooserFactory; /** * Create an instance of ExtractUnallocAction with a volume. @@ -90,7 +86,7 @@ final class ExtractUnallocAction extends AbstractAction { */ ExtractUnallocAction(String title, Volume volume) { this(title, null, volume); - + } /** @@ -110,9 +106,8 @@ final class ExtractUnallocAction extends AbstractAction { this.volume = null; this.image = image; - - ExecutorService executor = Executors.newSingleThreadExecutor(); - executor.execute(futureFileChooser); + + chooserFactory = new JFileChooserFactory(CustomFileChooser.class); } /** @@ -138,13 +133,7 @@ final class ExtractUnallocAction extends AbstractAction { return; } - if (fileChooser == null) { - try { - fileChooser = futureFileChooser.get(); - } catch (InterruptedException | ExecutionException ex) { - fileChooser = new CustomFileChooser(); - } - } + JFileChooser fileChooser = chooserFactory.getChooser(); fileChooser.setCurrentDirectory(new File(getExportDirectory(openCase))); if (JFileChooser.APPROVE_OPTION != fileChooser.showSaveDialog((Component) event.getSource())) { @@ -753,11 +742,11 @@ final class ExtractUnallocAction extends AbstractAction { } // A Custome JFileChooser for this Action Class. - private class CustomFileChooser extends JFileChooser { + public static class CustomFileChooser extends JFileChooser { private static final long serialVersionUID = 1L; - CustomFileChooser() { + public CustomFileChooser() { initalize(); } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java index 3ef6a79f21..1a9ae807f5 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java @@ -42,7 +42,7 @@ import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; import org.sleuthkit.datamodel.AbstractFile; /** @@ -53,8 +53,8 @@ public class ExtractActionHelper { private final Logger logger = Logger.getLogger(ExtractActionHelper.class.getName()); private String userDefinedExportPath; - private final JFileChooserHelper extractFileHelper = JFileChooserHelper.getHelper(); - private final JFileChooserHelper extractFilesHelper = JFileChooserHelper.getHelper(); + private final JFileChooserFactory extractFileHelper = new JFileChooserFactory(); + private final JFileChooserFactory extractFilesHelper = new JFileChooserFactory(); /** * Extract the specified collection of files with an event specified for diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationSettingsPanel.java index 3e97344db5..a7cab0fd25 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationSettingsPanel.java @@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.casemodule.GeneralFilter; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; /** * A panel to allow the user to set the custom properties of the geolocation @@ -48,7 +48,7 @@ final class GeolocationSettingsPanel extends javax.swing.JPanel implements Optio private static final Logger logger = Logger.getLogger(GeolocationSettingsPanel.class.getName()); - private static final JFileChooserHelper chooserHelper = JFileChooserHelper.getHelper(); + private static final JFileChooserFactory chooserHelper = new JFileChooserFactory(); /** * Creates new GeolocationSettingsPanel diff --git a/Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserFactory.java b/Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserFactory.java new file mode 100755 index 0000000000..d885b3b8a6 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserFactory.java @@ -0,0 +1,146 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.guicomponeontutils; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.awt.Cursor; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JFileChooser; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.coreutils.ThreadConfined; + +/** + * Factory class for initializing JFileChooser instances in a background thread. + * + * It is a known issue that on Windows a JFileChooser can take an indeterminate + * amount of time to initialize. Therefore when a JFileChooser is initialized on + * the EDT there is the potential for the UI to appear hung while initialization + * is occurring. + * + * Initializing a JFileChooser in a background thread should prevent the UI from + * hanging. Using this Factory class at component construction time should allow + * enough time for the JFileChooser to be initialized in the background before + * the UI user causes an event which will launch the JFileChooser. If the + * JFileChooser is not initialized prior to the event occurring, the EDT will be + * blocked , but the wait cursor will appear. + * + * https://stackoverflow.com/questions/49792375/jfilechooser-is-very-slow-when-using-windows-look-and-feel + */ +public final class JFileChooserFactory { + + private static final Logger logger = Logger.getLogger(JFileChooserFactory.class.getName()); + + private final FutureTask futureFileChooser; + private JFileChooser chooser; + + /** + * Create a new instance of the factory. The constructor will kick of an + * executor to that will execute the task of initializing the JFileChooser. + */ + public JFileChooserFactory() { + this(null); + } + + /** + * Create a new instance of the factory using a class that extends + * JFileChooser. The class default constructor will be called to initialize + * the class. + * + * The passed in Class must be public and its default constructor must be + * public. + * + * @param cls Class type to initialize. + */ + public JFileChooserFactory(Class cls) { + if (cls == null) { + futureFileChooser = new FutureTask<>(JFileChooser::new); + } else { + futureFileChooser = new FutureTask<>(new ChooserCallable(cls)); + } + + ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("JFileChooser-background-thread").build()); + executor.execute(futureFileChooser); + } + + /** + * Return and instance of JFileChooser to the caller. + * + * This call may block the EDT if the JFileChooser initialization has not + * completed. + * + * @return + */ + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) + public JFileChooser getChooser() { + if (chooser == null) { + // In case this takes a moment show the wait cursor. + try { + WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + try { + // get() will only return when the initilization of the + // JFileChooser has completed. + chooser = futureFileChooser.get(); + } catch (InterruptedException | ExecutionException ex) { + // An exception is generally not expected. On the off chance + // one does occur save the sisutation by created a new + // instance in the EDT. + // If an exception does occur + logger.log(Level.WARNING, "Failed to initialize JFileChooser in background thread."); + chooser = new JFileChooser(); + } + } finally { + WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + } + + return chooser; + } + + /** + * Simple Callable that will initialize any subclass of JFileChooser using + * the default constructor. + * + * Note that the class and default constructor must be public for this to + * work properly. + */ + private class ChooserCallable implements Callable { + + private final Class type; + + /** + * Construct a new instance for the given class type. + * + * @param type Class type to initialize. + */ + ChooserCallable(Class type) { + this.type = type; + } + + @Override + public JFileChooser call() throws Exception { + return type.newInstance(); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserHelper.java b/Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserHelper.java deleted file mode 100755 index 3d7cdb78b8..0000000000 --- a/Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserHelper.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2021 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.guicomponeontutils; - -import java.awt.Cursor; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.FutureTask; -import javax.swing.JFileChooser; -import org.openide.windows.WindowManager; - -/** - * Helper class that will initialize JFileChooser instances in background threads. - * - * On windows JFileChooser can take a long time to initialize. This helper class - * takes the work of initializing the JFileChooser off of the EDT so that in - * theory the when the chooser is needed initialized and ready to be displayed - * to the user. - * - * https://stackoverflow.com/questions/49792375/jfilechooser-is-very-slow-when-using-windows-look-and-feel - */ -public final class JFileChooserHelper { - private final FutureTask futureFileChooser = new FutureTask<>(JFileChooser::new); - private JFileChooser chooser; - - /** - * Get a helper instance. - * - * @return - */ - public static JFileChooserHelper getHelper() { - return new JFileChooserHelper(); - } - - /** - * Create a new instance of the helper class. The constructor will - * kick of an executor to that will execute the task of initializing the - * JFileChooser. - */ - private JFileChooserHelper() { - ExecutorService executor = Executors.newSingleThreadExecutor(); - executor.execute(futureFileChooser); - } - - /** - * Return and instance of JFileChooser to the caller. - * - * This call may block the EDT if the JFileChooser initialization has not - * completed. - * - * @return - */ - public JFileChooser getChooser() { - if (chooser == null) { - // In case this takes a moment show the wait cursor. - WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - try { - // get() will only return when the initilization of the - // JFileChooser has completed. - chooser = futureFileChooser.get(); - } catch (InterruptedException | ExecutionException ex) { - // If an exception occured create a new instance of JFileChooser. - chooser = new JFileChooser(); - } - WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - - return chooser; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java index f52c2aaf77..0b7e0b8364 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java @@ -61,7 +61,7 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; /** * Dashboard for viewing metrics and controlling the health monitor. @@ -87,7 +87,7 @@ public class HealthMonitorDashboard { private JDialog dialog = null; private final Container parentWindow; - private final JFileChooserHelper chooserHelper; + private final JFileChooserFactory chooserHelper; /** * Create an instance of the dashboard. @@ -98,7 +98,7 @@ public class HealthMonitorDashboard { timingData = new HashMap<>(); userData = new ArrayList<>(); parentWindow = parent; - chooserHelper = JFileChooserHelper.getHelper(); + chooserHelper = new JFileChooserFactory(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java index 7cc36dfad3..523a3693ce 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java @@ -50,7 +50,7 @@ import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; import org.sleuthkit.autopsy.logicalimager.dsp.DriveListUtils; /** @@ -64,7 +64,7 @@ final class ConfigVisualPanel1 extends JPanel { private static final String DEFAULT_CONFIG_FILE_NAME = "logical-imager-config.json"; private static final String UPDATE_UI_EVENT_NAME = "UPDATE_UI"; private String configFilename; - private final JFileChooserHelper chooserHelper; + private final JFileChooserFactory chooserHelper; /** * Creates new form ConfigVisualPanel1 @@ -76,7 +76,7 @@ final class ConfigVisualPanel1 extends JPanel { refreshDriveList(); updateControls(); }); - chooserHelper = JFileChooserHelper.getHelper(); + chooserHelper = new JFileChooserFactory(); } @NbBundle.Messages({ diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java index 7142e04781..e247a25f89 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java @@ -44,7 +44,7 @@ import javax.swing.table.TableColumn; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; /** * Panel for adding an logical image file from drive letters. Allows the user to @@ -68,7 +68,7 @@ final class LogicalImagerPanel extends JPanel implements DocumentListener { private final Pattern regex = Pattern.compile("Logical_Imager_(.+)_(\\d{4})(\\d{2})(\\d{2})_(\\d{2})_(\\d{2})_(\\d{2})"); private Path manualImageDirPath; private DefaultTableModel imageTableModel; - private final JFileChooserHelper chooserHelper; + private final JFileChooserFactory chooserHelper; /** * Creates new form LogicalImagerPanel @@ -81,7 +81,7 @@ final class LogicalImagerPanel extends JPanel implements DocumentListener { configureImageTable(); jScrollPane1.setBorder(null); clearImageTable(); - chooserHelper = JFileChooserHelper.getHelper(); + chooserHelper = new JFileChooserFactory(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java index d2252aff94..18dffede59 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java @@ -18,21 +18,15 @@ */ package org.sleuthkit.autopsy.modules.hashdatabase; -import java.awt.Cursor; import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.FutureTask; import java.util.logging.Level; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; import org.apache.commons.io.FilenameUtils; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; @@ -51,6 +45,7 @@ import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.featureaccess.FeatureAccessUtils; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; /** * Instances of this class allow a user to create a new hash database and add it @@ -69,7 +64,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { private CentralRepoOrganization selectedOrg = null; private List orgs = null; static final String HASH_DATABASE_DIR_NAME = "HashDatabases"; - private final FutureTask futureFileChooser = new FutureTask<>(CustomFileChooser::new); + private final JFileChooserFactory chooserFactory; /** * Displays a dialog that allows a user to create a new hash database and @@ -79,11 +74,10 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { HashDbCreateDatabaseDialog() { super((JFrame) WindowManager.getDefault().getMainWindow(), NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.createHashDbMsg"), true); initComponents(); + chooserFactory = new JFileChooserFactory(CustomFileChooser.class); enableComponents(); display(); - ExecutorService executor = Executors.newSingleThreadExecutor(); - executor.execute(futureFileChooser); } /** @@ -147,7 +141,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { /** * Customize the JFileChooser. */ - private class CustomFileChooser extends JFileChooser { + public static class CustomFileChooser extends JFileChooser { private static final long serialVersionUID = 1L; @@ -448,17 +442,11 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { path.append(".").append(HashDbManager.getHashDatabaseFileExtension()); if(fileChooser == null) { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - try { - fileChooser = futureFileChooser.get(); - } catch (InterruptedException | ExecutionException ex) { - fileChooser = new CustomFileChooser(); - } + fileChooser = chooserFactory.getChooser(); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); fileChooser.setDragEnabled(false); fileChooser.setMultiSelectionEnabled(false); - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index 55051cd3f0..9e9156dd62 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -43,7 +43,7 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDbManagerExc import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.featureaccess.FeatureAccessUtils; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; /** * Instances of this class allow a user to select an existing hash database and @@ -59,7 +59,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private final static String LAST_FILE_PATH_KEY = "HashDbImport_Path"; private CentralRepoOrganization selectedOrg = null; private List orgs = null; - private final JFileChooserHelper chooserHelper; + private final JFileChooserFactory chooserHelper; /** * Displays a dialog that allows a user to select an existing hash database @@ -70,7 +70,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { super((JFrame) WindowManager.getDefault().getMainWindow(), NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.importHashDbMsg"), true); - chooserHelper = JFileChooserHelper.getHelper(); + chooserHelper = new JFileChooserFactory(); initComponents(); enableComponents(); display(); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index 1ff46b95c8..18fe932d45 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -65,7 +65,7 @@ import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; /** @@ -95,7 +95,7 @@ public class HashDbManager implements PropertyChangeListener { private static final String KNOWN_STATUS_PARAM = "knownStatus"; private static final Pattern OFFICIAL_FILENAME = Pattern.compile("(?<" + DB_NAME_PARAM + ">.+?)\\.(?<" + KNOWN_STATUS_PARAM + ">.+?)\\." + KDB_EXT); - private final JFileChooserHelper chooserHelper; + private final JFileChooserFactory chooserHelper; private static final FilenameFilter DEFAULT_KDB_FILTER = new FilenameFilter() { @Override @@ -139,7 +139,7 @@ public class HashDbManager implements PropertyChangeListener { } private HashDbManager() { - chooserHelper = JFileChooserHelper.getHelper(); + chooserHelper = new JFileChooserFactory(); loadHashsetsConfiguration(); } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModuleConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModuleConfigPanel.java index bb23320c87..a1161737ac 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModuleConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModuleConfigPanel.java @@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.report.modules.stix; import java.io.File; import javax.swing.JFileChooser; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserHelper; +import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; /** * Configuration panel for STIX report generation. @@ -30,7 +30,7 @@ public class STIXReportModuleConfigPanel extends javax.swing.JPanel { String stixFile = null; boolean showAllResults; - private final JFileChooserHelper chooserHelper; + private final JFileChooserFactory chooserHelper; /** * Creates new form STIXReportModuleConfigPanel @@ -39,7 +39,7 @@ public class STIXReportModuleConfigPanel extends javax.swing.JPanel { initComponents(); showAllResults = false; jCheckBox1.setSelected(false); - chooserHelper = JFileChooserHelper.getHelper(); + chooserHelper = new JFileChooserFactory(); } void setConfiguration(STIXReportModuleSettings settings) { From 298059fcc9bf175a88bddd1f7f5b68f236fc9687 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 12 Aug 2021 17:43:07 -0400 Subject: [PATCH 30/76] Change the package of JFileChooserFactory --- Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java | 2 +- Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java | 2 +- Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java | 2 +- .../org/sleuthkit/autopsy/casemodule/MissingImageDialog.java | 2 +- .../org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java | 2 +- Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java | 2 +- Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java | 2 +- .../sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java | 2 +- .../sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java | 2 +- .../xry/XRYDataSourceProcessorConfigPanel.java | 2 +- .../autopsy/directorytree/AddExternalViewerRulePanel.java | 2 +- .../org/sleuthkit/autopsy/directorytree/ExportCSVAction.java | 2 +- .../directorytree/ExternalViewerGlobalSettingsPanel.java | 2 +- .../sleuthkit/autopsy/directorytree/ExtractUnallocAction.java | 2 +- .../directorytree/actionhelpers/ExtractActionHelper.java | 2 +- .../sleuthkit/autopsy/geolocation/GeolocationSettingsPanel.java | 2 +- .../{guicomponeontutils => guiutils}/JFileChooserFactory.java | 2 +- .../sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java | 2 +- .../autopsy/logicalimager/configuration/ConfigVisualPanel1.java | 2 +- .../sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java | 2 +- .../modules/hashdatabase/HashDbCreateDatabaseDialog.java | 2 +- .../modules/hashdatabase/HashDbImportDatabaseDialog.java | 2 +- .../sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java | 2 +- .../report/modules/stix/STIXReportModuleConfigPanel.java | 2 +- 24 files changed, 24 insertions(+), 24 deletions(-) rename Core/src/org/sleuthkit/autopsy/{guicomponeontutils => guiutils}/JFileChooserFactory.java (99%) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java index 81143091d4..25789939b3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java @@ -43,7 +43,7 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.Version; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; /** * The action associated with the Case/Open Case menu item via the layer.xml diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 20770a2c00..eda7149f66 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.coreutils.DriveUtils; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; import org.sleuthkit.datamodel.HashUtility; /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java index 4759ce1177..b0031ed1c7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java @@ -32,7 +32,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings; /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java index ffcbc7792f..e4edc6e7bb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java @@ -32,7 +32,7 @@ import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.DriveUtils; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java index aa0ec43316..64def92cc2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseVisualPanel1.java @@ -30,7 +30,7 @@ import javax.swing.event.DocumentListener; import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; /** * The JPanel for the first page of the new case wizard. diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java index 4d2aae6760..51e9a549ee 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java @@ -56,7 +56,7 @@ import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; import org.sleuthkit.datamodel.TskCoreException; import org.xml.sax.SAXException; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java index 61066c0137..38630b4aa4 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java @@ -49,7 +49,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.autopsy.coreutils.SQLiteTableReader; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; /** * A file content viewer for SQLite database files. diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java index 6470161459..0a52ae749c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java @@ -55,7 +55,7 @@ import org.sleuthkit.autopsy.machinesettings.UserMachinePreferencesException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.Version; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; import org.sleuthkit.autopsy.machinesettings.UserMachinePreferences.TempDirChoice; import org.sleuthkit.autopsy.report.ReportBranding; diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java index 80acf8a8a1..dbb571d4ba 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java @@ -32,7 +32,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PathValidator; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; /** * Allows examiner to supply a raw data source. diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessorConfigPanel.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessorConfigPanel.java index 88c2c34bf3..d7a78ea389 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessorConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/xry/XRYDataSourceProcessorConfigPanel.java @@ -30,7 +30,7 @@ import javax.swing.JPanel; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.ModuleSettings; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; /** * Allows an examiner to configure the XRY Data source processor. diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/AddExternalViewerRulePanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/AddExternalViewerRulePanel.java index 473270811e..beafb6ef5d 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/AddExternalViewerRulePanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/AddExternalViewerRulePanel.java @@ -26,7 +26,7 @@ import javax.swing.event.DocumentListener; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.GeneralFilter; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; /** diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java index e1c95361e5..27b7a11a84 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExportCSVAction.java @@ -51,7 +51,7 @@ import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFileProp import org.openide.nodes.Node; import org.openide.nodes.Node.PropertySet; import org.openide.nodes.Node.Property; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; /** * Exports CSV version of result nodes to a location selected by the user. diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index b13a149fc6..0235c849bd 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -33,7 +33,7 @@ import org.netbeans.spi.options.OptionsPanelController; import org.sleuthkit.autopsy.casemodule.GeneralFilter; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; /** * An options panel for the user to create, edit, and delete associations for diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java index 8b9f5af58d..a29f5c39ef 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java @@ -47,7 +47,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; import org.sleuthkit.datamodel.AbstractContent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java index 1a9ae807f5..5a28bd9c12 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/actionhelpers/ExtractActionHelper.java @@ -42,7 +42,7 @@ import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; import org.sleuthkit.datamodel.AbstractFile; /** diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationSettingsPanel.java index a7cab0fd25..de33c0ca2b 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationSettingsPanel.java @@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.casemodule.GeneralFilter; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; /** * A panel to allow the user to set the custom properties of the geolocation diff --git a/Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserFactory.java b/Core/src/org/sleuthkit/autopsy/guiutils/JFileChooserFactory.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserFactory.java rename to Core/src/org/sleuthkit/autopsy/guiutils/JFileChooserFactory.java index d885b3b8a6..996608f452 100755 --- a/Core/src/org/sleuthkit/autopsy/guicomponeontutils/JFileChooserFactory.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/JFileChooserFactory.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.guicomponeontutils; +package org.sleuthkit.autopsy.guiutils; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.awt.Cursor; diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java index 0b7e0b8364..bc673144c8 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java @@ -61,7 +61,7 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; /** * Dashboard for viewing metrics and controlling the health monitor. diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java index 523a3693ce..688c5e72a3 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel1.java @@ -50,7 +50,7 @@ import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; import org.sleuthkit.autopsy.logicalimager.dsp.DriveListUtils; /** diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java index e247a25f89..cc6297ae15 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java @@ -44,7 +44,7 @@ import javax.swing.table.TableColumn; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; /** * Panel for adding an logical image file from drive letters. Allows the user to diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java index 18dffede59..ee7634a276 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java @@ -45,7 +45,7 @@ import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.featureaccess.FeatureAccessUtils; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; /** * Instances of this class allow a user to create a new hash database and add it diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index 9e9156dd62..6f4d2606d7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -43,7 +43,7 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDbManagerExc import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.featureaccess.FeatureAccessUtils; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; /** * Instances of this class allow a user to select an existing hash database and diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index 18fe932d45..cf099075ed 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -65,7 +65,7 @@ import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; /** diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModuleConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModuleConfigPanel.java index a1161737ac..e32d3a0d0d 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModuleConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModuleConfigPanel.java @@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.report.modules.stix; import java.io.File; import javax.swing.JFileChooser; -import org.sleuthkit.autopsy.guicomponeontutils.JFileChooserFactory; +import org.sleuthkit.autopsy.guiutils.JFileChooserFactory; /** * Configuration panel for STIX report generation. From 0f719112795f633bc49d6f063b6773d6379c59d0 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Fri, 13 Aug 2021 13:36:13 -0400 Subject: [PATCH 31/76] Refoctoring --- .../Bundle.properties-MERGED | 4 + .../DataSourceSummaryReport.java | 35 +++--- .../ExcelExportAction.java | 112 ++++++++---------- 3 files changed, 75 insertions(+), 76 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index e9991129ff..1767afc028 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -1,3 +1,7 @@ +DataSourceSummaryReport.error.noDataSources=No data sources selected for report. +DataSourceSummaryReport.error.noOpenCase=No currently open case. +DataSourceSummaryReport.excelFileWriteError=Could not write the KML file. +DataSourceSummaryReport.failedToCompleteReport=Failed to complete report. DataSourceSummaryReport.getName.text=Data Source Summary Report DataSourceSummaryReport.getDesc.text=Data source summary report in Excel (XLS) format. DataSourceSummaryReport.endReport.srcModuleName.text=Excel Report diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java index 693667ceb1..a52f897897 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataSourceSummaryReport.java @@ -66,7 +66,7 @@ public class DataSourceSummaryReport implements GeneralReportModule { @Override public String getRelativeFilePath() { - return ""; //ELTODO "DataSourceSummaryReport.xlsx"; //NON-NLS + return ""; } @Override @@ -77,7 +77,7 @@ public class DataSourceSummaryReport implements GeneralReportModule { @Override public JPanel getConfigurationPanel() { - return null; // ELTODO + return null; } @Override @@ -85,13 +85,19 @@ public class DataSourceSummaryReport implements GeneralReportModule { return true; } + @NbBundle.Messages({ + "DataSourceSummaryReport.error.noOpenCase=No currently open case.", + "DataSourceSummaryReport.error.noDataSources=No data sources selected for report.", + "DataSourceSummaryReport.failedToCompleteReport=Failed to complete report.", + "DataSourceSummaryReport.excelFileWriteError=Could not write the KML file.",}) @Override public void generateReport(GeneralReportSettings settings, ReportProgressPanel progressPanel) { progressPanel.start(); - Case currentCase = null; + Case currentCase; try { currentCase = Case.getCurrentCaseThrows(); } catch (NoCurrentCaseException ex) { + progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR, Bundle.DataSourceSummaryReport_error_noOpenCase()); logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS return; } @@ -110,7 +116,7 @@ public class DataSourceSummaryReport implements GeneralReportModule { settings.setSelectedDataSources(dsIDs); } catch (TskCoreException ex) { result = ReportProgressPanel.ReportStatus.ERROR; - // ELTODO errorMessage = Bundle.KMLReport_failedToCompleteReport(); + errorMessage = Bundle.DataSourceSummaryReport_failedToCompleteReport(); logger.log(Level.SEVERE, "Could not get the datasources from the case", ex); progressPanel.complete(result, errorMessage); return; @@ -121,7 +127,7 @@ public class DataSourceSummaryReport implements GeneralReportModule { selectedDataSources.add(currentCase.getSleuthkitCase().getContentById(dsID)); } catch (TskCoreException ex) { result = ReportProgressPanel.ReportStatus.ERROR; - // ELTODO errorMessage = Bundle.KMLReport_failedToCompleteReport(); + errorMessage = Bundle.DataSourceSummaryReport_failedToCompleteReport(); logger.log(Level.SEVERE, "Could not get the datasources from the case", ex); progressPanel.complete(result, errorMessage); return; @@ -129,21 +135,20 @@ public class DataSourceSummaryReport implements GeneralReportModule { } } - String baseReportDir = settings.getReportDirectoryPath(); - // Start the progress bar and setup the report - // ELTODO progressPanel.setIndeterminate(true); - - //progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.querying")); - String reportFullPath = baseReportDir + getRelativeFilePath(); //NON-NLS - + if (selectedDataSources.isEmpty()) { + result = ReportProgressPanel.ReportStatus.ERROR; + progressPanel.complete(result, Bundle.DataSourceSummaryReport_error_noDataSources()); + logger.log(Level.SEVERE, "No data sources selected for report."); //NON-NLS + return; + } - // looop over all data sources + // looop over all selected data sources for (Content dataSource : selectedDataSources){ if (dataSource instanceof DataSource) { try { - new ExcelExportAction().exportToXLSX(progressPanel, (DataSource) dataSource, baseReportDir); + new ExcelExportAction().exportToXLSX(progressPanel, (DataSource) dataSource, settings.getReportDirectoryPath()); } catch (IOException | ExcelExport.ExcelExportException ex) { - // ELTODO errorMessage = Bundle.KMLReport_kmlFileWriteError(); + errorMessage = Bundle.DataSourceSummaryReport_excelFileWriteError(); logger.log(Level.SEVERE, errorMessage, ex); //NON-NLS progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR, errorMessage); return; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index d6a408766f..f513f26b89 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -107,90 +107,90 @@ class ExcelExportAction { throws IOException, ExcelExport.ExcelExportException { File reportFile = getXLSXPath(dataSource.getName(), baseReportDir); - int totalWeight = 10; + int totalWeight = 11; + int step = 1; progressPanel.setIndeterminate(false); + progressPanel.setLabels(dataSource.getName(), reportFile.getPath()); progressPanel.setMaximumProgress(totalWeight); progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_beginExport()); List sheetExports = new ArrayList<>(); - // Export Recent Activity data - progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringRecentActivityData()); - progressPanel.setProgress(1); - List exports = ExportRecentFiles.getExports(dataSource); - if (exports != null) { - sheetExports.addAll(exports); - } - - // Export Container & Image info data - progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringContainerData()); - progressPanel.setProgress(2); - exports = ExportContainerInfo.getExports(dataSource); - if (exports != null) { - sheetExports.addAll(exports); - } - - // Export Timeline data - progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringTimelineData()); - progressPanel.setProgress(3); - exports = ExportTimeline.getExports(dataSource); - if (exports != null) { - sheetExports.addAll(exports); - } - // Export file and MIME type data progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringFileData()); - progressPanel.setProgress(4); - exports = ExportTypes.getExports(dataSource); - if (exports != null) { - sheetExports.addAll(exports); - } - - // Export hash set hits, keyword hits, and interesting item hits - progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringAnalysisData()); - progressPanel.setProgress(5); - exports = ExportAnalysisResults.getExports(dataSource); - if (exports != null) { - sheetExports.addAll(exports); - } - - // Export hash set hits, keyword hits, and interesting item hits - progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringPastData()); - progressPanel.setProgress(6); - exports = ExportPastCases.getExports(dataSource); + progressPanel.setProgress(step); + List exports = ExportTypes.getExports(dataSource); if (exports != null) { sheetExports.addAll(exports); } // Export user activity progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringUserData()); - progressPanel.setProgress(6); + progressPanel.setProgress(++step); exports = ExportUserActivity.getExports(dataSource); if (exports != null) { sheetExports.addAll(exports); } + // Export Recent Activity data + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringRecentActivityData()); + progressPanel.setProgress(++step); + exports = ExportRecentFiles.getExports(dataSource); + if (exports != null) { + sheetExports.addAll(exports); + } + + // Export hash set hits, keyword hits, and interesting item hits + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringAnalysisData()); + progressPanel.setProgress(++step); + exports = ExportAnalysisResults.getExports(dataSource); + if (exports != null) { + sheetExports.addAll(exports); + } + + // Export past cases data + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringPastData()); + progressPanel.setProgress(++step); + exports = ExportPastCases.getExports(dataSource); + if (exports != null) { + sheetExports.addAll(exports); + } + // Export geolocation data progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringGeoData()); - progressPanel.setProgress(7); + progressPanel.setProgress(++step); exports = ExportGeolocation.getExports(dataSource); if (exports != null) { sheetExports.addAll(exports); } + // Export Timeline data + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringTimelineData()); + progressPanel.setProgress(++step); + exports = ExportTimeline.getExports(dataSource); + if (exports != null) { + sheetExports.addAll(exports); + } + // Export ingest history progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringIngestData()); - progressPanel.setProgress(8); + progressPanel.setProgress(++step); exports = ExportIngestHistory.getExports(dataSource); if (exports != null) { sheetExports.addAll(exports); } + // Export Container & Image info data + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringContainerData()); + progressPanel.setProgress(++step); + exports = ExportContainerInfo.getExports(dataSource); + if (exports != null) { + sheetExports.addAll(exports); + } + progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_writingToFile()); - progressPanel.setProgress(9); + progressPanel.setProgress(++step); ExcelExport.writeExcel(sheetExports, reportFile); - progressPanel.complete(ReportProgressPanel.ReportStatus.COMPLETE, ""); - try { // add to reports Case curCase = Case.getCurrentCaseThrows(); @@ -198,16 +198,6 @@ class ExcelExportAction { Bundle.ExcelExportAction_moduleName(), reportFile.getName(), dataSource); - - // and show finished dialog - /* - * ELTODO SwingUtilities.invokeLater(() -> { ExcelExportDialog - * dialog = new - * ExcelExportDialog(WindowManager.getDefault().getMainWindow(), - * path); dialog.setResizable(false); - * dialog.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); - * dialog.setVisible(true); dialog.toFront(); }); - */ } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.WARNING, "There was an error attaching report to case.", ex); } @@ -313,7 +303,7 @@ class ExcelExportAction { protected static ExcelSheetExport getTableExport(List> columnsModel, String sheetName, List data) { - return convertToExcel((dataList) -> new ExcelTableExport(sheetName, columnsModel, dataList), + return convertToExcel((dataList) -> new ExcelTableExport<>(sheetName, columnsModel, dataList), data, sheetName); } @@ -334,7 +324,7 @@ class ExcelExportAction { String sheetName, DataSource ds) { return getExport(dataFetcher, - (dataList) -> new ExcelTableExport(sheetName, columnsModel, dataList), + (dataList) -> new ExcelTableExport<>(sheetName, columnsModel, dataList), sheetName, ds); } From 7b91aa51d0d9e0b642f68d35f640f0b852c207e3 Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Fri, 13 Aug 2021 15:39:27 -0400 Subject: [PATCH 32/76] Make encryption messages consistent Make Encryption messages consistent --- .../modules/embeddedfileextractor/Bundle.properties | 1 - .../embeddedfileextractor/Bundle.properties-MERGED | 1 - .../modules/embeddedfileextractor/SevenZipExtractor.java | 4 ++-- .../EncryptionDetectionFileIngestModule.java | 6 +++--- .../EncryptionDetectionModuleFactory.java | 8 +++++++- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties index 2f8baa63cc..5e655eb928 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties @@ -10,7 +10,6 @@ OpenIDE-Module-Short-Description=Embedded File Extraction Ingest Module EmbeddedFileExtractorIngestModule.SevenZipContentReadStream.seek.exception.invalidOrigin=Invalid seek origin: {0} EmbeddedFileExtractorIngestModule.SevenZipContentReadStream.read.exception.errReadStream=Error reading content stream. EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFileLevel=Content-only Encryption (Archive File) -EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFull=Full Encryption (Archive File) EmbeddedFileExtractorIngestModule.ArchiveExtractor.init.errInitModule.details=Error initializing output dir: {0}: {1} EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg=Possible ZIP bomb detected in archive: {0}, item: {1} EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnDetails=Compression ratio is {0}, skipping items in {1}. diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED index efee783e8f..6f7251676d 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED @@ -23,7 +23,6 @@ OpenIDE-Module-Short-Description=Embedded File Extraction Ingest Module EmbeddedFileExtractorIngestModule.SevenZipContentReadStream.seek.exception.invalidOrigin=Invalid seek origin: {0} EmbeddedFileExtractorIngestModule.SevenZipContentReadStream.read.exception.errReadStream=Error reading content stream. EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFileLevel=Content-only Encryption (Archive File) -EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFull=Full Encryption (Archive File) EmbeddedFileExtractorIngestModule.ArchiveExtractor.init.errInitModule.details=Error initializing output dir: {0}: {1} EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg=Possible ZIP bomb detected in archive: {0}, item: {1} EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnDetails=Compression ratio is {0}, skipping items in {1}. diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 05b3fdfeb0..31f12eafce 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -58,6 +58,7 @@ import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.modules.encryptiondetection.EncryptionDetectionModuleFactory; import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestMessage; import org.sleuthkit.autopsy.ingest.IngestMonitor; @@ -95,8 +96,7 @@ class SevenZipExtractor { //encryption type strings private static final String ENCRYPTION_FILE_LEVEL = NbBundle.getMessage(EmbeddedFileExtractorIngestModule.class, "EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFileLevel"); - private static final String ENCRYPTION_FULL = NbBundle.getMessage(EmbeddedFileExtractorIngestModule.class, - "EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFull"); + private static final String ENCRYPTION_FULL = EncryptionDetectionModuleFactory.getPasswordProtectMessage(); //zip bomb detection private static final int MAX_DEPTH = 4; diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java index ff773cf8ef..1834f349fb 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java @@ -83,7 +83,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter private Blackboard blackboard; private IngestJobContext context; private double calculatedEntropy; - + private final double minimumEntropy; private final int minimumFileSize; private final boolean fileSizeMultipleEnforced; @@ -119,7 +119,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter } @Messages({ - "EncryptionDetectionFileIngestModule.artifactComment.password=Password protection detected.", +// "EncryptionDetectionFileIngestModule.artifactComment.password=Password protection detected.", "EncryptionDetectionFileIngestModule.artifactComment.suspected=Suspected encryption due to high entropy (%f)." }) @Override @@ -160,7 +160,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter String.format(Bundle.EncryptionDetectionFileIngestModule_artifactComment_suspected(), calculatedEntropy)); } else if (isFilePasswordProtected(file)) { return flagFile(file, BlackboardArtifact.Type.TSK_ENCRYPTION_DETECTED, Score.SCORE_NOTABLE, - Bundle.EncryptionDetectionFileIngestModule_artifactComment_password()); + EncryptionDetectionModuleFactory.getPasswordProtectMessage()); } } } catch (ReadContentInputStreamException | SAXException | TikaException | UnsupportedCodecException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java index 7a2d486841..2d1aceebab 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java @@ -36,8 +36,10 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; @ServiceProvider(service = IngestModuleFactory.class) @Messages({ "EncryptionDetectionFileIngestModule.moduleName.text=Encryption Detection", - "EncryptionDetectionFileIngestModule.getDesc.text=Looks for files with the specified minimum entropy." + "EncryptionDetectionFileIngestModule.getDesc.text=Looks for files with the specified minimum entropy.", + "EncryptionDetectionFileIngestModule.artifactComment.password=Password protection detected.", }) + public class EncryptionDetectionModuleFactory implements IngestModuleFactory { @Override @@ -45,6 +47,10 @@ public class EncryptionDetectionModuleFactory implements IngestModuleFactory { return getModuleName(); } + public static String getPasswordProtectMessage() { + return Bundle.EncryptionDetectionFileIngestModule_artifactComment_password(); + } + /** * Get the name of the module. * From dfccd20491f028a04ca42981e93f45951ad0cce2 Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Mon, 16 Aug 2021 13:32:50 -0400 Subject: [PATCH 33/76] Add static string to EncryptionDetection Added static string to EncryptionDetection module to keep a consistent message that can be called for password protected files. --- .../modules/embeddedfileextractor/SevenZipExtractor.java | 2 +- .../EncryptionDetectionFileIngestModule.java | 3 +-- .../EncryptionDetectionModuleFactory.java | 8 +++----- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 31f12eafce..a96de76442 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -96,7 +96,7 @@ class SevenZipExtractor { //encryption type strings private static final String ENCRYPTION_FILE_LEVEL = NbBundle.getMessage(EmbeddedFileExtractorIngestModule.class, "EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFileLevel"); - private static final String ENCRYPTION_FULL = EncryptionDetectionModuleFactory.getPasswordProtectMessage(); + private static final String ENCRYPTION_FULL = EncryptionDetectionModuleFactory.PASSWORD_PROTECT_MESSAGE; //zip bomb detection private static final int MAX_DEPTH = 4; diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java index 1834f349fb..81e7c1877e 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java @@ -119,7 +119,6 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter } @Messages({ -// "EncryptionDetectionFileIngestModule.artifactComment.password=Password protection detected.", "EncryptionDetectionFileIngestModule.artifactComment.suspected=Suspected encryption due to high entropy (%f)." }) @Override @@ -160,7 +159,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter String.format(Bundle.EncryptionDetectionFileIngestModule_artifactComment_suspected(), calculatedEntropy)); } else if (isFilePasswordProtected(file)) { return flagFile(file, BlackboardArtifact.Type.TSK_ENCRYPTION_DETECTED, Score.SCORE_NOTABLE, - EncryptionDetectionModuleFactory.getPasswordProtectMessage()); + EncryptionDetectionModuleFactory.PASSWORD_PROTECT_MESSAGE); } } } catch (ReadContentInputStreamException | SAXException | TikaException | UnsupportedCodecException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java index 2d1aceebab..7cfff12b07 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java @@ -42,15 +42,13 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; public class EncryptionDetectionModuleFactory implements IngestModuleFactory { + public static final String PASSWORD_PROTECT_MESSAGE = Bundle.EncryptionDetectionFileIngestModule_artifactComment_password(); + @Override public String getModuleDisplayName() { return getModuleName(); } - - public static String getPasswordProtectMessage() { - return Bundle.EncryptionDetectionFileIngestModule_artifactComment_password(); - } - + /** * Get the name of the module. * From 4f493317a05f72187ad80f8d9e26c1a18095d064 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 16 Aug 2021 14:57:43 -0400 Subject: [PATCH 34/76] removed 'public' declarations --- .../modules/datasourcesummaryexport/DataFetcher.java | 2 +- .../modules/datasourcesummaryexport/PieChartItem.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataFetcher.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataFetcher.java index f3b0b0fe6c..b513762280 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataFetcher.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataFetcher.java @@ -25,7 +25,7 @@ package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport; * another type in the event that the fetching encountered an error. */ @FunctionalInterface -public interface DataFetcher { +interface DataFetcher { /** * A function that accepts an input argument and outputs a result. Since it diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartItem.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartItem.java index 3b18a8c41c..4db4f41bfe 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartItem.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartItem.java @@ -23,7 +23,7 @@ import java.awt.Color; /** * An individual pie chart slice in the pie chart. */ -public class PieChartItem { +class PieChartItem { private final String label; private final double value; @@ -37,7 +37,7 @@ public class PieChartItem { * @param color The color for the pie slice. Can be null for * auto-determined. */ - public PieChartItem(String label, double value, Color color) { + PieChartItem(String label, double value, Color color) { this.label = label; this.value = value; this.color = color; @@ -46,21 +46,21 @@ public class PieChartItem { /** * @return The label for this item. */ - public String getLabel() { + String getLabel() { return label; } /** * @return The value for this item. */ - public double getValue() { + double getValue() { return value; } /** * @return The color for the pie slice or null for auto-determined. */ - public Color getColor() { + Color getColor() { return color; } From bccf0e310440f7e5acd44eb01af9c9d3a34954e4 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 18 Aug 2021 11:23:01 -0400 Subject: [PATCH 35/76] 7877 changes to cancellation for discovery --- .../discovery/search/DomainSearch.java | 16 +++--------- .../autopsy/discovery/search/FileSearch.java | 2 +- .../autopsy/discovery/ui/DiscoveryDialog.java | 8 +++--- .../discovery/ui/DiscoveryTopComponent.java | 1 - .../autopsy/discovery/ui/SearchWorker.java | 26 ++++++++++++++----- 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java index eb52327d45..b581544e85 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java @@ -66,8 +66,8 @@ public class DomainSearch { } /** - * Run the domain search to get the group keys and sizes. Clears cache of - * search results, caching new results for access at later time. + * Run the domain search to get the search results keys and sizes. Clears + * cache of search results, caching new results for access at later time. * * @param userName The name of the user performing the search. * @param filters The filters to apply. @@ -83,23 +83,15 @@ public class DomainSearch { * * @throws DiscoveryException */ - public Map getGroupSizes(String userName, + public Map> getSearchResults(String userName, List filters, DiscoveryAttributes.AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, ResultsSorter.SortingMethod domainSortingMethod, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { - - final Map> searchResults = searchCache.get( + return searchCache.get( userName, filters, groupAttributeType, groupSortingType, domainSortingMethod, caseDb, centralRepoDb); - // Transform the cached results into a map of group key to group size. - final LinkedHashMap groupSizes = new LinkedHashMap<>(); - for (GroupKey groupKey : searchResults.keySet()) { - groupSizes.put(groupKey, searchResults.get(groupKey).size()); - } - - return groupSizes; } /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java index 4c25419357..9a4c6d00e4 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java @@ -252,7 +252,7 @@ public class FileSearch { * * @throws DiscoveryException */ - private static Map> runFileSearch(String userName, + public static Map> runFileSearch(String userName, List filters, AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 450ad4d381..a60e9a4e41 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -31,7 +31,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; -import javax.swing.SwingUtilities; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; @@ -90,6 +89,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { if (discDialog == null) { discDialog = new DiscoveryDialog(); } + if (shouldUpdate) { discDialog.updateSearchSettings(); shouldUpdate = false; @@ -574,7 +574,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { } private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed - // Get the selected filters + setVisible(false); //set visible used here instead of dispose incase dispose code changes final DiscoveryTopComponent tc = DiscoveryTopComponent.getTopComponent(); if (tc == null) { setValid("No Top Component Found"); @@ -584,6 +584,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { tc.open(); } tc.resetTopComponent(); + // Get the selected filters List filters; if (videosButton.isSelected()) { filters = videoFilterPanel.getFilters(); @@ -617,7 +618,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { } searchWorker = new SearchWorker(centralRepoDb, type, filters, groupingAttr, groupSortAlgorithm, fileSort); searchWorker.execute(); - dispose(); + tc.toFront(); tc.requestActive(); }//GEN-LAST:event_searchButtonActionPerformed @@ -651,6 +652,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { void cancelSearch() { if (searchWorker != null) { searchWorker.cancel(true); + searchWorker = null; } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java index a74b32ca26..0a99945142 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java @@ -260,7 +260,6 @@ public final class DiscoveryTopComponent extends TopComponent { private void newSearchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newSearchButtonActionPerformed close(); final DiscoveryDialog discDialog = DiscoveryDialog.getDiscoveryDialogInstance(); - discDialog.cancelSearch(); discDialog.setVisible(true); discDialog.validateDialog(); }//GEN-LAST:event_newSearchButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java index 7c6863ce62..bf843af6ec 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java @@ -34,6 +34,7 @@ import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.FileSearch; import org.sleuthkit.autopsy.discovery.search.DiscoveryException; import org.sleuthkit.autopsy.discovery.search.DomainSearch; +import org.sleuthkit.autopsy.discovery.search.Result; import org.sleuthkit.autopsy.discovery.search.ResultsSorter; import org.sleuthkit.autopsy.discovery.search.SearchData; @@ -77,17 +78,28 @@ final class SearchWorker extends SwingWorker { // Run the search if (searchType == SearchData.Type.DOMAIN) { DomainSearch domainSearch = new DomainSearch(); - results.putAll(domainSearch.getGroupSizes(System.getProperty(USER_NAME_PROPERTY), filters, + final Map> searchResults = domainSearch.getSearchResults(System.getProperty(USER_NAME_PROPERTY), filters, groupingAttr, groupSortAlgorithm, fileSort, - Case.getCurrentCase().getSleuthkitCase(), centralRepoDb)); + Case.getCurrentCase().getSleuthkitCase(), centralRepoDb); + // Transform the cached results into a map of group key to group size. + final LinkedHashMap groupSizes = new LinkedHashMap<>(); + for (GroupKey groupKey : searchResults.keySet()) { + if (isCancelled()) { + return null; + } + results.put(groupKey, searchResults.get(groupKey).size()); + } } else { - results.putAll(FileSearch.getGroupSizes(System.getProperty(USER_NAME_PROPERTY), filters, - groupingAttr, - groupSortAlgorithm, - fileSort, - Case.getCurrentCase().getSleuthkitCase(), centralRepoDb)); + Map> searchResults = FileSearch.runFileSearch(System.getProperty(USER_NAME_PROPERTY), filters, + groupingAttr, groupSortAlgorithm, fileSort, Case.getCurrentCase().getSleuthkitCase(), centralRepoDb); + for (GroupKey groupKey : searchResults.keySet()) { + if (isCancelled()) { + return null; + } + results.put(groupKey, searchResults.get(groupKey).size()); + } } } catch (DiscoveryException ex) { logger.log(Level.SEVERE, "Error running file search test", ex); From 82209968ad2969b243b0e6ba5fe0fd26f40873e3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 18 Aug 2021 11:26:56 -0400 Subject: [PATCH 36/76] 7877 update copyrights and imports --- .../org/sleuthkit/autopsy/discovery/search/DomainSearch.java | 1 - Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java | 2 +- .../src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java | 2 +- .../sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java | 2 +- Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java index b581544e85..5d27cfa19b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.discovery.search; import java.awt.Image; import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java index 9a4c6d00e4..334286de20 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019-2020 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index a60e9a4e41..fe2c61b38d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -1,7 +1,7 @@ /* * Autopsy * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java index 0a99945142..c5dba98337 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryTopComponent.java @@ -1,7 +1,7 @@ /* * Autopsy * - * Copyright 2019-2020 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java index bf843af6ec..7f9ee22c16 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java @@ -1,7 +1,7 @@ /* * Autopsy * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); From 17224b10d259a4ecf6850ad1bec877455e9d6be3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 18 Aug 2021 11:36:25 -0400 Subject: [PATCH 37/76] 7877 update comment --- .../sleuthkit/autopsy/discovery/search/DomainSearch.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java index 5d27cfa19b..caffcfb27a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java @@ -65,8 +65,8 @@ public class DomainSearch { } /** - * Run the domain search to get the search results keys and sizes. Clears - * cache of search results, caching new results for access at later time. + * Run the domain search to get the search results caching new results for + * access at later time. * * @param userName The name of the user performing the search. * @param filters The filters to apply. @@ -78,7 +78,7 @@ public class DomainSearch { * @param centralRepoDb The central repository database. Can be null * if not needed. * - * @return A LinkedHashMap grouped and sorted according to the parameters. + * @return Domain search results matching the given parameters. * * @throws DiscoveryException */ From cccfde11f13ec9a9ec956ecbd8d71c265b19ebcd Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 18 Aug 2021 15:20:21 -0400 Subject: [PATCH 38/76] Refactored datasourcesummary packages --- .../contentutils/Bundle.properties-MERGED | 2 -- .../datamodel}/AnalysisSummary.java | 2 +- .../datamodel/Bundle.properties-MERGED | 0 .../datamodel/Bundle_ja.properties | 3 --- .../datamodel}/CityRecord.java | 2 +- .../datamodel}/ClosestCityMapper.java | 2 +- .../datamodel}/ContainerSummary.java | 2 +- .../datamodel}/DataSourceInfoUtilities.java | 2 +- .../datamodel}/GeolocationSummary.java | 2 +- .../datamodel}/LatLngMap.java | 2 +- .../datamodel}/PastCasesSummary.java | 2 +- .../datamodel}/RecentFilesSummary.java | 2 +- .../datamodel}/TimelineSummary.java | 2 +- .../datamodel}/TypesSummary.java | 2 +- .../datamodel}/UserActivitySummary.java | 2 +- .../datamodel}/worldcities.csv | 0 .../datasourcesummary/ui/AnalysisPanel.java | 1 - .../{datamodel => ui}/AnalysisSummaryGetter.java | 6 +++--- .../ui/Bundle.properties-MERGED | 2 ++ .../CaseDataSourcesSummary.java | 2 +- .../datasourcesummary/ui/ContainerPanel.java | 5 ++--- .../ContainerSummaryGetter.java | 6 +++--- .../datasourcesummary/ui/DataSourceBrowser.java | 1 - .../DataSourceLabeledValueCallback.java | 2 +- .../DataSourceSingleValueCallback.java | 2 +- .../datasourcesummary/ui/GeolocationPanel.java | 9 ++++----- .../GeolocationSummaryGetter.java | 8 ++++---- .../{datamodel => ui}/MimeTypeSummaryGetter.java | 6 +++--- .../datasourcesummary/ui/PastCasesPanel.java | 3 +-- .../PastCasesSummaryGetter.java | 8 ++++---- .../{datamodel => ui}/RecentFilesGetter.java | 12 ++++++------ .../datasourcesummary/ui/RecentFilesPanel.java | 7 +++---- .../{datamodel => ui}/SleuthkitCaseProvider.java | 2 +- .../datasourcesummary/ui/TimelinePanel.java | 7 +++---- .../{datamodel => ui}/TimelineSummaryGetter.java | 8 ++++---- .../autopsy/datasourcesummary/ui/TypesPanel.java | 9 +++------ .../{datamodel => ui}/TypesSummaryGetter.java | 6 +++--- .../datasourcesummary/ui/UserActivityPanel.java | 13 ++++++------- .../UserActivitySummaryGetter.java | 16 ++++++++-------- .../ExportAnalysisResults.java | 2 +- .../ExportContainerInfo.java | 6 +++--- .../ExportGeolocation.java | 10 +++++----- .../datasourcesummaryexport/ExportPastCases.java | 4 ++-- .../ExportRecentFiles.java | 8 ++++---- .../datasourcesummaryexport/ExportTimeline.java | 6 +++--- .../datasourcesummaryexport/ExportTypes.java | 8 ++++---- .../ExportUserActivity.java | 14 +++++++------- .../UserActivitySummaryTests.java | 6 +++--- .../datamodel/DataSourceInfoUtilitiesTest.java | 3 +-- .../datamodel/RecentFilesSummaryTest.java | 9 +++++---- .../datamodel/UserActivitySummaryTest.java | 13 +++++++------ 51 files changed, 123 insertions(+), 136 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/contentutils/Bundle.properties-MERGED rename Core/src/org/sleuthkit/autopsy/{contentutils => datasourcesummary/datamodel}/AnalysisSummary.java (99%) mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle.properties-MERGED delete mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle_ja.properties rename Core/src/org/sleuthkit/autopsy/{contentutils => datasourcesummary/datamodel}/CityRecord.java (98%) rename Core/src/org/sleuthkit/autopsy/{contentutils => datasourcesummary/datamodel}/ClosestCityMapper.java (99%) rename Core/src/org/sleuthkit/autopsy/{contentutils => datasourcesummary/datamodel}/ContainerSummary.java (99%) rename Core/src/org/sleuthkit/autopsy/{contentutils => datasourcesummary/datamodel}/DataSourceInfoUtilities.java (99%) rename Core/src/org/sleuthkit/autopsy/{contentutils => datasourcesummary/datamodel}/GeolocationSummary.java (99%) rename Core/src/org/sleuthkit/autopsy/{contentutils => datasourcesummary/datamodel}/LatLngMap.java (99%) rename Core/src/org/sleuthkit/autopsy/{contentutils => datasourcesummary/datamodel}/PastCasesSummary.java (99%) rename Core/src/org/sleuthkit/autopsy/{contentutils => datasourcesummary/datamodel}/RecentFilesSummary.java (99%) rename Core/src/org/sleuthkit/autopsy/{contentutils => datasourcesummary/datamodel}/TimelineSummary.java (99%) rename Core/src/org/sleuthkit/autopsy/{contentutils => datasourcesummary/datamodel}/TypesSummary.java (99%) rename Core/src/org/sleuthkit/autopsy/{contentutils => datasourcesummary/datamodel}/UserActivitySummary.java (99%) rename Core/src/org/sleuthkit/autopsy/{contentutils => datasourcesummary/datamodel}/worldcities.csv (100%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{datamodel => ui}/AnalysisSummaryGetter.java (94%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{datamodel => ui}/CaseDataSourcesSummary.java (99%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{datamodel => ui}/ContainerSummaryGetter.java (95%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{datamodel => ui}/DataSourceLabeledValueCallback.java (97%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{datamodel => ui}/DataSourceSingleValueCallback.java (97%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{datamodel => ui}/GeolocationSummaryGetter.java (89%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{datamodel => ui}/MimeTypeSummaryGetter.java (96%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{datamodel => ui}/PastCasesSummaryGetter.java (88%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{datamodel => ui}/RecentFilesGetter.java (90%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{datamodel => ui}/SleuthkitCaseProvider.java (97%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{datamodel => ui}/TimelineSummaryGetter.java (90%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{datamodel => ui}/TypesSummaryGetter.java (96%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{datamodel => ui}/UserActivitySummaryGetter.java (92%) diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentutils/Bundle.properties-MERGED deleted file mode 100755 index 2e019a0248..0000000000 --- a/Core/src/org/sleuthkit/autopsy/contentutils/Bundle.properties-MERGED +++ /dev/null @@ -1,2 +0,0 @@ -DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=Call Log -DataSourceUserActivitySummary_getRecentAccounts_emailMessage=Email Message diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/AnalysisSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/contentutils/AnalysisSummary.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java index dc12c9edad..e5824b9f3f 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/AnalysisSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.contentutils; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.util.ArrayList; import java.util.Collections; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle.properties-MERGED old mode 100644 new mode 100755 diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle_ja.properties deleted file mode 100644 index a8185f73ff..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle_ja.properties +++ /dev/null @@ -1,3 +0,0 @@ -#Mon Jun 14 12:23:19 UTC 2021 -DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=\u901a\u8a71\u8a18\u9332 -DataSourceUserActivitySummary_getRecentAccounts_emailMessage=\u30e1\u30fc\u30eb\u30e1\u30c3\u30bb\u30fc\u30b8 diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/CityRecord.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/CityRecord.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/contentutils/CityRecord.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/CityRecord.java index 562fc1758d..26fa46498c 100644 --- a/Core/src/org/sleuthkit/autopsy/contentutils/CityRecord.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/CityRecord.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.contentutils; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.util.Objects; import org.sleuthkit.autopsy.geolocation.KdTree; diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/ClosestCityMapper.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ClosestCityMapper.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/contentutils/ClosestCityMapper.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ClosestCityMapper.java index 3e39852c79..e2df913534 100644 --- a/Core/src/org/sleuthkit/autopsy/contentutils/ClosestCityMapper.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ClosestCityMapper.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.contentutils; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.io.BufferedReader; import java.io.IOException; diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java index 13f7eec7bf..7bd34016f3 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/ContainerSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.contentutils; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.sql.SQLException; import java.util.ArrayList; diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/DataSourceInfoUtilities.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/contentutils/DataSourceInfoUtilities.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java index 2b69808eba..2847ea4510 100644 --- a/Core/src/org/sleuthkit/autopsy/contentutils/DataSourceInfoUtilities.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.contentutils; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.sql.ResultSet; import java.sql.SQLException; diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/GeolocationSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummary.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/contentutils/GeolocationSummary.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummary.java index ea3ffec08c..b011dd8f4e 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/GeolocationSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummary.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.contentutils; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.io.IOException; import java.util.ArrayList; diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/LatLngMap.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/LatLngMap.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/contentutils/LatLngMap.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/LatLngMap.java index 9d026ab11d..22a004c03c 100644 --- a/Core/src/org/sleuthkit/autopsy/contentutils/LatLngMap.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/LatLngMap.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.contentutils; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.util.Collection; import java.util.List; diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/PastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/contentutils/PastCasesSummary.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java index c82bb2b2b8..5bfe52261c 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/PastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.contentutils; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.util.ArrayList; import java.util.Arrays; diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java index fd2d8341e7..77504394dd 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/RecentFilesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.contentutils; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.nio.file.Paths; import java.text.DateFormat; diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/TimelineSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/contentutils/TimelineSummary.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java index 345cda6332..c21927b4df 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/TimelineSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.contentutils; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.text.DateFormat; import java.text.SimpleDateFormat; diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/TypesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/contentutils/TypesSummary.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java index 4c6944de37..a0fc5c7aa9 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/TypesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.contentutils; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.awt.Color; import java.sql.SQLException; diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/UserActivitySummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/contentutils/UserActivitySummary.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java index 1d46523ebd..5b51d10461 100755 --- a/Core/src/org/sleuthkit/autopsy/contentutils/UserActivitySummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.contentutils; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.io.File; import java.util.ArrayList; diff --git a/Core/src/org/sleuthkit/autopsy/contentutils/worldcities.csv b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/worldcities.csv similarity index 100% rename from Core/src/org/sleuthkit/autopsy/contentutils/worldcities.csv rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/worldcities.csv diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index df86d973b1..929f2d2364 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -23,7 +23,6 @@ import java.util.List; import java.util.function.Function; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummaryGetter; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisSummaryGetter.java similarity index 94% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummaryGetter.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisSummaryGetter.java index 33cf925fba..9f2a19d72b 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisSummaryGetter.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.datasourcesummary.ui; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; import java.util.Arrays; @@ -26,8 +26,8 @@ import java.util.List; import java.util.Set; import org.apache.commons.lang3.tuple.Pair; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.contentutils.AnalysisSummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummary; +import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED index 27a706c4a0..a7a4e5870f 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -56,6 +56,8 @@ DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files DataSourceSummaryTabbedPane_timelineTab_title=Timeline DataSourceSummaryTabbedPane_typesTab_title=Types DataSourceSummaryTabbedPane_userActivityTab_title=User Activity +DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=Call Log +DataSourceUserActivitySummary_getRecentAccounts_emailMessage=Email Message GeolocationPanel_cityColumn_title=Closest City GeolocationPanel_countColumn_title=Count GeolocationPanel_mostCommon_tabName=Most Common Cities diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/CaseDataSourcesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/CaseDataSourcesSummary.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/CaseDataSourcesSummary.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/CaseDataSourcesSummary.java index 50e883e29a..4181af5b8e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/CaseDataSourcesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/CaseDataSourcesSummary.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.datasourcesummary.ui; import java.util.Collections; import java.util.HashMap; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java index 75e826f625..fc313d1ef8 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java @@ -28,9 +28,8 @@ import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.table.DefaultTableModel; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.contentutils.ContainerSummary.ContainerDetails; -import org.sleuthkit.autopsy.contentutils.ContainerSummary.ImageDetails; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummaryGetter; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary.ContainerDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary.ImageDetails; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerSummaryGetter.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerSummaryGetter.java index 9cf43f408e..68bff3d987 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerSummaryGetter.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.datasourcesummary.ui; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; import java.sql.SQLException; @@ -24,8 +24,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import org.sleuthkit.autopsy.contentutils.ContainerSummary; +import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceBrowser.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceBrowser.java index 51433534e4..5d2694f9ff 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceBrowser.java @@ -42,7 +42,6 @@ import static javax.swing.SwingConstants.RIGHT; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.table.TableColumn; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.CaseDataSourcesSummary; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; import org.sleuthkit.datamodel.SleuthkitCase; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceLabeledValueCallback.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceLabeledValueCallback.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceLabeledValueCallback.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceLabeledValueCallback.java index 6c9c918667..cbb4b18e86 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceLabeledValueCallback.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceLabeledValueCallback.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.datasourcesummary.ui; import java.sql.ResultSet; import java.sql.SQLException; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceSingleValueCallback.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSingleValueCallback.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceSingleValueCallback.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSingleValueCallback.java index 6b1ff205fa..901c3d9416 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceSingleValueCallback.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSingleValueCallback.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.datasourcesummary.ui; import java.sql.ResultSet; import java.sql.SQLException; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java index 3e5687255e..55d37a3d2e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java @@ -34,11 +34,10 @@ import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummaryGetter; -import org.sleuthkit.autopsy.contentutils.GeolocationSummary.CityCountsList; -import org.sleuthkit.autopsy.contentutils.GeolocationSummary.CityData; -import org.sleuthkit.autopsy.contentutils.GeolocationSummary.CityRecordCount; -import org.sleuthkit.autopsy.contentutils.CityRecord; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityCountsList; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityData; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityRecordCount; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.CityRecord; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationSummaryGetter.java similarity index 89% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummaryGetter.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationSummaryGetter.java index 9165f43561..9a9dc7f61c 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationSummaryGetter.java @@ -16,14 +16,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.datasourcesummary.ui; import java.io.IOException; import java.util.List; import java.util.Set; -import org.sleuthkit.autopsy.contentutils.GeolocationSummary; -import org.sleuthkit.autopsy.contentutils.GeolocationSummary.CityData; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityData; +import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/MimeTypeSummaryGetter.java similarity index 96% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummaryGetter.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/MimeTypeSummaryGetter.java index a0b29e8a7f..f2a96cdd92 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/MimeTypeSummaryGetter.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.datasourcesummary.ui; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; import java.sql.SQLException; @@ -27,8 +27,8 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; +import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceInfoUtilities; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index 5886457530..f893098313 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -22,8 +22,7 @@ import java.util.Arrays; import java.util.List; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.contentutils.PastCasesSummary.PastCasesResult; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummaryGetter; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.PastCasesResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesSummaryGetter.java similarity index 88% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummaryGetter.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesSummaryGetter.java index 4d33ad6757..f7b76081f7 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesSummaryGetter.java @@ -16,17 +16,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.datasourcesummary.ui; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; -import org.sleuthkit.autopsy.contentutils.PastCasesSummary; -import org.sleuthkit.autopsy.contentutils.PastCasesSummary.PastCasesResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.PastCasesResult; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesGetter.java similarity index 90% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesGetter.java index 668c0085df..0c6db1d7e1 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesGetter.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.datasourcesummary.ui; import java.util.Arrays; import java.util.Collections; @@ -25,13 +25,13 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGove import java.util.List; import java.util.Set; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.contentutils.RecentFilesSummary; -import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentAttachmentDetails; -import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentDownloadDetails; -import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentFileDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.datamodel.BlackboardArtifact; /** diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index 87e934dcc1..1794c24aec 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -28,10 +28,9 @@ import java.util.Locale; import java.util.function.Function; import java.util.function.Supplier; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesGetter; -import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentAttachmentDetails; -import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentDownloadDetails; -import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentFileDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/SleuthkitCaseProvider.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SleuthkitCaseProvider.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/SleuthkitCaseProvider.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SleuthkitCaseProvider.java index 8371b2fefd..90afc2d597 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/SleuthkitCaseProvider.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SleuthkitCaseProvider.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.datasourcesummary.ui; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java index dab41e9cc8..42a7b1ba8f 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java @@ -32,10 +32,9 @@ import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.contentutils.TimelineSummary; -import org.sleuthkit.autopsy.contentutils.TimelineSummary.DailyActivityAmount; -import org.sleuthkit.autopsy.contentutils.TimelineSummary.TimelineSummaryData; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummaryGetter; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData; import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries; import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.OrderedKey; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelineSummaryGetter.java similarity index 90% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummaryGetter.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelineSummaryGetter.java index 3331cd45ed..99bdc2737c 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelineSummaryGetter.java @@ -16,22 +16,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.datasourcesummary.ui; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; -import org.sleuthkit.autopsy.contentutils.TimelineSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.contentutils.TimelineSummary.TimelineSummaryData; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData; /** * Provides data source summary information pertaining to Timeline data. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index d892b4a9c4..ea4a85f406 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -29,12 +29,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory; -import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; -import org.sleuthkit.autopsy.contentutils.TypesSummary.FileTypeCategoryData; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummaryGetter; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummaryGetter; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummaryGetter; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceInfoUtilities; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary.FileTypeCategoryData; +import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesSummaryGetter.java similarity index 96% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummaryGetter.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesSummaryGetter.java index 7e0129382d..5bc6bf92ab 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesSummaryGetter.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.datasourcesummary.ui; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; import java.sql.SQLException; @@ -25,8 +25,8 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.contentutils.TypesSummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary; +import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index 9a6cf1ee42..3ac26a3b1e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -28,13 +28,12 @@ import java.util.Locale; import java.util.function.Function; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.LastAccessedArtifact; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopAccountResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDeviceAttachedResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDomainsResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopProgramsResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopWebSearchResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.LastAccessedArtifact; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopAccountResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDeviceAttachedResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopProgramsResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopWebSearchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java similarity index 92% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryGetter.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java index 73ac071470..04da065833 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.datamodel; +package org.sleuthkit.autopsy.datasourcesummary.ui; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; import java.util.Arrays; @@ -26,15 +26,15 @@ import java.util.List; import java.util.Set; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopAccountResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDeviceAttachedResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDomainsResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopProgramsResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopWebSearchResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopAccountResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDeviceAttachedResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopProgramsResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopWebSearchResult; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; /** diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java index 6ae7bb0381..865ffddd01 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java @@ -24,7 +24,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.contentutils.AnalysisSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummary; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelSheetExport; import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getTableExport; import org.sleuthkit.datamodel.DataSource; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java index 6d297abc0f..949bd853af 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java @@ -25,9 +25,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.contentutils.ContainerSummary; -import org.sleuthkit.autopsy.contentutils.ContainerSummary.ContainerDetails; -import org.sleuthkit.autopsy.contentutils.ContainerSummary.ImageDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary.ContainerDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary.ImageDetails; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelSheetExport; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.ExcelItemExportable; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.KeyValueItemExportable; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java index 1ea449b073..d320311485 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java @@ -27,11 +27,11 @@ import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.contentutils.GeolocationSummary.CityCountsList; -import org.sleuthkit.autopsy.contentutils.GeolocationSummary.CityData; -import org.sleuthkit.autopsy.contentutils.GeolocationSummary.CityRecordCount; -import org.sleuthkit.autopsy.contentutils.CityRecord; -import org.sleuthkit.autopsy.contentutils.GeolocationSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityCountsList; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityData; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityRecordCount; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.CityRecord; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary; import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getFetchResult; import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getTableExport; import org.sleuthkit.datamodel.DataSource; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java index 6448adb369..de6f027ed0 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java @@ -23,8 +23,8 @@ import java.util.Collections; import java.util.List; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.contentutils.PastCasesSummary; -import org.sleuthkit.autopsy.contentutils.PastCasesSummary.PastCasesResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.PastCasesResult; import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getFetchResult; import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getTableExport; import org.sleuthkit.datamodel.DataSource; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java index c9a57cc3aa..adb6068fe5 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java @@ -28,10 +28,10 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.contentutils.RecentFilesSummary; -import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentAttachmentDetails; -import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentDownloadDetails; -import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentFileDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails; import org.sleuthkit.datamodel.DataSource; /** diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java index e845093f08..3af85058a3 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java @@ -27,9 +27,9 @@ import java.util.Date; import java.util.List; import org.apache.commons.collections.CollectionUtils; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.contentutils.TimelineSummary; -import org.sleuthkit.autopsy.contentutils.TimelineSummary.DailyActivityAmount; -import org.sleuthkit.autopsy.contentutils.TimelineSummary.TimelineSummaryData; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.BarChartSeries.BarChartItem; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.BarChartSeries.OrderedKey; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.KeyValueItemExportable; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java index 9253b5b09b..1523540f23 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java @@ -30,11 +30,11 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.contentutils.ContainerSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory; -import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; -import org.sleuthkit.autopsy.contentutils.TypesSummary; -import org.sleuthkit.autopsy.contentutils.TypesSummary.FileTypeCategoryData; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceInfoUtilities; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary.FileTypeCategoryData; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.KeyValueItemExportable; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java index ba9ff135ce..6a1cb491e2 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java @@ -30,13 +30,13 @@ import java.util.stream.Stream; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.LastAccessedArtifact; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopAccountResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDeviceAttachedResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDomainsResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopProgramsResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopWebSearchResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.LastAccessedArtifact; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopAccountResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDeviceAttachedResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopProgramsResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopWebSearchResult; import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getTableExport; /** diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java index eb14d53e51..73fc864c61 100644 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java @@ -25,9 +25,9 @@ import java.util.Map; import java.util.stream.Collectors; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummaryGetter; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDomainsResult; +import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.ui.UserActivitySummaryGetter; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilitiesTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilitiesTest.java index 5179b4a509..1b5d809b1f 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilitiesTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilitiesTest.java @@ -27,7 +27,7 @@ import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities.SortOrder; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceInfoUtilities.SortOrder; import org.sleuthkit.datamodel.Blackboard; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -36,7 +36,6 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.testutils.TskMockUtils; import static org.mockito.Mockito.*; -import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities; import org.sleuthkit.autopsy.testutils.RandomizationUtils; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java index 302223a234..244a7da113 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.datasourcesummary.datamodel; +import org.sleuthkit.autopsy.datasourcesummary.ui.RecentFilesGetter; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; @@ -40,10 +41,10 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentAttachmentDetails; -import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentDownloadDetails; -import org.sleuthkit.autopsy.contentutils.RecentFilesSummary.RecentFileDetails; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails; +import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.testutils.RandomizationUtils; import org.sleuthkit.autopsy.testutils.TskMockUtils; import org.sleuthkit.datamodel.Blackboard; diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java index 787153543c..0fd7b72d9c 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.datasourcesummary.datamodel; +import org.sleuthkit.autopsy.datasourcesummary.ui.UserActivitySummaryGetter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -43,12 +44,12 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceSummaryMockUtils.getArtifactsTSKMock; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopAccountResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDeviceAttachedResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopDomainsResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopProgramsResult; -import org.sleuthkit.autopsy.contentutils.UserActivitySummary.TopWebSearchResult; +import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopAccountResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDeviceAttachedResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopProgramsResult; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopWebSearchResult; import org.sleuthkit.autopsy.testutils.TskMockUtils; import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException; import org.sleuthkit.autopsy.texttranslation.TextTranslationService; From ffd6be1823def155e7a4761edb8deb0557f53fd2 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 18 Aug 2021 18:18:45 -0400 Subject: [PATCH 39/76] Refactoring report module --- .../datamodel/AnalysisSummary.java | 36 +- .../datamodel/ClosestCityMapper.java | 27 +- .../datamodel/ContainerSummary.java | 63 +-- .../datamodel/DataSourceInfoUtilities.java | 34 +- .../datamodel/GeolocationSummary.java | 49 ++- .../datamodel/PastCasesSummary.java | 64 +++- .../datamodel/RecentFilesSummary.java | 39 +- .../SleuthkitCaseProvider.java | 2 +- .../datamodel/TimelineDataSourceUtils.java | 92 +++++ .../datamodel/TimelineSummary.java | 113 +++--- .../datamodel/TypesSummary.java | 65 ++-- .../datamodel/UserActivitySummary.java | 103 +++-- .../ui/AnalysisSummaryGetter.java | 24 +- .../ui/ContainerSummaryGetter.java | 30 +- .../ui/GeolocationSummaryGetter.java | 12 +- .../ui/MimeTypeSummaryGetter.java | 44 +-- .../ui/PastCasesSummaryGetter.java | 17 +- .../ui/RecentFilesGetter.java | 24 +- .../datasourcesummary/ui/TimelinePanel.java | 9 +- .../ui/TimelinePanel.java.bak | 358 ++++++++++++++++++ .../ui/TimelineSummaryGetter.java | 23 +- .../datasourcesummary/ui/TypesPanel.java | 2 +- .../ui/TypesSummaryGetter.java | 42 +- .../ui/UserActivitySummaryGetter.java | 36 +- .../ExcelExportAction.java | 16 +- .../ExportAnalysisResults.java | 13 +- .../ExportContainerInfo.java | 9 +- .../ExportGeolocation.java | 9 +- .../ExportPastCases.java | 9 +- .../ExportRecentFiles.java | 13 +- .../ExportTimeline.java | 9 +- .../datasourcesummaryexport/ExportTypes.java | 38 +- .../ExportUserActivity.java | 17 +- .../UserActivitySummaryTests.java | 2 +- .../datamodel/RecentFilesSummaryTest.java | 2 +- .../datamodel/UserActivitySummaryTest.java | 2 +- 36 files changed, 991 insertions(+), 456 deletions(-) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{ui => datamodel}/SleuthkitCaseProvider.java (97%) mode change 100644 => 100755 create mode 100755 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java create mode 100755 Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java.bak diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java index e5824b9f3f..60598f7529 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/AnalysisSummary.java @@ -28,8 +28,8 @@ import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -46,7 +46,22 @@ public class AnalysisSummary { private static final BlackboardAttribute.Type TYPE_SET_NAME = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME); private static final Set EXCLUDED_KEYWORD_SEARCH_ITEMS = new HashSet<>(); - private AnalysisSummary() { + private final SleuthkitCaseProvider provider; + + /** + * Main constructor. + */ + public AnalysisSummary() { + this(SleuthkitCaseProvider.DEFAULT); + } + + /** + * Main constructor. + * + * @param provider The means of obtaining a sleuthkit case. + */ + public AnalysisSummary(SleuthkitCaseProvider provider) { + this.provider = provider; } /** @@ -59,7 +74,7 @@ public class AnalysisSummary { * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public static List> getHashsetCounts(DataSource dataSource) throws NoCurrentCaseException, TskCoreException { + public List> getHashsetCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_HASHSET_HIT); } @@ -73,7 +88,7 @@ public class AnalysisSummary { * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public static List> getKeywordCounts(DataSource dataSource) throws NoCurrentCaseException, TskCoreException { + public List> getKeywordCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT).stream() // make sure we have a valid set and that that set does not belong to the set of excluded items .filter((pair) -> pair != null && pair.getKey() != null && !EXCLUDED_KEYWORD_SEARCH_ITEMS.contains(pair.getKey().toUpperCase().trim())) @@ -92,7 +107,7 @@ public class AnalysisSummary { * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public static List> getInterestingItemCounts(DataSource dataSource) throws NoCurrentCaseException, TskCoreException { + public List> getInterestingItemCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); } @@ -107,21 +122,22 @@ public class AnalysisSummary { * value and the value is the count of items found. This list is * sorted by the count descending max to min. * - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - private static List> getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes) - throws NoCurrentCaseException, TskCoreException { + private List> getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes) + throws SleuthkitCaseProviderException, TskCoreException { if (dataSource == null) { return Collections.emptyList(); } List artifacts = new ArrayList<>(); + SleuthkitCase skCase = provider.get(); // get all artifacts in one list for each artifact type for (ARTIFACT_TYPE type : artifactTypes) { - artifacts.addAll(Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(type.getTypeID(), dataSource.getId())); + artifacts.addAll(skCase.getBlackboard().getArtifacts(type.getTypeID(), dataSource.getId())); } // group those based on the value of the attribute type that should serve as a key diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ClosestCityMapper.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ClosestCityMapper.java index e2df913534..ecadc0931e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ClosestCityMapper.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ClosestCityMapper.java @@ -60,9 +60,6 @@ class ClosestCityMapper { // singleton instance of this class private static ClosestCityMapper instance = null; - // the logger - private static final java.util.logging.Logger logger = Logger.getLogger(ClosestCityMapper.class.getName()); - /** * Retrieves singleton instance of this class. * @@ -79,7 +76,10 @@ class ClosestCityMapper { } // data structure housing cities - private static LatLngMap latLngMap = null; + private LatLngMap latLngMap = null; + + // the logger + private final java.util.logging.Logger logger; /** * Main Constructor. @@ -87,7 +87,9 @@ class ClosestCityMapper { * @throws IOException */ private ClosestCityMapper() throws IOException { - this(ClosestCityMapper.class.getResourceAsStream(CITIES_CSV_FILENAME)); + this( + GeolocationSummary.class.getResourceAsStream(CITIES_CSV_FILENAME), + Logger.getLogger(ClosestCityMapper.class.getName())); } /** @@ -99,7 +101,8 @@ class ClosestCityMapper { * * @throws IOException */ - private ClosestCityMapper(InputStream citiesInputStream) throws IOException { + private ClosestCityMapper(InputStream citiesInputStream, java.util.logging.Logger logger) throws IOException { + this.logger = logger; latLngMap = new LatLngMap(parseCsvLines(citiesInputStream, true)); } @@ -111,7 +114,7 @@ class ClosestCityMapper { * * @return The closest city or null if no close city can be found. */ - static CityRecord findClosest(CityRecord point) { + CityRecord findClosest(CityRecord point) { return latLngMap.findClosest(point); } @@ -123,7 +126,7 @@ class ClosestCityMapper { * * @return The double value or null if value cannot be parsed. */ - private static Double tryParse(String s) { + private Double tryParse(String s) { if (s == null) { return null; } @@ -144,7 +147,7 @@ class ClosestCityMapper { * * @return The country name. */ - private static String parseCountryName(String orig, int lineNum) { + private String parseCountryName(String orig, int lineNum) { if (StringUtils.isBlank(orig)) { logger.log(Level.WARNING, String.format("No country name determined for line %d.", lineNum)); return null; @@ -167,7 +170,7 @@ class ClosestCityMapper { * * @return The parsed CityRecord or null if none can be determined. */ - private static CityRecord getCsvCityRecord(List csvRow, int lineNum) { + private CityRecord getCsvCityRecord(List csvRow, int lineNum) { if (csvRow == null || csvRow.size() <= MAX_IDX) { logger.log(Level.WARNING, String.format("Row at line number %d is required to have at least %d elements and does not.", lineNum, (MAX_IDX + 1))); return null; @@ -207,7 +210,7 @@ class ClosestCityMapper { * * @return The list of column values. */ - private static List parseCsvLine(String line, int lineNum) { + private List parseCsvLine(String line, int lineNum) { if (line == null || line.length() <= 0) { logger.log(Level.INFO, String.format("Line at %d had no content", lineNum)); return null; @@ -234,7 +237,7 @@ class ClosestCityMapper { * * @throws IOException */ - private static List parseCsvLines(InputStream csvInputStream, boolean ignoreHeaderRow) throws IOException { + private List parseCsvLines(InputStream csvInputStream, boolean ignoreHeaderRow) throws IOException { List cityRecords = new ArrayList<>(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(csvInputStream, "UTF-8"))) { int lineNum = 1; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java index 7bd34016f3..428c92047f 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java @@ -38,7 +38,22 @@ import org.sleuthkit.datamodel.TskData; */ public class ContainerSummary { - private ContainerSummary() { + private final SleuthkitCaseProvider provider; + + /** + * Main constructor. + */ + public ContainerSummary() { + this(SleuthkitCaseProvider.DEFAULT); + } + + /** + * Main constructor. + * + * @param provider The means of obtaining a sleuthkit case. + */ + public ContainerSummary(SleuthkitCaseProvider provider) { + this.provider = provider; } /** @@ -48,12 +63,12 @@ public class ContainerSummary { * * @return The size or null if the query could not be executed. * - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException * @throws TskCoreException * @throws SQLException */ - public static Long getSizeOfUnallocatedFiles(DataSource currentDataSource) - throws TskCoreException, SQLException, NoCurrentCaseException { + public Long getSizeOfUnallocatedFiles(DataSource currentDataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { if (currentDataSource == null) { return null; } @@ -79,7 +94,7 @@ public class ContainerSummary { } }; - return DataSourceInfoUtilities.getBaseQueryResult(query, handler); + return DataSourceInfoUtilities.getBaseQueryResult(provider.get(), query, handler); } /** @@ -91,12 +106,12 @@ public class ContainerSummary { * @return The concatenated value or null if the query could not be * executed. * - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException * @throws TskCoreException * @throws SQLException */ - public static String getOperatingSystems(DataSource dataSource) - throws TskCoreException, SQLException, NoCurrentCaseException { + public String getOperatingSystems(DataSource dataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { if (dataSource == null) { return null; @@ -116,12 +131,12 @@ public class ContainerSummary { * @return The concatenated value or null if the query could not be * executed. * - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException * @throws TskCoreException * @throws SQLException */ - public static String getDataSourceType(DataSource dataSource) - throws TskCoreException, SQLException, NoCurrentCaseException { + public String getDataSourceType(DataSource dataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { if (dataSource == null) { return null; @@ -136,19 +151,19 @@ public class ContainerSummary { * Generates a string which is a concatenation of the value received from * the result set. * - * @param query The query. - * @param valueParam The parameter for the value in the result set. - * @param separator The string separator used in concatenation. + * @param query The query. + * @param valueParam The parameter for the value in the result set. + * @param separator The string separator used in concatenation. * * @return The concatenated string or null if the query could not be * executed. * - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException * @throws TskCoreException * @throws SQLException */ - private static String getConcattedStringsResult(String query, String valueParam, String separator) - throws TskCoreException, SQLException, NoCurrentCaseException { + private String getConcattedStringsResult(String query, String valueParam, String separator) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { DataSourceInfoUtilities.ResultSetHandler handler = (resultSet) -> { String toRet = ""; @@ -165,7 +180,7 @@ public class ContainerSummary { return toRet; }; - return DataSourceInfoUtilities.getBaseQueryResult(query, handler); + return DataSourceInfoUtilities.getBaseQueryResult(provider.get(), query, handler); } /** @@ -179,12 +194,12 @@ public class ContainerSummary { * @return The concatenated value or null if the query could not be * executed. * - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException * @throws TskCoreException * @throws SQLException */ - private static String getConcattedAttrValue(long dataSourceId, int artifactTypeId, int attributeTypeId) - throws TskCoreException, SQLException, NoCurrentCaseException { + private String getConcattedAttrValue(long dataSourceId, int artifactTypeId, int attributeTypeId) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { final String valueParam = "concatted_attribute_value"; String query = "SELECT attr.value_text AS " + valueParam @@ -198,6 +213,8 @@ public class ContainerSummary { return getConcattedStringsResult(query, valueParam, separator); } + // ELTODO everything below is NOT in develop! + /** * Data model data for data source images. */ @@ -383,7 +400,7 @@ public class ContainerSummary { * * @return The generated view model. */ - public static ContainerDetails getContainerDetails(DataSource ds) throws TskCoreException, SQLException, NoCurrentCaseException { + public ContainerDetails getContainerDetails(DataSource ds) throws TskCoreException, SQLException, SleuthkitCaseProvider.SleuthkitCaseProviderException { if (ds == null) { return null; } @@ -404,7 +421,7 @@ public class ContainerSummary { * * @return The generated view model. */ - public static ImageDetails getImageDetails(Image image) throws TskCoreException, SQLException, NoCurrentCaseException { + public ImageDetails getImageDetails(Image image) throws TskCoreException, SQLException, SleuthkitCaseProvider.SleuthkitCaseProviderException { if (image == null) { return null; } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java index 2847ea4510..7e51a53037 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java @@ -52,6 +52,7 @@ public final class DataSourceInfoUtilities { /** * Gets a count of tsk_files for a particular datasource. * + * @param skCase The current SleuthkitCase. * @param currentDataSource The datasource. * @param additionalWhere Additional sql where clauses. * @@ -59,12 +60,11 @@ public final class DataSourceInfoUtilities { * * @throws TskCoreException * @throws SQLException - * @throws NoCurrentCaseException */ - public static Long getCountOfTskFiles(DataSource currentDataSource, String additionalWhere) - throws TskCoreException, SQLException, NoCurrentCaseException { + static Long getCountOfTskFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) + throws TskCoreException, SQLException { if (currentDataSource != null) { - return Case.getCurrentCaseThrows().getSleuthkitCase().countFilesWhere( + return skCase.countFilesWhere( "data_source_obj_id=" + currentDataSource.getId() + (StringUtils.isBlank(additionalWhere) ? "" : (" AND " + additionalWhere))); } @@ -74,6 +74,7 @@ public final class DataSourceInfoUtilities { /** * Gets a count of regular files for a particular datasource. * + * @param skCase The current SleuthkitCase. * @param currentDataSource The datasource. * @param additionalWhere Additional sql where clauses. * @@ -81,22 +82,22 @@ public final class DataSourceInfoUtilities { * * @throws TskCoreException * @throws SQLException - * @throws NoCurrentCaseException */ - public static Long getCountOfRegularFiles(DataSource currentDataSource, String additionalWhere) - throws TskCoreException, SQLException, NoCurrentCaseException { + static Long getCountOfRegularFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) + throws TskCoreException, SQLException { String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue(); if (StringUtils.isNotBlank(additionalWhere)) { whereClause += " AND " + additionalWhere; } - return getCountOfTskFiles(currentDataSource, whereClause); + return getCountOfTskFiles(skCase, currentDataSource, whereClause); } /** * Gets a count of regular non-slack files for a particular datasource. * + * @param skCase The current SleuthkitCase. * @param currentDataSource The datasource. * @param additionalWhere Additional sql where clauses. * @@ -104,10 +105,9 @@ public final class DataSourceInfoUtilities { * * @throws TskCoreException * @throws SQLException - * @throws NoCurrentCaseException */ - public static Long getCountOfRegNonSlackFiles(DataSource currentDataSource, String additionalWhere) - throws TskCoreException, SQLException, NoCurrentCaseException { + public static Long getCountOfRegNonSlackFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere) + throws TskCoreException, SQLException { String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue() + " AND type<>" + TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType(); @@ -115,7 +115,7 @@ public final class DataSourceInfoUtilities { whereClause += " AND " + additionalWhere; } - return getCountOfTskFiles(currentDataSource, whereClause); + return getCountOfTskFiles(skCase, currentDataSource, whereClause); } /** @@ -129,6 +129,7 @@ public final class DataSourceInfoUtilities { /** * Retrieves a result based on the provided query. * + * @param skCase The current SleuthkitCase. * @param query The query. * @param processor The result set handler. * @@ -137,11 +138,10 @@ public final class DataSourceInfoUtilities { * * @throws TskCoreException * @throws SQLException - * @throws NoCurrentCaseException */ - public static T getBaseQueryResult(String query, ResultSetHandler processor) - throws TskCoreException, SQLException, NoCurrentCaseException { - try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCaseThrows().getSleuthkitCase().executeQuery(query)) { + static T getBaseQueryResult(SleuthkitCase skCase, String query, ResultSetHandler processor) + throws TskCoreException, SQLException { + try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(query)) { ResultSet resultSet = dbQuery.getResultSet(); return processor.process(resultSet); } @@ -433,6 +433,8 @@ public final class DataSourceInfoUtilities { Long longVal = getLongOrNull(artifact, attributeType); return (longVal == null || longVal == 0) ? null : new Date(longVal * 1000); } + + // ELTODO everything below is not in develop /** * Returns the long value or zero if longVal is null. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummary.java index b011dd8f4e..1b8f2feb8e 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/GeolocationSummary.java @@ -31,8 +31,7 @@ import java.util.concurrent.BlockingQueue; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.geolocation.AbstractWaypointFetcher; import org.sleuthkit.autopsy.geolocation.GeoFilter; import org.sleuthkit.autopsy.geolocation.MapWaypoint; @@ -238,12 +237,13 @@ public class GeolocationSummary { private static final long DAY_SECS = 24 * 60 * 60; - private static final SupplierWithException cityMapper = () -> ClosestCityMapper.getInstance(); + private final SleuthkitCaseProvider provider; + private final SupplierWithException cityMapper; /** * A supplier of an item T that can throw an exception of type E. */ - interface SupplierWithException { + public interface SupplierWithException { /** * A supplier method that can throw an exception of E. @@ -255,7 +255,23 @@ public class GeolocationSummary { T get() throws E; } - private GeolocationSummary() { + /** + * Default constructor. + */ + public GeolocationSummary() { + this(() -> ClosestCityMapper.getInstance(), SleuthkitCaseProvider.DEFAULT); + } + + /** + * Main constructor. + * + * @param cityMapper A means of acquiring a ClosestCityMapper that can throw + * an IOException. + * @param provider A means of acquiring a SleuthkitCaseProvider. + */ + public GeolocationSummary(SupplierWithException cityMapper, SleuthkitCaseProvider provider) { + this.cityMapper = cityMapper; + this.provider = provider; } /** @@ -321,7 +337,7 @@ public class GeolocationSummary { * * @return A tuple of the closest city and timestamp in seconds from epoch. */ - private static Pair getClosestWithTime(ClosestCityMapper cityMapper, MapWaypoint pt) { + private Pair getClosestWithTime(ClosestCityMapper cityMapper, MapWaypoint pt) { if (pt == null) { return null; } @@ -344,7 +360,7 @@ public class GeolocationSummary { * null if a closest is not determined) and the latest timestamp for * each. */ - private static Stream> reduceGrouping(Set points, ClosestCityMapper cityMapper) { + private Stream> reduceGrouping(Set points, ClosestCityMapper cityMapper) { if (points == null) { return Stream.empty(); } @@ -381,7 +397,7 @@ public class GeolocationSummary { * * @throws IOException */ - private static Stream> processGeoResult(GeoResult geoResult, ClosestCityMapper cityMapper) { + private Stream> processGeoResult(GeoResult geoResult, ClosestCityMapper cityMapper) { if (geoResult == null) { return Stream.empty(); } @@ -418,14 +434,14 @@ public class GeolocationSummary { * * @return The sorted list. * - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException * @throws GeoLocationDataException * @throws InterruptedException */ - public static CityData getCityCounts(DataSource dataSource, int daysCount, int maxCount) - throws NoCurrentCaseException, GeoLocationDataException, InterruptedException, IOException { + public CityData getCityCounts(DataSource dataSource, int daysCount, int maxCount) + throws SleuthkitCaseProviderException, GeoLocationDataException, InterruptedException, IOException { - ClosestCityMapper closestCityMapper = cityMapper.get(); + ClosestCityMapper closestCityMapper = this.cityMapper.get(); GeoResult geoResult = getGeoResult(dataSource); List> dataSourcePoints = processGeoResult(geoResult, closestCityMapper) .collect(Collectors.toList()); @@ -524,13 +540,12 @@ public class GeolocationSummary { * @param dataSource The data source. * * @return The GPS data pertaining to the data source. - * - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException * @throws GeoLocationDataException * @throws InterruptedException */ - private static GeoResult getGeoResult(DataSource dataSource) - throws NoCurrentCaseException, GeoLocationDataException, InterruptedException { + private GeoResult getGeoResult(DataSource dataSource) + throws SleuthkitCaseProviderException, GeoLocationDataException, InterruptedException { // make asynchronous callback synchronous (the callback nature will be handled in a different level) // see the following: https://stackoverflow.com/questions/20659961/java-synchronous-callback @@ -538,7 +553,7 @@ public class GeolocationSummary { GeoFilter geoFilter = new GeoFilter(true, false, 0, Arrays.asList(dataSource), GPS_ARTIFACT_TYPES); - WaypointBuilder.getAllWaypoints(Case.getCurrentCaseThrows().getSleuthkitCase(), + WaypointBuilder.getAllWaypoints(provider.get(), Arrays.asList(dataSource), GPS_ARTIFACT_TYPES, true, diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java index 5bfe52261c..66e265e128 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java @@ -25,12 +25,12 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -111,7 +111,34 @@ public class PastCasesSummary { private static final String CASE_SEPARATOR = ","; private static final String PREFIX_END = ":"; - private PastCasesSummary() { + private final SleuthkitCaseProvider caseProvider; + private final java.util.logging.Logger logger; + + /** + * Main constructor. + */ + public PastCasesSummary() { + this( + SleuthkitCaseProvider.DEFAULT, + org.sleuthkit.autopsy.coreutils.Logger.getLogger(PastCasesSummary.class.getName()) + ); + + } + + /** + * Main constructor with external dependencies specified. This constructor + * is designed with unit testing in mind since mocked dependencies can be + * utilized. + * + * @param provider The object providing the current SleuthkitCase. + * @param logger The logger to use. + */ + public PastCasesSummary( + SleuthkitCaseProvider provider, + java.util.logging.Logger logger) { + + this.caseProvider = provider; + this.logger = logger; } /** @@ -211,24 +238,21 @@ public class PastCasesSummary { * * @return The artifact if found or null if not. * - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException */ - private static BlackboardArtifact getParentArtifact(BlackboardArtifact artifact) throws NoCurrentCaseException { + private BlackboardArtifact getParentArtifact(BlackboardArtifact artifact) throws SleuthkitCaseProviderException { Long parentId = DataSourceInfoUtilities.getLongOrNull(artifact, TYPE_ASSOCIATED_ARTIFACT); if (parentId == null) { return null; } + SleuthkitCase skCase = caseProvider.get(); try { - return Case.getCurrentCaseThrows().getSleuthkitCase().getArtifactByArtifactId(parentId); - } catch (TskCoreException ignore) { - /* - * I'm not certain why we ignore this, but it was previously simply - * logged as warning so I'm keeping the original logic - * logger.log(Level.WARNING, String.format("There was an error - * fetching the parent artifact of a TSK_INTERESTING_ARTIFACT_HIT - * (parent id: %d)", parentId), ex); - */ + return skCase.getArtifactByArtifactId(parentId); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, + String.format("There was an error fetching the parent artifact of a TSK_INTERESTING_ARTIFACT_HIT (parent id: %d)", parentId), + ex); return null; } } @@ -240,9 +264,9 @@ public class PastCasesSummary { * * @return True if there is a device associated artifact. * - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException */ - private static boolean hasDeviceAssociatedArtifact(BlackboardArtifact artifact) throws NoCurrentCaseException { + private boolean hasDeviceAssociatedArtifact(BlackboardArtifact artifact) throws SleuthkitCaseProviderException { BlackboardArtifact parent = getParentArtifact(artifact); if (parent == null) { return false; @@ -258,17 +282,17 @@ public class PastCasesSummary { * * @return The retrieved data or null if null dataSource. * - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public static PastCasesResult getPastCasesData(DataSource dataSource) - throws NoCurrentCaseException, TskCoreException { + public PastCasesResult getPastCasesData(DataSource dataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { if (dataSource == null) { return null; } - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + SleuthkitCase skCase = caseProvider.get(); List deviceArtifactCases = new ArrayList<>(); List nonDeviceArtifactCases = new ArrayList<>(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java index 77504394dd..1beb97766b 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummary.java @@ -29,8 +29,7 @@ import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import org.apache.commons.lang.StringUtils; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -55,10 +54,26 @@ public class RecentFilesSummary { private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.getDefault()); + private final SleuthkitCaseProvider provider; + /** * Default constructor. */ - private RecentFilesSummary() { + public RecentFilesSummary() { + this(SleuthkitCaseProvider.DEFAULT); + } + + /** + * Construct object with given SleuthkitCaseProvider + * + * @param provider SleuthkitCaseProvider provider, cannot be null. + */ + public RecentFilesSummary(SleuthkitCaseProvider provider) { + if (provider == null) { + throw new IllegalArgumentException("Unable to construct RecentFileSummary object. SleuthkitCaseProvider cannot be null"); + } + + this.provider = provider; } /** @@ -112,17 +127,17 @@ public class RecentFilesSummary { * @return A list RecentFileDetails representing the most recently opened * documents or an empty list if none were found. * - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public static List getRecentlyOpenedDocuments(DataSource dataSource, int maxCount) throws TskCoreException, NoCurrentCaseException { + public List getRecentlyOpenedDocuments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException { if (dataSource == null) { return Collections.emptyList(); } throwOnNonPositiveCount(maxCount); - List details = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard() + List details = provider.get().getBlackboard() .getArtifacts(ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID(), dataSource.getId()).stream() .map(art -> getRecentlyOpenedDocument(art)) .filter(d -> d != null) @@ -173,16 +188,16 @@ public class RecentFilesSummary { * found. * * @throws TskCoreException - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException */ - public static List getRecentDownloads(DataSource dataSource, int maxCount) throws TskCoreException, NoCurrentCaseException { + public List getRecentDownloads(DataSource dataSource, int maxCount) throws TskCoreException, SleuthkitCaseProviderException { if (dataSource == null) { return Collections.emptyList(); } throwOnNonPositiveCount(maxCount); - List details = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard() + List details = provider.get().getBlackboard() .getArtifacts(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID(), dataSource.getId()).stream() .map(art -> getRecentDownload(art)) .filter(d -> d != null) @@ -200,17 +215,17 @@ public class RecentFilesSummary { * * @return A list of RecentFileDetails of the most recent attachments. * - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public static List getRecentAttachments(DataSource dataSource, int maxCount) throws NoCurrentCaseException, TskCoreException { + public List getRecentAttachments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException { if (dataSource == null) { return Collections.emptyList(); } throwOnNonPositiveCount(maxCount); - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + SleuthkitCase skCase = provider.get(); List associatedArtifacts = skCase.getBlackboard() .getArtifacts(ASSOCATED_OBJ_ART.getTypeID(), dataSource.getId()); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SleuthkitCaseProvider.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/SleuthkitCaseProvider.java old mode 100644 new mode 100755 similarity index 97% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SleuthkitCaseProvider.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/SleuthkitCaseProvider.java index 90afc2d597..8371b2fefd --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/SleuthkitCaseProvider.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/SleuthkitCaseProvider.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.ui; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java new file mode 100755 index 0000000000..6528284911 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineDataSourceUtils.java @@ -0,0 +1,92 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 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.datasourcesummary.datamodel; + +import org.sleuthkit.autopsy.timeline.TimeLineController; +import org.sleuthkit.autopsy.timeline.TimeLineModule; +import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.FilterState; +import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TimelineFilter; +import org.sleuthkit.datamodel.TimelineFilter.DataSourceFilter; +import org.sleuthkit.datamodel.TimelineFilter.RootFilter; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Utilities for interacting with Timeline in relation to data sources. + */ +public class TimelineDataSourceUtils { + + private static TimelineDataSourceUtils instance = null; + + /** + * @return Singleton instance of this class. + */ + public static TimelineDataSourceUtils getInstance() { + if (instance == null) { + instance = new TimelineDataSourceUtils(); + } + + return instance; + } + + /** + * Main constructor. Should be instantiated through getInstance(). + */ + private TimelineDataSourceUtils() { + } + + /** + * Retrieves a RootFilter based on the default filter state but only the + * specified dataSource is selected. + * + * @param dataSource The data source. + * @return The root filter representing a default filter with only this data + * source selected. + * @throws TskCoreException + */ + public RootFilter getDataSourceFilter(DataSource dataSource) throws TskCoreException { + RootFilterState filterState = getDataSourceFilterState(dataSource); + return filterState == null ? null : filterState.getActiveFilter(); + } + + /** + * Retrieves a TimeLineController based on the default filter state but only + * the specified dataSource is selected. + * + * @param dataSource The data source. + * @return The root filter state representing a default filter with only + * this data source selected. + * @throws TskCoreException + */ + public RootFilterState getDataSourceFilterState(DataSource dataSource) throws TskCoreException { + TimeLineController controller = TimeLineModule.getController(); + RootFilterState dataSourceState = controller.getEventsModel().getDefaultEventFilterState().copyOf(); + + for (FilterState filterState : dataSourceState.getDataSourcesFilterState().getSubFilterStates()) { + DataSourceFilter dsFilter = filterState.getFilter(); + if (dsFilter != null) { + filterState.setSelected(dsFilter.getDataSourceID() == dataSource.getId()); + } + + } + + return dataSourceState; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java index c21927b4df..28c616a89f 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TimelineSummary.java @@ -39,21 +39,31 @@ import org.sleuthkit.datamodel.TimelineEventType; import org.sleuthkit.datamodel.TimelineFilter.RootFilter; import org.sleuthkit.datamodel.TimelineManager; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import java.util.function.Supplier; import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.timeline.TimeLineController; -import org.sleuthkit.autopsy.timeline.TimeLineModule; -import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.FilterState; -import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState; -import org.sleuthkit.datamodel.TimelineFilter; /** * Provides data source summary information pertaining to Timeline data. */ public class TimelineSummary { - private static final TimeZone timeZone = TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()); + /** + * A function for obtaining a Timeline RootFilter filtered to the specific + * data source. + */ + public interface DataSourceFilterFunction { + + /** + * Obtains a Timeline RootFilter filtered to the specific data source. + * + * @param dataSource The data source. + * @return The timeline root filter. + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + */ + RootFilter apply(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException; + } private static final long DAY_SECS = 24 * 60 * 60; private static final Set FILE_SYSTEM_EVENTS @@ -63,7 +73,31 @@ public class TimelineSummary { TimelineEventType.FILE_CREATED, TimelineEventType.FILE_CHANGED)); - private TimelineSummary() { + private final SleuthkitCaseProvider caseProvider; + private final Supplier timeZoneProvider; + private final DataSourceFilterFunction filterFunction; + + /** + * Default constructor. + */ + public TimelineSummary() { + this(SleuthkitCaseProvider.DEFAULT, + () -> TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()), + (ds) -> TimelineDataSourceUtils.getInstance().getDataSourceFilter(ds)); + } + + /** + * Construct object with given SleuthkitCaseProvider + * + * @param caseProvider SleuthkitCaseProvider provider; cannot be null. + * @param timeZoneProvider The timezone provider; cannot be null. + * @param filterFunction Provides the default root filter function filtered + * to the data source; cannot be null. + */ + public TimelineSummary(SleuthkitCaseProvider caseProvider, Supplier timeZoneProvider, DataSourceFilterFunction filterFunction) { + this.caseProvider = caseProvider; + this.timeZoneProvider = timeZoneProvider; + this.filterFunction = filterFunction; } /** @@ -75,12 +109,12 @@ public class TimelineSummary { * include. * * @return The retrieved data. - * + * @throws SleuthkitCaseProviderException * @throws TskCoreException - * @throws NoCurrentCaseException */ - public static TimelineSummaryData getTimelineSummaryData(DataSource dataSource, int recentDaysNum) throws TskCoreException, NoCurrentCaseException { - TimelineManager timelineManager = Case.getCurrentCaseThrows().getSleuthkitCase().getTimelineManager(); + public TimelineSummaryData getTimelineSummaryData(DataSource dataSource, int recentDaysNum) throws SleuthkitCaseProviderException, TskCoreException { + TimeZone timeZone = this.timeZoneProvider.get(); + TimelineManager timelineManager = this.caseProvider.get().getTimelineManager(); // get a mapping of days from epoch to the activity for that day Map dateCounts = getTimelineEventsByDay(dataSource, timelineManager, timeZone); @@ -122,7 +156,7 @@ public class TimelineSummary { * * @return The most recent daily activity amounts. */ - private static List getMostRecentActivityAmounts(Map dateCounts, long minRecentDay, long maxDay) { + private List getMostRecentActivityAmounts(Map dateCounts, long minRecentDay, long maxDay) { List mostRecentActivityAmt = new ArrayList<>(); for (long curRecentDay = minRecentDay; curRecentDay <= maxDay; curRecentDay++) { @@ -148,11 +182,10 @@ public class TimelineSummary { * @return A Map mapping days from epoch to the activity for that day. * * @throws TskCoreException - * @throws NoCurrentCaseException */ - private static Map getTimelineEventsByDay(DataSource dataSource, TimelineManager timelineManager, TimeZone timeZone) - throws TskCoreException, NoCurrentCaseException { - RootFilter rootFilter = getDataSourceFilter(dataSource); + private Map getTimelineEventsByDay(DataSource dataSource, TimelineManager timelineManager, TimeZone timeZone) + throws TskCoreException, SleuthkitCaseProviderException { + RootFilter rootFilter = this.filterFunction.apply(dataSource); // get events for data source long curRunTime = System.currentTimeMillis(); @@ -287,50 +320,6 @@ public class TimelineSummary { } } - /** - * Retrieves a RootFilter based on the default filter state but only the - * specified dataSource is selected. - * - * @param dataSource The data source. - * - * @return The root filter representing a default filter with only this data - * source selected. - * - * @throws NoCurrentCaseException - * @throws TskCoreException - */ - public static RootFilter getDataSourceFilter(DataSource dataSource) throws NoCurrentCaseException, TskCoreException { - RootFilterState filterState = getDataSourceFilterState(dataSource); - return filterState == null ? null : filterState.getActiveFilter(); - } - - /** - * Retrieves a TimeLineController based on the default filter state but only - * the specified dataSource is selected. - * - * @param dataSource The data source. - * - * @return The root filter state representing a default filter with only - * this data source selected. - * - * @throws NoCurrentCaseException - * @throws TskCoreException - */ - public static RootFilterState getDataSourceFilterState(DataSource dataSource) throws NoCurrentCaseException, TskCoreException { - TimeLineController controller = TimeLineModule.getController(); - RootFilterState dataSourceState = controller.getEventsModel().getDefaultEventFilterState().copyOf(); - - for (FilterState filterState : dataSourceState.getDataSourcesFilterState().getSubFilterStates()) { - TimelineFilter.DataSourceFilter dsFilter = filterState.getFilter(); - if (dsFilter != null) { - filterState.setSelected(dsFilter.getDataSourceID() == dataSource.getId()); - } - - } - - return dataSourceState; - } - /** * Creates a DateFormat formatter that uses UTC for time zone. * diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java index a0fc5c7aa9..6c1b71861b 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.awt.Color; import java.sql.SQLException; import java.util.Set; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.FileTypeUtils; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; @@ -33,9 +32,25 @@ import org.sleuthkit.datamodel.TskData; */ public class TypesSummary { - private TypesSummary() { + private final SleuthkitCaseProvider provider; + + /** + * Main constructor. + */ + public TypesSummary() { + this(SleuthkitCaseProvider.DEFAULT); } + /** + * Main constructor. + * + * @param provider The means of obtaining a sleuthkit case. + */ + public TypesSummary(SleuthkitCaseProvider provider) { + this.provider = provider; + } + + /** * Get count of regular files (not directories) in a data source. * @@ -43,13 +58,17 @@ public class TypesSummary { * * @return The count. * + * @throws SleuthkitCaseProviderException * @throws TskCoreException * @throws SQLException - * @throws NoCurrentCaseException */ - public static Long getCountOfFiles(DataSource currentDataSource) - throws TskCoreException, SQLException, NoCurrentCaseException { - return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource, null); + public Long getCountOfFiles(DataSource currentDataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { + return DataSourceInfoUtilities.getCountOfRegularFiles( + provider.get(), + currentDataSource, + null + ); } /** @@ -59,14 +78,14 @@ public class TypesSummary { * * @return The count. * + * @throws SleuthkitCaseProviderException * @throws TskCoreException * @throws SQLException - * @throws NoCurrentCaseException */ - public static Long getCountOfAllocatedFiles(DataSource currentDataSource) - throws TskCoreException, SQLException, NoCurrentCaseException { + public Long getCountOfAllocatedFiles(DataSource currentDataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)); } @@ -77,14 +96,14 @@ public class TypesSummary { * * @return The count. * + * @throws SleuthkitCaseProviderException * @throws TskCoreException * @throws SQLException - * @throws NoCurrentCaseException */ - public static Long getCountOfUnallocatedFiles(DataSource currentDataSource) - throws NoCurrentCaseException, TskCoreException, SQLException { + public Long getCountOfUnallocatedFiles(DataSource currentDataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)); } @@ -95,14 +114,14 @@ public class TypesSummary { * * @return The count. * + * @throws SleuthkitCaseProviderException * @throws TskCoreException * @throws SQLException - * @throws NoCurrentCaseException */ - public static Long getCountOfDirectories(DataSource currentDataSource) - throws NoCurrentCaseException, TskCoreException, SQLException { + public Long getCountOfDirectories(DataSource currentDataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - return DataSourceInfoUtilities.getCountOfTskFiles(currentDataSource, + return DataSourceInfoUtilities.getCountOfTskFiles(provider.get(), currentDataSource, "meta_type=" + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue() + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()); } @@ -114,16 +133,18 @@ public class TypesSummary { * * @return The count. * + * @throws SleuthkitCaseProviderException * @throws TskCoreException * @throws SQLException - * @throws NoCurrentCaseException */ - public static Long getCountOfSlackFiles(DataSource currentDataSource) - throws NoCurrentCaseException, TskCoreException, SQLException { + public Long getCountOfSlackFiles(DataSource currentDataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource, + return DataSourceInfoUtilities.getCountOfRegularFiles(provider.get(), currentDataSource, "type=" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()); } + + // ELTODO everything below is not in develop /** * Information concerning a particular file type category. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java index 5b51d10461..8310c1f5b0 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java @@ -31,13 +31,13 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Function; +import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.DataSource; @@ -144,7 +144,35 @@ public class UserActivitySummary { private static final long DOMAIN_WINDOW_DAYS = 30; private static final long DOMAIN_WINDOW_MS = DOMAIN_WINDOW_DAYS * MS_PER_DAY; - private UserActivitySummary() { + private final SleuthkitCaseProvider caseProvider; + private final TextTranslationService translationService; + private final java.util.logging.Logger logger; + + /** + * Main constructor. + */ + public UserActivitySummary() { + this(SleuthkitCaseProvider.DEFAULT, TextTranslationService.getInstance(), + org.sleuthkit.autopsy.coreutils.Logger.getLogger(UserActivitySummary.class.getName())); + } + + /** + * Main constructor with external dependencies specified. This constructor + * is designed with unit testing in mind since mocked dependencies can be + * utilized. + * + * @param provider The object providing the current SleuthkitCase. + * @param translationService The translation service. + * @param logger The logger to use. + */ + public UserActivitySummary( + SleuthkitCaseProvider provider, + TextTranslationService translationService, + java.util.logging.Logger logger) { + + this.caseProvider = provider; + this.translationService = translationService; + this.logger = logger; } /** @@ -158,6 +186,7 @@ public class UserActivitySummary { } } + // ELTODO this method is not in develop /** * Determines a short folder name if any. Otherwise, returns empty string. * @@ -199,10 +228,9 @@ public class UserActivitySummary { * * @return The list of items retrieved from the database. * - * @throws TskCoreException - * @throws NoCurrentCaseException + * @throws InterruptedException */ - public static List getRecentDomains(DataSource dataSource, int count) throws TskCoreException, NoCurrentCaseException { + public List getRecentDomains(DataSource dataSource, int count) throws TskCoreException, SleuthkitCaseProviderException { assertValidCount(count); if (dataSource == null) { @@ -240,7 +268,7 @@ public class UserActivitySummary { * @return The TopDomainsResult or null if no visits to this domain within * 30 days of mostRecentMs. */ - private static TopDomainsResult getDomainsResult(String domain, List> visits, long mostRecentMs) { + private TopDomainsResult getDomainsResult(String domain, List> visits, long mostRecentMs) { long visitCount = 0; Long thisMostRecentMs = null; BlackboardArtifact thisMostRecentArtifact = null; @@ -283,10 +311,10 @@ public class UserActivitySummary { * visited and the relevant artifact. * * @throws TskCoreException - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException */ - private static Pair>>> getDomainGroupsAndMostRecent(DataSource dataSource) throws TskCoreException, NoCurrentCaseException { - List artifacts = DataSourceInfoUtilities.getArtifacts(Case.getCurrentCaseThrows().getSleuthkitCase(), TYPE_WEB_HISTORY, + private Pair>>> getDomainGroupsAndMostRecent(DataSource dataSource) throws TskCoreException, SleuthkitCaseProviderException { + List artifacts = DataSourceInfoUtilities.getArtifacts(caseProvider.get(), TYPE_WEB_HISTORY, dataSource, TYPE_DATETIME_ACCESSED, DataSourceInfoUtilities.SortOrder.DESCENDING, 0); Long mostRecentMs = null; @@ -368,10 +396,11 @@ public class UserActivitySummary { * @return The list of most recent web searches where most recent search * appears first. * - * @throws NoCurrentCaseException + * @throws + * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException * @throws TskCoreException */ - public static List getMostRecentWebSearches(DataSource dataSource, int count) throws NoCurrentCaseException, TskCoreException { + public List getMostRecentWebSearches(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { assertValidCount(count); if (dataSource == null) { @@ -379,7 +408,7 @@ public class UserActivitySummary { } // get the artifacts - List webSearchArtifacts = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard() + List webSearchArtifacts = caseProvider.get().getBlackboard() .getArtifacts(ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID(), dataSource.getId()); // group by search string (case insensitive) @@ -406,7 +435,6 @@ public class UserActivitySummary { .collect(Collectors.toList()); // get translation if possible - TextTranslationService translationService = TextTranslationService.getInstance(); if (translationService.hasProvider()) { for (TopWebSearchResult result : results) { result.setTranslatedResult(getTranslationOrNull(result.getSearchString())); @@ -423,10 +451,9 @@ public class UserActivitySummary { * @param original The original text. * * @return The translated text or null if no translation can be determined - * or exists. + * or exists. */ - private static String getTranslationOrNull(String original) { - TextTranslationService translationService = TextTranslationService.getInstance(); + private String getTranslationOrNull(String original) { if (!translationService.hasProvider() || StringUtils.isBlank(original)) { return null; } @@ -434,9 +461,8 @@ public class UserActivitySummary { String translated = null; try { translated = translationService.translate(original); - } catch (NoServiceProviderException | TranslationException ignore) { - // Original logic ignored this error and simply logged it as warning so i'm keeping the same logic - // logger.log(Level.WARNING, String.format("There was an error translating text: '%s'", original), ex); + } catch (NoServiceProviderException | TranslationException ex) { + logger.log(Level.WARNING, String.format("There was an error translating text: '%s'", original), ex); } // if there is no translation or the translation is the same as the original, return null. @@ -458,8 +484,8 @@ public class UserActivitySummary { * * @return The most recent one with a non-null date. */ - private static TopDeviceAttachedResult getMostRecentDevice(TopDeviceAttachedResult r1, TopDeviceAttachedResult r2) { - if (r2.getLastAccessed() == null) { + private TopDeviceAttachedResult getMostRecentDevice(TopDeviceAttachedResult r1, TopDeviceAttachedResult r2) { + if (r2.getLastAccessed()== null) { return r1; } @@ -480,17 +506,18 @@ public class UserActivitySummary { * @return The list of most recent devices attached where most recent device * attached appears first. * - * @throws NoCurrentCaseException + * @throws + * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException * @throws TskCoreException */ - public static List getRecentDevices(DataSource dataSource, int count) throws NoCurrentCaseException, TskCoreException { + public List getRecentDevices(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { assertValidCount(count); if (dataSource == null) { return Collections.emptyList(); } - Collection results = DataSourceInfoUtilities.getArtifacts(Case.getCurrentCaseThrows().getSleuthkitCase(), TYPE_DEVICE_ATTACHED, + Collection results = DataSourceInfoUtilities.getArtifacts(caseProvider.get(), TYPE_DEVICE_ATTACHED, dataSource, TYPE_DATETIME, DataSourceInfoUtilities.SortOrder.DESCENDING, 0) .stream() .map(artifact -> { @@ -565,30 +592,30 @@ public class UserActivitySummary { * sent. * * @param dataSource The data source. - * @param count The maximum number of records to be shown (must be > - * 0). + * @param count The maximum number of records to be shown (must be > 0). * * @return The list of most recent accounts used where the most recent - * account by last message sent occurs first. + * account by last message sent occurs first. * - * @throws NoCurrentCaseException + * @throws + * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException * @throws TskCoreException */ @Messages({ "DataSourceUserActivitySummary_getRecentAccounts_emailMessage=Email Message", "DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=Call Log",}) - public static List getRecentAccounts(DataSource dataSource, int count) throws NoCurrentCaseException, TskCoreException { + public List getRecentAccounts(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { assertValidCount(count); if (dataSource == null) { return Collections.emptyList(); } - Stream messageResults = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(), dataSource.getId()) + Stream messageResults = caseProvider.get().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(), dataSource.getId()) .stream() .map((art) -> getMessageAccountResult(art)); - Stream emailResults = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(), dataSource.getId()) + Stream emailResults = caseProvider.get().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(), dataSource.getId()) .stream() .map((art) -> { return getAccountResult( @@ -598,7 +625,7 @@ public class UserActivitySummary { TYPE_DATETIME_SENT); }); - Stream calllogResults = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_CALLLOG.getTypeID(), dataSource.getId()) + Stream calllogResults = caseProvider.get().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_CALLLOG.getTypeID(), dataSource.getId()) .stream() .map((art) -> { return getAccountResult( @@ -639,7 +666,7 @@ public class UserActivitySummary { * * @return The generated TopProgramsResult. */ - private static TopProgramsResult getTopProgramsResult(BlackboardArtifact artifact) { + private TopProgramsResult getTopProgramsResult(BlackboardArtifact artifact) { String programName = DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_PROG_NAME); // ignore items with no name or a ntos boot identifier @@ -691,7 +718,7 @@ public class UserActivitySummary { * @param long2 Second possibly null long. * * @return Returns the compare value: 1,0,-1 favoring the higher non-null - * value. + * value. */ private static int nullableCompare(Long long1, Long long2) { if (long1 == null && long2 == null) { @@ -732,10 +759,10 @@ public class UserActivitySummary { * @return The sorted list and limited to the count if last run or run count * information is available on any item. * - * @throws NoCurrentCaseException + * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - public static List getTopPrograms(DataSource dataSource, int count) throws NoCurrentCaseException, TskCoreException { + public List getTopPrograms(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { assertValidCount(count); if (dataSource == null) { @@ -743,7 +770,7 @@ public class UserActivitySummary { } // Get TopProgramsResults for each TSK_PROG_RUN artifact - Collection results = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID(), dataSource.getId()) + Collection results = caseProvider.get().getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID(), dataSource.getId()) .stream() // convert to a TopProgramsResult object or null if missing critical information .map((art) -> getTopProgramsResult(art)) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisSummaryGetter.java index 9f2a19d72b..f4891a0b37 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisSummaryGetter.java @@ -25,9 +25,8 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.lang3.tuple.Pair; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummary; -import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; @@ -46,10 +45,13 @@ public class AnalysisSummaryGetter implements DefaultArtifactUpdateGovernor { ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() )); + AnalysisSummary analysisSummary; + /** * Main constructor. */ public AnalysisSummaryGetter() { + analysisSummary = new AnalysisSummary(); } @Override @@ -68,11 +70,7 @@ public class AnalysisSummaryGetter implements DefaultArtifactUpdateGovernor { * @throws TskCoreException */ public List> getHashsetCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { - try { - return AnalysisSummary.getHashsetCounts(dataSource); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return analysisSummary.getHashsetCounts(dataSource); } /** @@ -86,11 +84,7 @@ public class AnalysisSummaryGetter implements DefaultArtifactUpdateGovernor { * @throws TskCoreException */ public List> getKeywordCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { - try { - return AnalysisSummary.getKeywordCounts(dataSource); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return analysisSummary.getKeywordCounts(dataSource); } /** @@ -106,10 +100,6 @@ public class AnalysisSummaryGetter implements DefaultArtifactUpdateGovernor { * @throws TskCoreException */ public List> getInterestingItemCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { - try { - return AnalysisSummary.getInterestingItemCounts(dataSource); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return analysisSummary.getInterestingItemCounts(dataSource); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerSummaryGetter.java index 68bff3d987..4770359911 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerSummaryGetter.java @@ -24,9 +24,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; -import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -45,10 +44,13 @@ public class ContainerSummaryGetter implements DefaultArtifactUpdateGovernor { BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID() )); + private ContainerSummary containerSummary; + /** * Main constructor. */ public ContainerSummaryGetter() { + containerSummary = new ContainerSummary(); } @Override @@ -79,11 +81,7 @@ public class ContainerSummaryGetter implements DefaultArtifactUpdateGovernor { */ public Long getSizeOfUnallocatedFiles(DataSource currentDataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - try { - return ContainerSummary.getSizeOfUnallocatedFiles(currentDataSource); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return containerSummary.getSizeOfUnallocatedFiles(currentDataSource); } /** @@ -101,11 +99,7 @@ public class ContainerSummaryGetter implements DefaultArtifactUpdateGovernor { */ public String getOperatingSystems(DataSource dataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - try { - return ContainerSummary.getOperatingSystems(dataSource); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return containerSummary.getOperatingSystems(dataSource); } /** @@ -123,11 +117,7 @@ public class ContainerSummaryGetter implements DefaultArtifactUpdateGovernor { */ public String getDataSourceType(DataSource dataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - try { - return ContainerSummary.getDataSourceType(dataSource); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return containerSummary.getDataSourceType(dataSource); } /** @@ -145,10 +135,6 @@ public class ContainerSummaryGetter implements DefaultArtifactUpdateGovernor { */ public ContainerSummary.ContainerDetails getContainerDetails(DataSource dataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - try { - return ContainerSummary.getContainerDetails(dataSource); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return containerSummary.getContainerDetails(dataSource); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationSummaryGetter.java index 9a9dc7f61c..cea19db803 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationSummaryGetter.java @@ -23,7 +23,7 @@ import java.util.List; import java.util.Set; import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityData; -import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; @@ -37,10 +37,13 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; */ public class GeolocationSummaryGetter implements DefaultArtifactUpdateGovernor { + private GeolocationSummary geoSummary; + /** * Default constructor. */ public GeolocationSummaryGetter() { + geoSummary = new GeolocationSummary(); } /** @@ -71,11 +74,6 @@ public class GeolocationSummaryGetter implements DefaultArtifactUpdateGovernor { */ public CityData getCityCounts(DataSource dataSource, int daysCount, int maxCount) throws SleuthkitCaseProviderException, GeoLocationDataException, InterruptedException, IOException { - - try { - return GeolocationSummary.getCityCounts(dataSource, daysCount, maxCount); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return geoSummary.getCityCounts(dataSource, daysCount, maxCount); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/MimeTypeSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/MimeTypeSummaryGetter.java index f2a96cdd92..e4b06262ca 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/MimeTypeSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/MimeTypeSummaryGetter.java @@ -26,8 +26,8 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceInfoUtilities; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; @@ -44,10 +44,22 @@ public class MimeTypeSummaryGetter implements DefaultUpdateGovernor { private static final Set INGEST_JOB_EVENTS = new HashSet<>( Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED)); + private final SleuthkitCaseProvider provider; + /** * Main constructor. */ public MimeTypeSummaryGetter() { + this(SleuthkitCaseProvider.DEFAULT); + } + + /** + * Main constructor. + * + * @param provider The means of obtaining a sleuthkit case. + */ + public MimeTypeSummaryGetter(SleuthkitCaseProvider provider) { + this.provider = provider; } @Override @@ -90,11 +102,7 @@ public class MimeTypeSummaryGetter implements DefaultUpdateGovernor { */ public Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set setOfMimeTypes) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - try { - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "mime_type IN " + getSqlSet(setOfMimeTypes)); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, "mime_type IN " + getSqlSet(setOfMimeTypes)); } /** @@ -115,13 +123,9 @@ public class MimeTypeSummaryGetter implements DefaultUpdateGovernor { */ public Long getCountOfFilesNotInMimeTypes(DataSource currentDataSource, Set setOfMimeTypes) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - try { - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, - "mime_type NOT IN " + getSqlSet(setOfMimeTypes) - + " AND mime_type IS NOT NULL AND mime_type <> '' "); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, + "mime_type NOT IN " + getSqlSet(setOfMimeTypes) + + " AND mime_type IS NOT NULL AND mime_type <> '' "); } /** @@ -137,11 +141,7 @@ public class MimeTypeSummaryGetter implements DefaultUpdateGovernor { */ public Long getCountOfAllRegularFiles(DataSource dataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - try { - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(dataSource, null); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), dataSource, null); } /** @@ -158,11 +158,7 @@ public class MimeTypeSummaryGetter implements DefaultUpdateGovernor { */ public Long getCountOfFilesWithNoMimeType(DataSource currentDataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - try { - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "(mime_type IS NULL OR mime_type = '') "); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, "(mime_type IS NULL OR mime_type = '') "); } /** diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesSummaryGetter.java index f7b76081f7..c4ed083852 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesSummaryGetter.java @@ -23,7 +23,8 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.PastCasesResult; @@ -32,8 +33,9 @@ import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; /** - * Wrapper class for converting org.sleuthkit.autopsy.contentutils.PastCasesSummary - * functionality into a DefaultArtifactUpdateGovernor used by PastCases tab. + * Wrapper class for converting + * org.sleuthkit.autopsy.contentutils.PastCasesSummary functionality into a + * DefaultArtifactUpdateGovernor used by PastCases tab. */ public class PastCasesSummaryGetter implements DefaultArtifactUpdateGovernor { @@ -42,7 +44,10 @@ public class PastCasesSummaryGetter implements DefaultArtifactUpdateGovernor { ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() )); + private PastCasesSummary pastSummary; + public PastCasesSummaryGetter() { + pastSummary = new PastCasesSummary(); } @Override @@ -67,10 +72,6 @@ public class PastCasesSummaryGetter implements DefaultArtifactUpdateGovernor { return null; } - try { - return PastCasesSummary.getPastCasesData(dataSource); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return pastSummary.getPastCasesData(dataSource); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesGetter.java index 0c6db1d7e1..02824dacb7 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesGetter.java @@ -24,14 +24,13 @@ import java.util.HashSet; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; import java.util.List; import java.util.Set; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.datamodel.BlackboardArtifact; /** @@ -49,10 +48,13 @@ public class RecentFilesGetter implements DefaultArtifactUpdateGovernor { BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() )); + private RecentFilesSummary recentSummary; + /** * Default constructor. */ public RecentFilesGetter() { + recentSummary = new RecentFilesSummary(); } @Override @@ -75,11 +77,7 @@ public class RecentFilesGetter implements DefaultArtifactUpdateGovernor { * @throws TskCoreException */ public List getRecentlyOpenedDocuments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException { - try { - return RecentFilesSummary.getRecentlyOpenedDocuments(dataSource, maxCount); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return recentSummary.getRecentlyOpenedDocuments(dataSource, maxCount); } /** @@ -97,11 +95,7 @@ public class RecentFilesGetter implements DefaultArtifactUpdateGovernor { * @throws SleuthkitCaseProviderException */ public List getRecentDownloads(DataSource dataSource, int maxCount) throws TskCoreException, SleuthkitCaseProviderException { - try { - return RecentFilesSummary.getRecentDownloads(dataSource, maxCount); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return recentSummary.getRecentDownloads(dataSource, maxCount); } /** @@ -117,10 +111,6 @@ public class RecentFilesGetter implements DefaultArtifactUpdateGovernor { * @throws TskCoreException */ public List getRecentAttachments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException { - try { - return RecentFilesSummary.getRecentAttachments(dataSource, maxCount); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return recentSummary.getRecentAttachments(dataSource, maxCount); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java index 42a7b1ba8f..eed41cda3d 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java @@ -30,8 +30,8 @@ import org.joda.time.DateTime; import org.joda.time.Interval; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineDataSourceUtils; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData; @@ -77,6 +77,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { private final LoadableLabel earliestLabel = new LoadableLabel(Bundle.TimelinePanel_earliestLabel_title()); private final LoadableLabel latestLabel = new LoadableLabel(Bundle.TimelinePanel_latestLabel_title()); private final BarChartPanel last30DaysChart = new BarChartPanel(Bundle.TimlinePanel_last30DaysChart_title(), "", ""); + private final TimelineDataSourceUtils timelineUtils = TimelineDataSourceUtils.getInstance(); // all loadable components on this tab private final List> loadableComponents = Arrays.asList(earliestLabel, latestLabel, last30DaysChart); @@ -96,7 +97,7 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { public TimelinePanel(TimelineSummaryGetter timelineData) { super(timelineData); - dataFetcher = (dataSource) -> TimelineSummary.getTimelineSummaryData(dataSource, MOST_RECENT_DAYS_COUNT); + dataFetcher = (dataSource) -> timelineData.getData(dataSource, MOST_RECENT_DAYS_COUNT); // set up data acquisition methods dataFetchComponents = Arrays.asList( @@ -228,13 +229,13 @@ public class TimelinePanel extends BaseDataSourceSummaryPanel { final TimeLineController controller = TimeLineModule.getController(); if (dataSource != null) { - controller.pushFilters(TimelineSummary.getDataSourceFilterState(dataSource)); + controller.pushFilters(timelineUtils.getDataSourceFilterState(dataSource)); } if (minDate != null && maxDate != null) { timeSpan = new Interval(new DateTime(minDate), new DateTime(maxDate)); } - } catch (NoCurrentCaseException | TskCoreException ex) { + } catch (TskCoreException ex) { logger.log(Level.WARNING, "Unable to view time range in Timeline view", ex); } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java.bak b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java.bak new file mode 100755 index 0000000000..6b1292139e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java.bak @@ -0,0 +1,358 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020-2021 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.datasourcesummary.ui; + +import java.awt.Color; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.logging.Level; +import org.apache.commons.collections.CollectionUtils; +import org.joda.time.DateTime; +import org.joda.time.Interval; +import org.openide.util.NbBundle.Messages; +import org.openide.util.actions.CallableSystemAction; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.OrderedKey; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.BarChartItem; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel; +import org.sleuthkit.autopsy.timeline.OpenTimelineAction; +import org.sleuthkit.autopsy.timeline.TimeLineController; +import org.sleuthkit.autopsy.timeline.TimeLineModule; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * A tab shown in data source summary displaying information about a data + * source's timeline events. + */ +@Messages({ + "TimelinePanel_earliestLabel_title=Earliest", + "TimelinePanel_latestLabel_title=Latest", + "TimlinePanel_last30DaysChart_title=Last 30 Days", + "TimlinePanel_last30DaysChart_fileEvts_title=File Events", + "TimlinePanel_last30DaysChart_artifactEvts_title=Result Events",}) +public class TimelinePanel extends BaseDataSourceSummaryPanel { + + private static final Logger logger = Logger.getLogger(TimelinePanel.class.getName()); + private static final long serialVersionUID = 1L; + + private static final String EARLIEST_LATEST_FORMAT_STR = "MMM d, yyyy"; + private static final DateFormat EARLIEST_LATEST_FORMAT = TimelineSummary.getUtcFormat(EARLIEST_LATEST_FORMAT_STR); + private static final DateFormat CHART_FORMAT = TimelineSummary.getUtcFormat("MMM d, yyyy"); + private static final int MOST_RECENT_DAYS_COUNT = 30; + + // components displayed in the tab + private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel(); + private final LoadableLabel earliestLabel = new LoadableLabel(Bundle.TimelinePanel_earliestLabel_title()); + private final LoadableLabel latestLabel = new LoadableLabel(Bundle.TimelinePanel_latestLabel_title()); + private final BarChartPanel last30DaysChart = new BarChartPanel(Bundle.TimlinePanel_last30DaysChart_title(), "", ""); + private final TimelineDataSourceUtils timelineUtils = TimelineDataSourceUtils.getInstance(); + + // all loadable components on this tab + private final List> loadableComponents = Arrays.asList(earliestLabel, latestLabel, last30DaysChart); + + private final DataFetcher dataFetcher; + + // actions to load data for this tab + private final List> dataFetchComponents; + + public TimelinePanel() { + this(new TimelineSummaryGetter()); + } + + /** + * Creates new form PastCasesPanel + */ + public TimelinePanel(TimelineSummaryGetter timelineData) { + super(timelineData); + + dataFetcher = (dataSource) -> timelineData.getData(dataSource, MOST_RECENT_DAYS_COUNT); + + // set up data acquisition methods + dataFetchComponents = Arrays.asList( + new DataFetchWorker.DataFetchComponents<>(dataFetcher, (result) -> handleResult(result))); + + initComponents(); + } + + private static final Color FILE_EVT_COLOR = new Color(228, 22, 28); + private static final Color ARTIFACT_EVT_COLOR = new Color(21, 227, 100); + + /** + * Converts DailyActivityAmount data retrieved from TimelineSummaryGetter + * into data to be displayed as a bar chart. + * + * @param recentDaysActivity The data retrieved from + * TimelineSummaryGetter. + * @param showIntermediateDates If true, shows all dates. If false, shows + * only first and last date. + * + * @return The data to be displayed in the BarChart. + */ + private List parseChartData(List recentDaysActivity, boolean showIntermediateDates) { + // if no data, return null indicating no result. + if (CollectionUtils.isEmpty(recentDaysActivity)) { + return null; + } + + // Create a bar chart item for each recent days activity item + List fileEvtCounts = new ArrayList<>(); + List artifactEvtCounts = new ArrayList<>(); + + for (int i = 0; i < recentDaysActivity.size(); i++) { + DailyActivityAmount curItem = recentDaysActivity.get(i); + + long fileAmt = curItem.getFileActivityCount(); + long artifactAmt = curItem.getArtifactActivityCount() * 100; + String formattedDate = (showIntermediateDates || i == 0 || i == recentDaysActivity.size() - 1) + ? TimelineSummary.formatDate(curItem.getDay(), CHART_FORMAT) : ""; + + OrderedKey thisKey = new OrderedKey(formattedDate, i); + fileEvtCounts.add(new BarChartItem(thisKey, fileAmt)); + artifactEvtCounts.add(new BarChartItem(thisKey, artifactAmt)); + } + + return Arrays.asList( + new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_fileEvts_title(), FILE_EVT_COLOR, fileEvtCounts), + new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_artifactEvts_title(), ARTIFACT_EVT_COLOR, artifactEvtCounts)); + } + + private final Object timelineBtnLock = new Object(); + private TimelineSummaryData curTimelineData = null; + + /** + * Handles displaying the result for each displayable item in the + * TimelinePanel by breaking the TimelineSummaryData result into its + * constituent parts and then sending each data item to the pertinent + * component. + * + * @param result The result to be displayed on this tab. + */ + private void handleResult(DataFetchResult result) { + earliestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> TimelineSummary.formatDate(r.getMinDate(), EARLIEST_LATEST_FORMAT))); + latestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> TimelineSummary.formatDate(r.getMaxDate(), EARLIEST_LATEST_FORMAT))); + last30DaysChart.showDataFetchResult(DataFetchResult.getSubResult(result, r -> parseChartData(r.getMostRecentDaysActivity(), false))); + + if (result != null + && result.getResultType() == DataFetchResult.ResultType.SUCCESS + && result.getData() != null) { + + synchronized (this.timelineBtnLock) { + this.curTimelineData = result.getData(); + this.viewInTimelineBtn.setEnabled(true); + } + } else { + synchronized (this.timelineBtnLock) { + this.viewInTimelineBtn.setEnabled(false); + } + } + } + + /** + * Action that occurs when 'View in Timeline' button is pressed. + */ + private void openFilteredChart() { + DataSource dataSource = null; + Date minDate = null; + Date maxDate = null; + + // get date from current timelineData if that data exists. + synchronized (this.timelineBtnLock) { + if (curTimelineData == null) { + return; + } + + dataSource = curTimelineData.getDataSource(); + if (CollectionUtils.isNotEmpty(curTimelineData.getMostRecentDaysActivity())) { + minDate = curTimelineData.getMostRecentDaysActivity().get(0).getDay(); + maxDate = curTimelineData.getMostRecentDaysActivity().get(curTimelineData.getMostRecentDaysActivity().size() - 1).getDay(); + // set outer bound to end of day instead of beginning + if (maxDate != null) { + maxDate = new Date(maxDate.getTime() + 1000 * 60 * 60 * 24); + } + } + } + + openFilteredChart(dataSource, minDate, maxDate); + } + + /** + * Action that occurs when 'View in Timeline' button is pressed. + * + * @param dataSource The data source to filter to. + * @param minDate The min date for the zoom of the window. + * @param maxDate The max date for the zoom of the window. + */ + private void openFilteredChart(DataSource dataSource, Date minDate, Date maxDate) { + OpenTimelineAction openTimelineAction = CallableSystemAction.get(OpenTimelineAction.class); + if (openTimelineAction == null) { + logger.log(Level.WARNING, "No OpenTimelineAction provided by CallableSystemAction; taking no redirect action."); + } + + // notify dialog (if in dialog) should close. + TimelinePanel.this.notifyParentClose(); + + Interval timeSpan = null; + + try { + final TimeLineController controller = TimeLineModule.getController(); + + if (dataSource != null) { + controller.pushFilters(TimelineSummary.getDataSourceFilterState(dataSource)); + } + + if (minDate != null && maxDate != null) { + timeSpan = new Interval(new DateTime(minDate), new DateTime(maxDate)); + } + } catch (NoCurrentCaseException | TskCoreException ex) { + logger.log(Level.WARNING, "Unable to view time range in Timeline view", ex); + } + + try { + openTimelineAction.showTimeline(timeSpan); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "An unexpected exception occurred while opening the timeline.", ex); + } + } + + @Override + protected void fetchInformation(DataSource dataSource) { + fetchInformation(dataFetchComponents, dataSource); + } + + @Override + protected void onNewDataSource(DataSource dataSource) { + onNewDataSource(dataFetchComponents, loadableComponents, dataSource); + } + + @Override + public void close() { + ingestRunningLabel.unregister(); + super.close(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.JScrollPane mainScrollPane = new javax.swing.JScrollPane(); + javax.swing.JPanel mainContentPanel = new javax.swing.JPanel(); + javax.swing.JPanel ingestRunningPanel = ingestRunningLabel; + javax.swing.JLabel activityRangeLabel = new javax.swing.JLabel(); + javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); + javax.swing.JPanel earliestLabelPanel = earliestLabel; + javax.swing.JPanel latestLabelPanel = latestLabel; + javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); + javax.swing.JPanel last30DaysPanel = last30DaysChart; + viewInTimelineBtn = new javax.swing.JButton(); + javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767)); + + mainContentPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10)); + mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS)); + + ingestRunningPanel.setAlignmentX(0.0F); + ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 25)); + ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 25)); + ingestRunningPanel.setPreferredSize(new java.awt.Dimension(10, 25)); + mainContentPanel.add(ingestRunningPanel); + + activityRangeLabel.setFont(new java.awt.Font("Segoe UI", 1, 12)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(activityRangeLabel, org.openide.util.NbBundle.getMessage(TimelinePanel.class, "TimelinePanel.activityRangeLabel.text")); // NOI18N + mainContentPanel.add(activityRangeLabel); + activityRangeLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(TimelinePanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N + + filler1.setAlignmentX(0.0F); + mainContentPanel.add(filler1); + + earliestLabelPanel.setAlignmentX(0.0F); + earliestLabelPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); + earliestLabelPanel.setMinimumSize(new java.awt.Dimension(100, 20)); + earliestLabelPanel.setPreferredSize(new java.awt.Dimension(100, 20)); + mainContentPanel.add(earliestLabelPanel); + + latestLabelPanel.setAlignmentX(0.0F); + latestLabelPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); + latestLabelPanel.setMinimumSize(new java.awt.Dimension(100, 20)); + latestLabelPanel.setPreferredSize(new java.awt.Dimension(100, 20)); + mainContentPanel.add(latestLabelPanel); + + filler2.setAlignmentX(0.0F); + mainContentPanel.add(filler2); + + last30DaysPanel.setAlignmentX(0.0F); + last30DaysPanel.setMaximumSize(new java.awt.Dimension(600, 300)); + last30DaysPanel.setMinimumSize(new java.awt.Dimension(600, 300)); + last30DaysPanel.setPreferredSize(new java.awt.Dimension(600, 300)); + last30DaysPanel.setVerifyInputWhenFocusTarget(false); + mainContentPanel.add(last30DaysPanel); + + org.openide.awt.Mnemonics.setLocalizedText(viewInTimelineBtn, org.openide.util.NbBundle.getMessage(TimelinePanel.class, "TimelinePanel.viewInTimelineBtn.text")); // NOI18N + viewInTimelineBtn.setEnabled(false); + viewInTimelineBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + viewInTimelineBtnActionPerformed(evt); + } + }); + mainContentPanel.add(viewInTimelineBtn); + + filler5.setAlignmentX(0.0F); + mainContentPanel.add(filler5); + + mainScrollPane.setViewportView(mainContentPanel); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + private void viewInTimelineBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewInTimelineBtnActionPerformed + openFilteredChart(); + }//GEN-LAST:event_viewInTimelineBtnActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton viewInTimelineBtn; + // End of variables declaration//GEN-END:variables + +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelineSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelineSummaryGetter.java index 99bdc2737c..4ea7a51f36 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelineSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelineSummaryGetter.java @@ -22,7 +22,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; -import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -30,7 +30,6 @@ import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData; /** @@ -41,10 +40,13 @@ public class TimelineSummaryGetter implements DefaultUpdateGovernor { private static final Set INGEST_JOB_EVENTS = new HashSet<>( Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED)); + private TimelineSummary timelineSummary; + /** * Default constructor. */ public TimelineSummaryGetter() { + timelineSummary = new TimelineSummary(); } @Override @@ -70,20 +72,17 @@ public class TimelineSummaryGetter implements DefaultUpdateGovernor { /** * Retrieves timeline summary data. * - * @param dataSource The data source for which timeline data will be - * retrieved. + * @param dataSource The data source for which timeline data will be + * retrieved. * @param recentDaysNum The maximum number of most recent days' activity to - * include. + * include. + * * @return The retrieved data. + * * @throws SleuthkitCaseProviderException * @throws TskCoreException - * @throws NoCurrentCaseException */ - public TimelineSummaryData getData(DataSource dataSource, int recentDaysNum) throws SleuthkitCaseProviderException, TskCoreException, NoCurrentCaseException { - try { - return TimelineSummary.getTimelineSummaryData(dataSource, recentDaysNum); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + public TimelineSummaryData getData(DataSource dataSource, int recentDaysNum) throws SleuthkitCaseProviderException, TskCoreException { + return timelineSummary.getTimelineSummaryData(dataSource, recentDaysNum); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index ea4a85f406..45eba82918 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -31,7 +31,7 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory; import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceInfoUtilities; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary.FileTypeCategoryData; -import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesSummaryGetter.java index 5bc6bf92ab..3b0887c52f 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesSummaryGetter.java @@ -24,9 +24,9 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary; -import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; @@ -34,18 +34,22 @@ import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; /** - * Wrapper class for converting org.sleuthkit.autopsy.contentutils.TypesSummary functionality into a - * DefaultArtifactUpdateGovernor used by DataSourceSummaryCountsPanel. + * Wrapper class for converting org.sleuthkit.autopsy.contentutils.TypesSummary + * functionality into a DefaultArtifactUpdateGovernor used by + * DataSourceSummaryCountsPanel. */ public class TypesSummaryGetter implements DefaultUpdateGovernor { private static final Set INGEST_JOB_EVENTS = new HashSet<>( Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED)); + private TypesSummary typesSummary; + /** * Main constructor. */ public TypesSummaryGetter() { + typesSummary = new TypesSummary(); } @Override @@ -81,11 +85,7 @@ public class TypesSummaryGetter implements DefaultUpdateGovernor { */ public Long getCountOfFiles(DataSource currentDataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - try { - return TypesSummary.getCountOfFiles(currentDataSource); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return typesSummary.getCountOfFiles(currentDataSource); } /** @@ -101,11 +101,7 @@ public class TypesSummaryGetter implements DefaultUpdateGovernor { */ public Long getCountOfAllocatedFiles(DataSource currentDataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - try { - return TypesSummary.getCountOfAllocatedFiles(currentDataSource); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return typesSummary.getCountOfAllocatedFiles(currentDataSource); } /** @@ -121,11 +117,7 @@ public class TypesSummaryGetter implements DefaultUpdateGovernor { */ public Long getCountOfUnallocatedFiles(DataSource currentDataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - try { - return TypesSummary.getCountOfUnallocatedFiles(currentDataSource); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return typesSummary.getCountOfUnallocatedFiles(currentDataSource); } /** @@ -141,11 +133,7 @@ public class TypesSummaryGetter implements DefaultUpdateGovernor { */ public Long getCountOfDirectories(DataSource currentDataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - try { - return TypesSummary.getCountOfDirectories(currentDataSource); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return typesSummary.getCountOfDirectories(currentDataSource); } /** @@ -161,10 +149,6 @@ public class TypesSummaryGetter implements DefaultUpdateGovernor { */ public Long getCountOfSlackFiles(DataSource currentDataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - try { - return TypesSummary.getCountOfSlackFiles(currentDataSource); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return typesSummary.getCountOfSlackFiles(currentDataSource); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java index 04da065833..ab98b0e271 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java @@ -25,8 +25,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary; @@ -54,7 +53,10 @@ public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID() )); + private final UserActivitySummary userActivity; + public UserActivitySummaryGetter() { + userActivity = new UserActivitySummary(); } @Override @@ -90,11 +92,7 @@ public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor return Collections.emptyList(); } - try { - return UserActivitySummary.getRecentDomains(dataSource, count); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return userActivity.getRecentDomains(dataSource, count); } /** @@ -119,11 +117,7 @@ public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor return Collections.emptyList(); } - try { - return UserActivitySummary.getMostRecentWebSearches(dataSource, count); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return userActivity.getMostRecentWebSearches(dataSource, count); } /** @@ -147,11 +141,7 @@ public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor return Collections.emptyList(); } - try { - return UserActivitySummary.getRecentDevices(dataSource, count); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return userActivity.getRecentDevices(dataSource, count); } /** @@ -179,11 +169,7 @@ public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor return Collections.emptyList(); } - try { - return UserActivitySummary.getRecentAccounts(dataSource, count); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return userActivity.getRecentAccounts(dataSource, count); } /** @@ -228,10 +214,6 @@ public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor return Collections.emptyList(); } - try { - return UserActivitySummary.getTopPrograms(dataSource, count); - } catch (NoCurrentCaseException ex) { - throw new SleuthkitCaseProviderException("No currently open case.", ex); - } + return userActivity.getTopPrograms(dataSource, count); } } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index f513f26b89..3d7f303ea5 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -118,7 +118,7 @@ class ExcelExportAction { // Export file and MIME type data progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringFileData()); progressPanel.setProgress(step); - List exports = ExportTypes.getExports(dataSource); + List exports = new ExportTypes().getExports(dataSource); if (exports != null) { sheetExports.addAll(exports); } @@ -126,7 +126,7 @@ class ExcelExportAction { // Export user activity progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringUserData()); progressPanel.setProgress(++step); - exports = ExportUserActivity.getExports(dataSource); + exports = new ExportUserActivity().getExports(dataSource); if (exports != null) { sheetExports.addAll(exports); } @@ -134,7 +134,7 @@ class ExcelExportAction { // Export Recent Activity data progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringRecentActivityData()); progressPanel.setProgress(++step); - exports = ExportRecentFiles.getExports(dataSource); + exports = new ExportRecentFiles().getExports(dataSource); if (exports != null) { sheetExports.addAll(exports); } @@ -142,7 +142,7 @@ class ExcelExportAction { // Export hash set hits, keyword hits, and interesting item hits progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringAnalysisData()); progressPanel.setProgress(++step); - exports = ExportAnalysisResults.getExports(dataSource); + exports = new ExportAnalysisResults().getExports(dataSource); if (exports != null) { sheetExports.addAll(exports); } @@ -150,7 +150,7 @@ class ExcelExportAction { // Export past cases data progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringPastData()); progressPanel.setProgress(++step); - exports = ExportPastCases.getExports(dataSource); + exports = new ExportPastCases().getExports(dataSource); if (exports != null) { sheetExports.addAll(exports); } @@ -158,7 +158,7 @@ class ExcelExportAction { // Export geolocation data progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringGeoData()); progressPanel.setProgress(++step); - exports = ExportGeolocation.getExports(dataSource); + exports = new ExportGeolocation().getExports(dataSource); if (exports != null) { sheetExports.addAll(exports); } @@ -166,7 +166,7 @@ class ExcelExportAction { // Export Timeline data progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringTimelineData()); progressPanel.setProgress(++step); - exports = ExportTimeline.getExports(dataSource); + exports = new ExportTimeline().getExports(dataSource); if (exports != null) { sheetExports.addAll(exports); } @@ -182,7 +182,7 @@ class ExcelExportAction { // Export Container & Image info data progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringContainerData()); progressPanel.setProgress(++step); - exports = ExportContainerInfo.getExports(dataSource); + exports = new ExportContainerInfo().getExports(dataSource); if (exports != null) { sheetExports.addAll(exports); } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java index 865ffddd01..8d154bd847 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java @@ -56,14 +56,17 @@ class ExportAnalysisResults { ) ); - private ExportAnalysisResults() { + private final AnalysisSummary analysisSummary; + + ExportAnalysisResults() { + analysisSummary = new AnalysisSummary(); } - static List getExports(DataSource dataSource) { + List getExports(DataSource dataSource) { - DataFetcher>> hashsetsFetcher = (ds) -> AnalysisSummary.getHashsetCounts(ds); - DataFetcher>> keywordsFetcher = (ds) -> AnalysisSummary.getKeywordCounts(ds); - DataFetcher>> interestingItemsFetcher = (ds) -> AnalysisSummary.getInterestingItemCounts(ds); + DataFetcher>> hashsetsFetcher = (ds) -> analysisSummary.getHashsetCounts(ds); + DataFetcher>> keywordsFetcher = (ds) -> analysisSummary.getKeywordCounts(ds); + DataFetcher>> interestingItemsFetcher = (ds) -> analysisSummary.getInterestingItemCounts(ds); return Stream.of( getTableExport(hashsetsFetcher, DEFAULT_COLUMNS, Bundle.ExportAnalysisResults_hashsetHits_tabName(), dataSource), diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java index 949bd853af..e6af2ce2a0 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java @@ -39,11 +39,14 @@ import org.sleuthkit.datamodel.DataSource; * Class to export additional details associated with a specific DataSource */ class ExportContainerInfo { + + private final ContainerSummary containerSummary; /** * Creates new form ExportContainerInfo. */ - private ExportContainerInfo() { + ExportContainerInfo() { + containerSummary = new ContainerSummary(); } /** @@ -81,8 +84,8 @@ class ExportContainerInfo { "ExportContainerInfo_export_sha256=SHA256:", "ExportContainerInfo_export_unallocatedSize=Unallocated Space:", "ExportContainerInfo_export_filePaths=File Paths:",}) - static List getExports(DataSource ds) { - DataFetcher containerDataFetcher = (dataSource) -> ContainerSummary.getContainerDetails(dataSource); + List getExports(DataSource ds) { + DataFetcher containerDataFetcher = (dataSource) -> containerSummary.getContainerDetails(dataSource); ContainerDetails containerDetails = ExcelExportAction.getFetchResult(containerDataFetcher, "Container sheets", ds); if (ds == null || containerDetails == null) { return Collections.emptyList(); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java index d320311485..8cdecf8338 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java @@ -46,6 +46,8 @@ import org.sleuthkit.datamodel.DataSource; "ExportGeolocation_mostCommon_tabName=Most Common Cities", "ExportGeolocation_mostRecent_tabName=Most Recent Cities",}) class ExportGeolocation { + + private final GeolocationSummary geoSummary; /** * Object encapsulating geolocation data. @@ -109,7 +111,8 @@ class ExportGeolocation { COUNT_COL ); - private ExportGeolocation() { + ExportGeolocation() { + geoSummary = new GeolocationSummary(); } /** @@ -203,9 +206,9 @@ class ExportGeolocation { } } - static List getExports(DataSource dataSource) { + List getExports(DataSource dataSource) { - DataFetcher geolocationFetcher = (ds) -> convertToViewModel(GeolocationSummary.getCityCounts(ds, DAYS_COUNT, MAX_COUNT)); + DataFetcher geolocationFetcher = (ds) -> convertToViewModel(geoSummary.getCityCounts(ds, DAYS_COUNT, MAX_COUNT)); GeolocationData model = getFetchResult(geolocationFetcher, "Geolocation sheets", dataSource); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java index de6f027ed0..da91b8744e 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java @@ -39,6 +39,8 @@ import org.sleuthkit.datamodel.DataSource; "ExportPastCases_notableFileTable_tabName=Cases with Common Notable", "ExportPastCases_sameIdsTable_tabName=Past Cases with the Same Devices",}) class ExportPastCases { + + private final PastCasesSummary pastSummary; // model for column indicating the case private static final ColumnModel, DefaultCellModel> CASE_COL = new ColumnModel<>( @@ -58,11 +60,12 @@ class ExportPastCases { private static List, DefaultCellModel>> DEFAULT_TEMPLATE = Arrays.asList(CASE_COL, COUNT_COL); - private ExportPastCases() { + ExportPastCases() { + pastSummary = new PastCasesSummary(); } - static List getExports(DataSource dataSource) { - DataFetcher pastCasesFetcher = (ds) -> PastCasesSummary.getPastCasesData(ds); + List getExports(DataSource dataSource) { + DataFetcher pastCasesFetcher = (ds) -> pastSummary.getPastCasesData(ds); PastCasesResult result = getFetchResult(pastCasesFetcher, "Past cases sheets", dataSource); if (result == null) { return Collections.emptyList(); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java index adb6068fe5..38dbc59a78 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java @@ -47,6 +47,8 @@ import org.sleuthkit.datamodel.DataSource; "ExportRecentFiles_col_header_sender=Sender" }) final class ExportRecentFiles { + + private final RecentFilesSummary recentSummary; private static final String DATETIME_FORMAT_STR = "yyyy/MM/dd HH:mm:ss"; private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat(DATETIME_FORMAT_STR, Locale.getDefault()); @@ -86,7 +88,8 @@ final class ExportRecentFiles { return new DefaultCellModel<>(prog.getSender()); }, 150)); - private ExportRecentFiles() { + ExportRecentFiles() { + recentSummary = new RecentFilesSummary(); } /** @@ -103,11 +106,11 @@ final class ExportRecentFiles { }; } - static List getExports(DataSource dataSource) { + List getExports(DataSource dataSource) { - DataFetcher> docsFetcher = (ds) -> RecentFilesSummary.getRecentlyOpenedDocuments(ds, 10); - DataFetcher> downloadsFetcher = (ds) -> RecentFilesSummary.getRecentDownloads(ds, 10); - DataFetcher> attachmentsFetcher = (ds) -> RecentFilesSummary.getRecentAttachments(ds, 10); + DataFetcher> docsFetcher = (ds) -> recentSummary.getRecentlyOpenedDocuments(ds, 10); + DataFetcher> downloadsFetcher = (ds) -> recentSummary.getRecentDownloads(ds, 10); + DataFetcher> attachmentsFetcher = (ds) -> recentSummary.getRecentAttachments(ds, 10); return Stream.of( ExcelExportAction.getTableExport(docsFetcher, docsTemplate, Bundle.ExportRecentFiles_docsTable_tabName(), dataSource), diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java index 3af85058a3..efefa6bc97 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java @@ -46,6 +46,8 @@ import org.sleuthkit.datamodel.DataSource; "TimlinePanel_last30DaysChart_fileEvts_title=File Events", "TimlinePanel_last30DaysChart_artifactEvts_title=Result Events",}) class ExportTimeline { + + private final TimelineSummary timelineSummary; private static final String EARLIEST_LATEST_FORMAT_STR = "MMM d, yyyy"; private static final DateFormat EARLIEST_LATEST_FORMAT = TimelineSummary.getUtcFormat(EARLIEST_LATEST_FORMAT_STR); @@ -58,7 +60,8 @@ class ExportTimeline { /** * Creates new form PastCasesPanel */ - private ExportTimeline() { + ExportTimeline() { + timelineSummary = new TimelineSummary(); } /** @@ -118,8 +121,8 @@ class ExportTimeline { "TimelinePanel_getExports_latest=Latest:", "TimelinePanel_getExports_dateColumnHeader=Date", "TimelinePanel_getExports_chartName=Last 30 Days",}) - static List getExports(DataSource dataSource) { - DataFetcher dataFetcher = (ds) -> TimelineSummary.getTimelineSummaryData(ds, MOST_RECENT_DAYS_COUNT); + List getExports(DataSource dataSource) { + DataFetcher dataFetcher = (ds) -> timelineSummary.getTimelineSummaryData(ds, MOST_RECENT_DAYS_COUNT); TimelineSummaryData summaryData = ExcelExportAction.getFetchResult(dataFetcher, "Timeline", dataSource); if (summaryData == null) { return Collections.emptyList(); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java index 1523540f23..1321a4b511 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java @@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory; import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceInfoUtilities; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary.FileTypeCategoryData; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.KeyValueItemExportable; @@ -99,6 +100,10 @@ class ExportTypes { return usefulContent; } } + + private final ContainerSummary containerSummary; + private final TypesSummary typesSummary; + private final SleuthkitCaseProvider provider; private static final Color IMAGES_COLOR = new Color(156, 39, 176); private static final Color VIDEOS_COLOR = Color.YELLOW; @@ -119,7 +124,10 @@ class ExportTypes { new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")), UNKNOWN_COLOR) ); - private ExportTypes() { + ExportTypes() { + this.provider = SleuthkitCaseProvider.DEFAULT; + containerSummary = new ContainerSummary(); + typesSummary = new TypesSummary(); } /** @@ -160,8 +168,8 @@ class ExportTypes { * @throws TskCoreException * @throws SQLException */ - private static Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set setOfMimeTypes) throws TskCoreException, SQLException, NoCurrentCaseException { - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "mime_type IN " + getSqlSet(setOfMimeTypes)); + private Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set setOfMimeTypes) throws TskCoreException, SQLException, SleuthkitCaseProvider.SleuthkitCaseProviderException { + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, "mime_type IN " + getSqlSet(setOfMimeTypes)); } /** @@ -176,8 +184,8 @@ class ExportTypes { * @throws TskCoreException * @throws SQLException */ - private static Long getCountOfFilesWithNoMimeType(DataSource currentDataSource) throws TskCoreException, SQLException, NoCurrentCaseException { - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "(mime_type IS NULL OR mime_type = '') "); + private Long getCountOfFilesWithNoMimeType(DataSource currentDataSource) throws TskCoreException, SQLException, SleuthkitCaseProvider.SleuthkitCaseProviderException { + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, "(mime_type IS NULL OR mime_type = '') "); } /** @@ -188,8 +196,8 @@ class ExportTypes { * * @return The pie chart items. */ - private static TypesPieChartData getMimeTypeCategoriesModel(DataSource dataSource) - throws SQLException, TskCoreException, NoCurrentCaseException { + private TypesPieChartData getMimeTypeCategoriesModel(DataSource dataSource) + throws SQLException, TskCoreException, SleuthkitCaseProvider.SleuthkitCaseProviderException { if (dataSource == null) { return null; @@ -213,7 +221,7 @@ class ExportTypes { long noMimeTypeCount = DataSourceInfoUtilities.getLongOrZero(getCountOfFilesWithNoMimeType(dataSource)); // get a count of all regular files - long allRegularFiles = DataSourceInfoUtilities.getLongOrZero(DataSourceInfoUtilities.getCountOfRegNonSlackFiles(dataSource, null)); + long allRegularFiles = DataSourceInfoUtilities.getLongOrZero(DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), dataSource, null)); // create entry for mime types in other category long otherCount = allRegularFiles - (categoryTotalCount + noMimeTypeCount); @@ -268,21 +276,21 @@ class ExportTypes { new DefaultCellModel(count, DataSourceInfoUtilities.COMMA_FORMATTER::format, DataSourceInfoUtilities.COMMA_FORMAT_STR)); } - static List getExports(DataSource dataSource) { + List getExports(DataSource dataSource) { if (dataSource == null) { return Collections.emptyList(); } - DataFetcher usageFetcher = (ds) -> ContainerSummary.getDataSourceType(ds); - DataFetcher osFetcher = (ds) -> ContainerSummary.getOperatingSystems(ds); + DataFetcher usageFetcher = (ds) -> containerSummary.getDataSourceType(ds); + DataFetcher osFetcher = (ds) -> containerSummary.getOperatingSystems(ds); DataFetcher sizeFetcher = (ds) -> ds == null ? null : ds.getSize(); DataFetcher typesFetcher = (ds) -> getMimeTypeCategoriesModel(ds); - DataFetcher allocatedFetcher = (ds) -> TypesSummary.getCountOfAllocatedFiles(ds); - DataFetcher unallocatedFetcher = (ds) -> TypesSummary.getCountOfUnallocatedFiles(ds); - DataFetcher slackFetcher = (ds) -> TypesSummary.getCountOfSlackFiles(ds); - DataFetcher directoriesFetcher = (ds) -> TypesSummary.getCountOfDirectories(ds); + DataFetcher allocatedFetcher = (ds) -> typesSummary.getCountOfAllocatedFiles(ds); + DataFetcher unallocatedFetcher = (ds) -> typesSummary.getCountOfUnallocatedFiles(ds); + DataFetcher slackFetcher = (ds) -> typesSummary.getCountOfSlackFiles(ds); + DataFetcher directoriesFetcher = (ds) -> typesSummary.getCountOfDirectories(ds); // Retrieve data to create the types pie chart TypesPieChartData typesData = ExcelExportAction.getFetchResult(typesFetcher, "Types", dataSource); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java index 6a1cb491e2..028073e53d 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java @@ -67,6 +67,8 @@ import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.Excel "ExportUserActivity_noDataExists=No communication data exists"}) class ExportUserActivity { + private final UserActivitySummary userSummary; + private static final String DATETIME_FORMAT_STR = "yyyy/MM/dd HH:mm:ss"; private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat(DATETIME_FORMAT_STR, Locale.getDefault()); private static final int TOP_PROGS_COUNT = 10; @@ -206,7 +208,8 @@ class ExportUserActivity { ) ); - private ExportUserActivity() { + ExportUserActivity() { + userSummary = new UserActivitySummary(); } private static Function> getDateFunct() { @@ -228,13 +231,13 @@ class ExportUserActivity { return UserActivitySummary.getShortFolderName(path, appName); } - static List getExports(DataSource dataSource) { + List getExports(DataSource dataSource) { - DataFetcher> topProgramsFetcher = (ds) -> UserActivitySummary.getTopPrograms(ds, TOP_PROGS_COUNT); - DataFetcher> topDomainsFetcher = (ds) -> UserActivitySummary.getRecentDomains(ds, TOP_DOMAINS_COUNT); - DataFetcher> topWebSearchesFetcher = (ds) -> UserActivitySummary.getMostRecentWebSearches(ds, TOP_SEARCHES_COUNT); - DataFetcher> topDevicesAttachedFetcher = (ds) -> UserActivitySummary.getRecentDevices(ds, TOP_DEVICES_COUNT); - DataFetcher> topAccountsFetcher = (ds) -> UserActivitySummary.getRecentAccounts(ds, TOP_ACCOUNTS_COUNT); + DataFetcher> topProgramsFetcher = (ds) -> userSummary.getTopPrograms(ds, TOP_PROGS_COUNT); + DataFetcher> topDomainsFetcher = (ds) -> userSummary.getRecentDomains(ds, TOP_DOMAINS_COUNT); + DataFetcher> topWebSearchesFetcher = (ds) -> userSummary.getMostRecentWebSearches(ds, TOP_SEARCHES_COUNT); + DataFetcher> topDevicesAttachedFetcher = (ds) -> userSummary.getRecentDevices(ds, TOP_DEVICES_COUNT); + DataFetcher> topAccountsFetcher = (ds) -> userSummary.getRecentAccounts(ds, TOP_ACCOUNTS_COUNT); return Stream.of( getTableExport(topProgramsFetcher, topProgramsTemplate, Bundle.ExportUserActivity_TopProgramsTableModel_tabName(), dataSource), diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java index 73fc864c61..5cfdfca671 100644 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java @@ -25,7 +25,7 @@ import java.util.Map; import java.util.stream.Collectors; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.ui.UserActivitySummaryGetter; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; import org.sleuthkit.datamodel.Content; diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java index 244a7da113..535f258ced 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java @@ -44,7 +44,7 @@ import static org.mockito.Mockito.when; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails; -import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.testutils.RandomizationUtils; import org.sleuthkit.autopsy.testutils.TskMockUtils; import org.sleuthkit.datamodel.Blackboard; diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java index 0fd7b72d9c..81983ce4d5 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java @@ -44,7 +44,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceSummaryMockUtils.getArtifactsTSKMock; -import org.sleuthkit.autopsy.datasourcesummary.ui.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopAccountResult; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDeviceAttachedResult; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; From 2b7f40a5844c622763689deab49f7e21b91aa220 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 18 Aug 2021 18:33:35 -0400 Subject: [PATCH 40/76] Restored unit tests --- .../UserActivitySummaryTests.java | 10 +- .../datamodel/RecentFilesSummaryTest.java | 35 +++--- .../datamodel/UserActivitySummaryTest.java | 113 ++++++++++-------- 3 files changed, 82 insertions(+), 76 deletions(-) diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java index 5cfdfca671..14455b27c9 100644 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/datasourcesummary/UserActivitySummaryTests.java @@ -26,7 +26,7 @@ import java.util.stream.Collectors; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import org.sleuthkit.autopsy.datasourcesummary.ui.UserActivitySummaryGetter; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDomainsResult; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DataSource; @@ -36,14 +36,14 @@ import org.sleuthkit.autopsy.integrationtesting.IntegrationTest; import org.sleuthkit.autopsy.integrationtesting.IntegrationTestGroup; /** - * Tests for the UserActivitySummaryGetter class. + * Tests for the UserActivitySummary class. */ @ServiceProvider(service = IntegrationTestGroup.class) public class UserActivitySummaryTests implements IntegrationTestGroup { /** - * Runs UserActivitySummaryGetter.getRecentDomains for all data sources found in - the current case. + * Runs UserActivitySummary.getRecentDomains for all data sources found in + * the current case. * * @return A map where the key is the data source name and the value are the * results of that method. @@ -52,7 +52,7 @@ public class UserActivitySummaryTests implements IntegrationTestGroup { public Map>> getRecentDomainsTest() throws NoCurrentCaseException, TskCoreException, SleuthkitCaseProviderException { - UserActivitySummaryGetter userActivitySummary = new UserActivitySummaryGetter(); + UserActivitySummary userActivitySummary = new UserActivitySummary(); Map>> toRet = new HashMap<>(); for (Content c : Case.getCurrentCaseThrows().getDataSources()) { if (c instanceof DataSource) { diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java index 535f258ced..0acda3954a 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/RecentFilesSummaryTest.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.datasourcesummary.datamodel; -import org.sleuthkit.autopsy.datasourcesummary.ui.RecentFilesGetter; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; @@ -63,15 +62,15 @@ import org.sleuthkit.datamodel.TskCoreException; public class RecentFilesSummaryTest { /** - * An interface for calling methods in RecentFilesGetter in a uniform - manner. + * An interface for calling methods in RecentFilesSummary in a uniform + * manner. */ private interface RecentFilesMethod { /** - * Means of acquiring data from a method in RecentFilesGetter. + * Means of acquiring data from a method in RecentFilesSummary. * - * @param recentFilesSummary The RecentFilesGetter object. + * @param recentFilesSummary The RecentFilesSummary object. * @param dataSource The datasource. * @param count The number of items to retrieve. * @@ -80,7 +79,7 @@ public class RecentFilesSummaryTest { * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - List fetch(RecentFilesGetter recentFilesSummary, DataSource dataSource, int count) + List fetch(RecentFilesSummary recentFilesSummary, DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException; } @@ -106,7 +105,7 @@ public class RecentFilesSummaryTest { throws TskCoreException, SleuthkitCaseProviderException { Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(null); DataSource dataSource = TskMockUtils.getDataSource(1); - RecentFilesGetter summary = new RecentFilesGetter(); + RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); try { method.fetch(summary, dataSource, -1); @@ -147,7 +146,7 @@ public class RecentFilesSummaryTest { throws SleuthkitCaseProviderException, TskCoreException { Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(null); - RecentFilesGetter summary = new RecentFilesGetter(); + RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); List items = recentFilesMethod.fetch(summary, null, 10); Assert.assertNotNull("Expected method " + methodName + " to return an empty list.", items); @@ -185,7 +184,7 @@ public class RecentFilesSummaryTest { throws SleuthkitCaseProviderException, TskCoreException { Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(Collections.emptyList()); - RecentFilesGetter summary = new RecentFilesGetter(); + RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); DataSource dataSource = TskMockUtils.getDataSource(1); List items = recentFilesMethod.fetch(summary, dataSource, 10); Assert.assertNotNull("Expected method " + methodName + " to return an empty list.", items); @@ -279,7 +278,7 @@ public class RecentFilesSummaryTest { // run through method Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(RandomizationUtils.getMixedUp(artifacts)); - RecentFilesGetter summary = new RecentFilesGetter(); + RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); List results = summary.getRecentlyOpenedDocuments(dataSource, countRequest); // verify results @@ -303,7 +302,7 @@ public class RecentFilesSummaryTest { List artifacts = Arrays.asList(item2, item3, item1); Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(RandomizationUtils.getMixedUp(artifacts)); - RecentFilesGetter summary = new RecentFilesGetter(); + RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); List results = summary.getRecentlyOpenedDocuments(dataSource, 10); // verify results (only successItem) @@ -323,7 +322,7 @@ public class RecentFilesSummaryTest { List artifacts = Arrays.asList(nullTime, zeroTime, successItem); Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(RandomizationUtils.getMixedUp(artifacts)); - RecentFilesGetter summary = new RecentFilesGetter(); + RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); List results = summary.getRecentlyOpenedDocuments(dataSource, 10); // verify results (only successItem) @@ -374,7 +373,7 @@ public class RecentFilesSummaryTest { // call method Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(RandomizationUtils.getMixedUp(artifacts)); - RecentFilesGetter summary = new RecentFilesGetter(); + RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); List results = summary.getRecentDownloads(dataSource, countRequest); // verify results @@ -400,7 +399,7 @@ public class RecentFilesSummaryTest { List artifacts = Arrays.asList(item2, item3, item1); Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(RandomizationUtils.getMixedUp(artifacts)); - RecentFilesGetter summary = new RecentFilesGetter(); + RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); // call method List results = summary.getRecentDownloads(dataSource, 10); @@ -423,7 +422,7 @@ public class RecentFilesSummaryTest { List artifacts = Arrays.asList(nullTime, zeroTime, successItem); Pair casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(RandomizationUtils.getMixedUp(artifacts)); - RecentFilesGetter summary = new RecentFilesGetter(); + RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); // call method List results = summary.getRecentDownloads(dataSource, 10); @@ -652,7 +651,7 @@ public class RecentFilesSummaryTest { List mixedUpItems = RandomizationUtils.getMixedUp(items); Pair casePair = getRecentAttachmentArtifactCase(mixedUpItems); - RecentFilesGetter summary = new RecentFilesGetter(); + RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); // retrieve results List results = summary.getRecentAttachments(dataSource, countRequest); @@ -699,7 +698,7 @@ public class RecentFilesSummaryTest { noParentFile, noAssocAttr, missingAssocArt); Pair casePair = getRecentAttachmentArtifactCase(items); - RecentFilesGetter summary = new RecentFilesGetter(); + RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); // get data List results = summary.getRecentAttachments(dataSource, 10); @@ -736,7 +735,7 @@ public class RecentFilesSummaryTest { List items = Arrays.asList(item1, item2, item3); Pair casePair = getRecentAttachmentArtifactCase(items); - RecentFilesGetter summary = new RecentFilesGetter(); + RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft()); // get data List results = summary.getRecentAttachments(dataSource, 10); diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java index 81983ce4d5..2b6a1c6600 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummaryTest.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.datasourcesummary.datamodel; -import org.sleuthkit.autopsy.datasourcesummary.ui.UserActivitySummaryGetter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -64,27 +63,27 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; /** - * Tests for UserActivitySummaryGetter. + * Tests for UserActivitySummary. */ public class UserActivitySummaryTest { /** - * Function to retrieve data from UserActivitySummaryGetter with the provided - arguments. + * Function to retrieve data from UserActivitySummary with the provided + * arguments. */ private interface DataFunction { /** - * A UserActivitySummaryGetter method encapsulated in a uniform manner. + * A UserActivitySummary method encapsulated in a uniform manner. * - * @param userActivitySummary The UserActivitySummaryGetter class to use. + * @param userActivitySummary The UserActivitySummary class to use. * @param datasource The data source. * @param count The count. * @return The list of objects to return. * @throws SleuthkitCaseProviderException * @throws TskCoreException */ - List retrieve(UserActivitySummaryGetter userActivitySummary, DataSource datasource, int count) throws + List retrieve(UserActivitySummary userActivitySummary, DataSource datasource, int count) throws SleuthkitCaseProviderException, TskCoreException; } @@ -120,21 +119,25 @@ public class UserActivitySummaryTest { } /** - * Gets a UserActivitySummaryGetter class to test. + * Gets a UserActivitySummary class to test. * * @param tskCase The SleuthkitCase. * @param hasTranslation Whether the translation service is functional. * @param translateFunction Function for translation. * - * @return The UserActivitySummaryGetter class to use for testing. + * @return The UserActivitySummary class to use for testing. * * @throws NoServiceProviderException * @throws TranslationException */ - private static UserActivitySummaryGetter getTestClass(SleuthkitCase tskCase, boolean hasTranslation, Function translateFunction) + private static UserActivitySummary getTestClass(SleuthkitCase tskCase, boolean hasTranslation, Function translateFunction) throws NoServiceProviderException, TranslationException { - return new UserActivitySummaryGetter(); + return new UserActivitySummary( + () -> tskCase, + TskMockUtils.getTextTranslationService(translateFunction, hasTranslation), + TskMockUtils.getJavaLogger("UNIT TEST LOGGER") + ); } private void testMinCount(DataFunction funct, String id) @@ -142,7 +145,7 @@ public class UserActivitySummaryTest { for (int count : new int[]{0, -1}) { Pair tskPair = getArtifactsTSKMock(null); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); try { funct.retrieve(summary, TskMockUtils.getDataSource(1), -1); @@ -180,7 +183,7 @@ public class UserActivitySummaryTest { throws TskCoreException, NoServiceProviderException, TranslationException, SleuthkitCaseProviderException { Pair tskPair = getArtifactsTSKMock(null); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List retArr = funct.retrieve(summary, null, 10); verify(tskPair.getRight(), never() .description(String.format("Expected method %s to return empty list for null data source and not call SleuthkitCase", id))) @@ -213,7 +216,7 @@ public class UserActivitySummaryTest { long dataSourceId = 1; int count = 10; Pair tskPair = getArtifactsTSKMock(new ArrayList<>()); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List retArr = funct.retrieve(summary, TskMockUtils.getDataSource(dataSourceId), count); Assert.assertTrue(String.format("Expected non null empty list returned from %s", id), retArr != null); @@ -287,7 +290,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); Pair tskPair = getArtifactsTSKMock(artifacts); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getRecentDevices(ds, count); @@ -301,8 +304,8 @@ public class UserActivitySummaryTest { } /** - * Ensures that UserActivitySummaryGetter.getRecentDevices limits returned entries - to count provided. + * Ensures that UserActivitySummary.getRecentDevices limits returned entries + * to count provided. * * @throws TskCoreException * @throws NoServiceProviderException @@ -324,7 +327,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); Pair tskPair = getArtifactsTSKMock(returnedArtifacts); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getRecentDevices(dataSource, countRequested); verifyCalled(tskPair.getRight(), ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID(), dataSourceId, @@ -345,7 +348,7 @@ public class UserActivitySummaryTest { BlackboardArtifact item3 = getRecentDeviceArtifact(1003, dataSource, "ID1", "MAKE1", "MODEL1", DAY_SECONDS + 2); Pair tskPair = getArtifactsTSKMock(Arrays.asList(item1, item2, item3)); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getRecentDevices(dataSource, 10); @@ -393,7 +396,7 @@ public class UserActivitySummaryTest { List artList = Arrays.asList(art1a, art2a, art2b, art1b, art1c); Pair tskPair = getArtifactsTSKMock(artList); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getMostRecentWebSearches(ds, 10); verifyCalled(tskPair.getRight(), ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID(), dataSourceId, "Expected getRecentDevices to call getArtifacts with correct arguments."); @@ -430,7 +433,11 @@ public class UserActivitySummaryTest { // set up a mock TextTranslationService returning a translation TextTranslationService translationService = TskMockUtils.getTextTranslationService(translator, hasProvider); - UserActivitySummaryGetter summary = new UserActivitySummaryGetter(); + UserActivitySummary summary = new UserActivitySummary( + () -> tskPair.getLeft(), + translationService, + TskMockUtils.getJavaLogger("UNIT TEST LOGGER") + ); List results = summary.getMostRecentWebSearches(ds, queries.size()); @@ -466,8 +473,8 @@ public class UserActivitySummaryTest { } /** - * Verify that UserActivitySummaryGetter.getMostRecentWebSearches handles - translation appropriately. + * Verify that UserActivitySummary.getMostRecentWebSearches handles + * translation appropriately. * * @throws SleuthkitCaseProviderException * @throws TskCoreException @@ -495,8 +502,8 @@ public class UserActivitySummaryTest { } /** - * Ensure that UserActivitySummaryGetter.getMostRecentWebSearches results limited - to count. + * Ensure that UserActivitySummary.getMostRecentWebSearches results limited + * to count. * * @throws TskCoreException * @throws NoServiceProviderException @@ -518,7 +525,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); Pair tskPair = getArtifactsTSKMock(returnedArtifacts); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getMostRecentWebSearches(dataSource, countRequested); verifyCalled(tskPair.getRight(), ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID(), dataSourceId, @@ -551,8 +558,8 @@ public class UserActivitySummaryTest { private static final long DOMAIN_WINDOW_DAYS = 30; /** - * UserActivitySummaryGetter.getRecentDomains should return results within 30 days - of the most recent access. + * UserActivitySummary.getRecentDomains should return results within 30 days + * of the most recent access. * * @throws TskCoreException * @throws SleuthkitCaseProviderException @@ -582,7 +589,7 @@ public class UserActivitySummaryTest { Pair tskPair = getArtifactsTSKMock(retArr); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List domains = summary.getRecentDomains(dataSource, 10); @@ -626,7 +633,7 @@ public class UserActivitySummaryTest { Pair tskPair = getArtifactsTSKMock(retArr); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List domains = summary.getRecentDomains(dataSource, 10); @@ -663,7 +670,7 @@ public class UserActivitySummaryTest { List retArr = Arrays.asList(artifact1, artifact1a, artifact2, artifact2a, artifact2b); Pair tskPair = getArtifactsTSKMock(retArr); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List domains = summary.getRecentDomains(dataSource, 10); @@ -682,8 +689,8 @@ public class UserActivitySummaryTest { } /** - * Ensure that UserActivitySummaryGetter.getRecentDomains limits to count - appropriately. + * Ensure that UserActivitySummary.getRecentDomains limits to count + * appropriately. * * @throws TskCoreException * @throws NoServiceProviderException @@ -712,7 +719,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); Pair tskPair = getArtifactsTSKMock(returnedArtifacts); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getRecentDomains(dataSource, countRequested); verifyCalled(tskPair.getRight(), ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID(), dataSourceId, @@ -811,7 +818,7 @@ public class UserActivitySummaryTest { } /** - * Performs a test on UserActivitySummaryGetter.getRecentAccounts. + * Performs a test on UserActivitySummary.getRecentAccounts. * * @param dataSource The datasource to use as parameter. * @param count The count to use as a parameter. @@ -842,7 +849,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); }); - UserActivitySummaryGetter summary = getTestClass(mockCase, false, null); + UserActivitySummary summary = getTestClass(mockCase, false, null); List receivedResults = summary.getRecentAccounts(dataSource, count); @@ -873,8 +880,8 @@ public class UserActivitySummaryTest { } /** - * Verify that UserActivitySummaryGetter.getRecentAccounts attempts to find a date - but if none present, the artifact is excluded. + * Verify that UserActivitySummary.getRecentAccounts attempts to find a date + * but if none present, the artifact is excluded. * * @throws TskCoreException * @throws NoServiceProviderException @@ -943,8 +950,8 @@ public class UserActivitySummaryTest { } /** - * Verifies that UserActivitySummaryGetter.getRecentAccounts groups appropriately - by account type. + * Verifies that UserActivitySummary.getRecentAccounts groups appropriately + * by account type. * * @throws TskCoreException * @throws NoServiceProviderException @@ -979,8 +986,8 @@ public class UserActivitySummaryTest { } /** - * Verifies that UserActivitySummaryGetter.getRecentAccounts properly limits - results returned. + * Verifies that UserActivitySummary.getRecentAccounts properly limits + * results returned. * * @throws TskCoreException * @throws NoServiceProviderException @@ -1000,7 +1007,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); Pair tskPair = getArtifactsTSKMock(returnedArtifacts); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getRecentAccounts(dataSource, countRequested); verifyCalled(tskPair.getRight(), ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(), dataSource.getId(), @@ -1037,7 +1044,7 @@ public class UserActivitySummaryTest { expected.put("/Other Path/Item/Item.exe", ""); Pair tskPair = getArtifactsTSKMock(null); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); for (Entry path : expected.entrySet()) { Assert.assertTrue(path.getValue().equalsIgnoreCase(summary.getShortFolderName(path.getKey(), "Item.exe"))); @@ -1105,7 +1112,7 @@ public class UserActivitySummaryTest { successful, successful2 )); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getTopPrograms(ds1, 10); Assert.assertEquals(2, results.size()); @@ -1143,7 +1150,7 @@ public class UserActivitySummaryTest { prog2, prog2a, prog2b, prog3, prog3a, prog3b )); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getTopPrograms(ds1, 10); Assert.assertEquals(3, results.size()); @@ -1167,7 +1174,7 @@ public class UserActivitySummaryTest { throws TskCoreException, NoServiceProviderException, TranslationException, SleuthkitCaseProviderException { Pair tskPair = getArtifactsTSKMock(artifacts); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getTopPrograms(ds1, 10); Assert.assertEquals(programNamesReturned.size(), results.size()); @@ -1177,8 +1184,8 @@ public class UserActivitySummaryTest { } /** - * Ensure that UserActivitySummaryGetter.getTopPrograms properly orders results - (first by run count, then date, then program name). + * Ensure that UserActivitySummary.getTopPrograms properly orders results + * (first by run count, then date, then program name). * * @throws TskCoreException * @throws NoServiceProviderException @@ -1207,8 +1214,8 @@ public class UserActivitySummaryTest { } /** - * Ensure that UserActivitySummaryGetter.getTopPrograms properly limits results - (if no run count and no run date, then no limit). + * Ensure that UserActivitySummary.getTopPrograms properly limits results + * (if no run count and no run date, then no limit). * * @throws TskCoreException * @throws NoServiceProviderException @@ -1232,7 +1239,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); Pair tskPair = getArtifactsTSKMock(returnedArtifacts); - UserActivitySummaryGetter summary = getTestClass(tskPair.getLeft(), false, null); + UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null); List results = summary.getTopPrograms(dataSource, countRequested); verifyCalled(tskPair.getRight(), ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID(), dataSourceId, @@ -1246,7 +1253,7 @@ public class UserActivitySummaryTest { .collect(Collectors.toList()); Pair tskPairAlphabetical = getArtifactsTSKMock(returnedArtifactsAlphabetical); - UserActivitySummaryGetter summaryAlphabetical = getTestClass(tskPairAlphabetical.getLeft(), false, null); + UserActivitySummary summaryAlphabetical = getTestClass(tskPairAlphabetical.getLeft(), false, null); List resultsAlphabetical = summaryAlphabetical.getTopPrograms(dataSource, countRequested); verifyCalled(tskPairAlphabetical.getRight(), ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID(), dataSourceId, From b469e2b5bf97309da84a8c7ac09a5d649fad46ab Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 19 Aug 2021 09:48:30 -0400 Subject: [PATCH 41/76] Resolved TODOs --- .../datamodel/ContainerSummary.java | 2 -- .../datamodel/DataSourceInfoUtilities.java | 2 -- .../datamodel/TypesSummary.java | 2 -- .../datamodel/UserActivitySummary.java | 1 - .../datasourcesummary/ui/UserActivityPanel.java | 5 +++-- .../ui/UserActivitySummaryGetter.java | 16 ---------------- .../ExportUserActivity.java | 14 +------------- 7 files changed, 4 insertions(+), 38 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java index 428c92047f..4ecacdb059 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/ContainerSummary.java @@ -212,8 +212,6 @@ public class ContainerSummary { String separator = ", "; return getConcattedStringsResult(query, valueParam, separator); } - - // ELTODO everything below is NOT in develop! /** * Data model data for data source images. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java index 7e51a53037..dfbe49c282 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java @@ -433,8 +433,6 @@ public final class DataSourceInfoUtilities { Long longVal = getLongOrNull(artifact, attributeType); return (longVal == null || longVal == 0) ? null : new Date(longVal * 1000); } - - // ELTODO everything below is not in develop /** * Returns the long value or zero if longVal is null. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java index 6c1b71861b..b13e852b95 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TypesSummary.java @@ -143,8 +143,6 @@ public class TypesSummary { return DataSourceInfoUtilities.getCountOfRegularFiles(provider.get(), currentDataSource, "type=" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType()); } - - // ELTODO everything below is not in develop /** * Information concerning a particular file type category. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java index 8310c1f5b0..a32867ffce 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/UserActivitySummary.java @@ -186,7 +186,6 @@ public class UserActivitySummary { } } - // ELTODO this method is not in develop /** * Determines a short folder name if any. Otherwise, returns empty string. * diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index 3ac26a3b1e..bb81dc9b2e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -28,6 +28,7 @@ import java.util.Locale; import java.util.function.Function; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.LastAccessedArtifact; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopAccountResult; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopDeviceAttachedResult; @@ -342,8 +343,8 @@ public class UserActivityPanel extends BaseDataSourceSummaryPanel { * * @return The underlying short folder name if one exists. */ - private String getShortFolderName(String path, String appName) { - return this.userActivityData.getShortFolderName(path, appName); + private static String getShortFolderName(String path, String appName) { + return UserActivitySummary.getShortFolderName(path, appName); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java index ab98b0e271..70ad958be5 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java @@ -172,22 +172,6 @@ public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor return userActivity.getRecentAccounts(dataSource, count); } - /** - * Determines a short folder name if any. Otherwise, returns empty string. - * - * @param strPath The string path. - * @param applicationName The application name. - * - * @return The short folder name or empty string if not found. - */ - public String getShortFolderName(String strPath, String applicationName) { - if (strPath == null) { - return ""; - } - - return UserActivitySummary.getShortFolderName(strPath, applicationName); - } - /** * Retrieves the top programs results for the given data source limited to * the count provided as a parameter. The highest run times are at the top diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java index 028073e53d..7be189cc1b 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java @@ -91,7 +91,7 @@ class ExportUserActivity { Bundle.ExportUserActivity_TopProgramsTableModel_folder_header(), (prog) -> { return new DefaultCellModel<>( - getShortFolderName( + UserActivitySummary.getShortFolderName( prog.getProgramPath(), prog.getProgramName())); }, @@ -219,18 +219,6 @@ class ExportUserActivity { }; } - /** - * Queries DataSourceTopProgramsSummary instance for short folder name. - * - * @param path The path for the application. - * @param appName The application name. - * - * @return The underlying short folder name if one exists. - */ - private static String getShortFolderName(String path, String appName) { - return UserActivitySummary.getShortFolderName(path, appName); - } - List getExports(DataSource dataSource) { DataFetcher> topProgramsFetcher = (ds) -> userSummary.getTopPrograms(ds, TOP_PROGS_COUNT); From d56f05267e243933c111589351b09e90ef586659 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 19 Aug 2021 12:42:06 -0400 Subject: [PATCH 42/76] 7877 initial implementation of SearchContext for search cancellation --- .../discovery/search/AbstractFilter.java | 2 +- .../discovery/search/DiscoveryAttributes.java | 82 +++++++++++++------ .../discovery/search/DiscoveryKeyUtils.java | 17 +++- .../discovery/search/DomainSearch.java | 31 +++++-- .../discovery/search/DomainSearchCache.java | 4 +- .../search/DomainSearchCacheLoader.java | 4 +- .../autopsy/discovery/search/FileSearch.java | 30 +++---- .../search/SearchCancellationException.java | 31 +++++++ .../discovery/search/SearchContext.java | 24 ++++++ .../discovery/search/SearchFiltering.java | 67 ++++++++++----- .../autopsy/discovery/ui/DiscoveryDialog.java | 1 + .../autopsy/discovery/ui/PageWorker.java | 13 ++- .../autopsy/discovery/ui/SearchWorker.java | 36 ++++---- .../ui/SwingWorkerSearchContext.java | 37 +++++++++ 14 files changed, 275 insertions(+), 104 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/search/SearchCancellationException.java create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/search/SearchContext.java create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ui/SwingWorkerSearchContext.java diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java index bb2e258f2e..3fc2b33966 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java @@ -61,7 +61,7 @@ public abstract class AbstractFilter { * @throws DiscoveryException */ public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { + CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { return new ArrayList<>(); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index 16e0e80f1b..3f44b796f9 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -1,7 +1,7 @@ /* * Autopsy * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -81,7 +81,7 @@ public class DiscoveryAttributes { * * @throws DiscoveryException */ - public void addAttributeToResults(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + public void addAttributeToResults(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { // Default is to do nothing } } @@ -154,10 +154,13 @@ public class DiscoveryAttributes { @Override public void addAttributeToResults(List results, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { + CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { try { - Map> domainsToCategories = getDomainsWithWebCategories(caseDb); + Map> domainsToCategories = getDomainsWithWebCategories(caseDb, context); for (Result result : results) { + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while Domain Category Attribute was being added."); + } if (result instanceof ResultDomain) { ResultDomain domain = (ResultDomain) result; domain.addWebCategories(domainsToCategories.get(domain.getDomain())); @@ -173,13 +176,16 @@ public class DiscoveryAttributes { * the category name attribute. Each ResultDomain is then parsed and * matched against this map of values. */ - private Map> getDomainsWithWebCategories(SleuthkitCase caseDb) throws TskCoreException, InterruptedException { + private Map> getDomainsWithWebCategories(SleuthkitCase caseDb, SearchContext context) throws TskCoreException, InterruptedException, SearchCancellationException { Map> domainToCategory = new HashMap<>(); for (BlackboardArtifact artifact : caseDb.getBlackboardArtifacts(TSK_WEB_CATEGORIZATION)) { if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } + if (context.searchIsCancelled()) { + throw new SearchCancellationException("Search was cancelled while getting domains for artifact type: " + artifact.getDisplayName()); + } BlackboardAttribute webCategory = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME)); BlackboardAttribute domain = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN)); if (webCategory != null && domain != null) { @@ -206,14 +212,16 @@ public class DiscoveryAttributes { @Override public void addAttributeToResults(List results, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { + CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { // Get pairs of (object ID, keyword list name) for all files in the list of files that have // keyword list hits. String selectQuery = createSetNameClause(results, BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); - SetKeywordListNamesCallback callback = new SetKeywordListNamesCallback(results); + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while Keyword List Attribute was being added."); + } try { caseDb.getCaseDbAccessManager().select(selectQuery, callback); } catch (TskCoreException ex) { @@ -279,7 +287,7 @@ public class DiscoveryAttributes { * this map, all domain instances that represent google.com can be updated * after one simple lookup. */ - private static Map> organizeByValue(List domainsBatch, CorrelationAttributeInstance.Type attributeType) { + private static Map> organizeByValue(List domainsBatch, CorrelationAttributeInstance.Type attributeType, SearchContext context) throws SearchCancellationException { final Map> resultDomainTable = new HashMap<>(); for (ResultDomain domainInstance : domainsBatch) { try { @@ -288,6 +296,9 @@ public class DiscoveryAttributes { final List bucket = resultDomainTable.getOrDefault(normalizedDomain, new ArrayList<>()); bucket.add(domainInstance); resultDomainTable.put(normalizedDomain, bucket); + if (context.searchIsCancelled()) { + throw new SearchCancellationException("Search was cancelled while orgainizing domains by their normalized value."); + } } catch (CorrelationAttributeNormalizationException ex) { logger.log(Level.INFO, String.format("Domain [%s] failed normalization, skipping...", domainInstance.getDomain())); } @@ -322,37 +333,40 @@ public class DiscoveryAttributes { @Override public void addAttributeToResults(List results, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { + CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { if (centralRepoDb != null) { - processFilesWithCr(results, centralRepoDb); + processFilesWithCr(results, centralRepoDb, context); } } - private void processFilesWithCr(List results, CentralRepository centralRepo) throws DiscoveryException { + private void processFilesWithCr(List results, CentralRepository centralRepo, SearchContext context) throws DiscoveryException, SearchCancellationException { List domainsBatch = new ArrayList<>(); for (Result result : results) { + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while Previously Notable attribute was being calculated with the CR."); + } if (result.getType() == SearchData.Type.DOMAIN) { domainsBatch.add((ResultDomain) result); if (domainsBatch.size() == DOMAIN_BATCH_SIZE) { - queryPreviouslyNotable(domainsBatch, centralRepo); + queryPreviouslyNotable(domainsBatch, centralRepo, context); domainsBatch.clear(); } } } - queryPreviouslyNotable(domainsBatch, centralRepo); + queryPreviouslyNotable(domainsBatch, centralRepo, context); } - private void queryPreviouslyNotable(List domainsBatch, CentralRepository centralRepo) throws DiscoveryException { + private void queryPreviouslyNotable(List domainsBatch, CentralRepository centralRepo, SearchContext context) throws DiscoveryException, SearchCancellationException { if (domainsBatch.isEmpty()) { return; } try { final CorrelationAttributeInstance.Type attributeType = centralRepo.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID); - final Map> resultDomainTable = organizeByValue(domainsBatch, attributeType); + final Map> resultDomainTable = organizeByValue(domainsBatch, attributeType, context); final String values = createCSV(resultDomainTable.keySet()); final String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType); @@ -421,7 +435,7 @@ public class DiscoveryAttributes { @Override public void addAttributeToResults(List results, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { + CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { if (centralRepoDb == null) { for (Result result : results) { if (result.getFrequency() == SearchData.Frequency.UNKNOWN && result.getKnown() == TskData.FileKnown.KNOWN) { @@ -429,7 +443,7 @@ public class DiscoveryAttributes { } } } else { - processResultFilesForCR(results, centralRepoDb); + processResultFilesForCR(results, centralRepoDb, context); } } @@ -442,11 +456,14 @@ public class DiscoveryAttributes { * @param centralRepoDb The central repository currently in use. */ private void processResultFilesForCR(List results, - CentralRepository centralRepoDb) throws DiscoveryException { + CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { List currentFiles = new ArrayList<>(); Set hashesToLookUp = new HashSet<>(); List domainsToQuery = new ArrayList<>(); for (Result result : results) { + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while Frequency attribute was being calculated with the CR."); + } // If frequency was already calculated, skip... if (result.getFrequency() == SearchData.Frequency.UNKNOWN) { if (result.getKnown() == TskData.FileKnown.KNOWN) { @@ -470,15 +487,14 @@ public class DiscoveryAttributes { } else { domainsToQuery.add((ResultDomain) result); if (domainsToQuery.size() == DOMAIN_BATCH_SIZE) { - queryDomainFrequency(domainsToQuery, centralRepoDb); - + queryDomainFrequency(domainsToQuery, centralRepoDb, context); domainsToQuery.clear(); } } } } - queryDomainFrequency(domainsToQuery, centralRepoDb); + queryDomainFrequency(domainsToQuery, centralRepoDb, context); computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); } } @@ -491,13 +507,13 @@ public class DiscoveryAttributes { * * @throws DiscoveryException */ - private static void queryDomainFrequency(List domainsToQuery, CentralRepository centralRepository) throws DiscoveryException { + private static void queryDomainFrequency(List domainsToQuery, CentralRepository centralRepository, SearchContext context) throws DiscoveryException, SearchCancellationException { if (domainsToQuery.isEmpty()) { return; } try { final CorrelationAttributeInstance.Type attributeType = centralRepository.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID); - final Map> resultDomainTable = organizeByValue(domainsToQuery, attributeType); + final Map> resultDomainTable = organizeByValue(domainsToQuery, attributeType, context); final String values = createCSV(resultDomainTable.keySet()); final String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType); final String domainFrequencyQuery = " value AS domain_name, COUNT(value) AS frequency FROM" @@ -620,7 +636,7 @@ public class DiscoveryAttributes { @Override public void addAttributeToResults(List results, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { + CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { // Get pairs of (object ID, hash set name) for all files in the list of files that have // hash set hits. @@ -628,6 +644,9 @@ public class DiscoveryAttributes { BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); HashSetNamesCallback callback = new HashSetNamesCallback(results); + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while Hash Hit attribute was being added."); + } try { caseDb.getCaseDbAccessManager().select(selectQuery, callback); } catch (TskCoreException ex) { @@ -695,7 +714,7 @@ public class DiscoveryAttributes { @Override public void addAttributeToResults(List results, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { + CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { // Get pairs of (object ID, interesting item set name) for all files in the list of files that have // interesting file set hits. @@ -703,6 +722,9 @@ public class DiscoveryAttributes { BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); InterestingFileSetNamesCallback callback = new InterestingFileSetNamesCallback(results); + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while Interesting Item attribute was being added."); + } try { caseDb.getCaseDbAccessManager().select(selectQuery, callback); } catch (TskCoreException ex) { @@ -808,7 +830,7 @@ public class DiscoveryAttributes { @Override public void addAttributeToResults(List results, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { + CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { // Get pairs of (object ID, object type name) for all files in the list of files that have // objects detected @@ -816,6 +838,9 @@ public class DiscoveryAttributes { BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID()); ObjectDetectedNamesCallback callback = new ObjectDetectedNamesCallback(results); + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while Object Detected attribute was being added."); + } try { caseDb.getCaseDbAccessManager().select(selectQuery, callback); } catch (TskCoreException ex) { @@ -884,10 +909,13 @@ public class DiscoveryAttributes { @Override public void addAttributeToResults(List results, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { + CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { try { for (Result result : results) { + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while File Tag attribute was being added."); + } if (result.getType() == SearchData.Type.DOMAIN) { return; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index c201414199..7d2a482afb 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -59,6 +59,7 @@ public class DiscoveryKeyUtils { private final List filters; private final SleuthkitCase sleuthkitCase; private final CentralRepository centralRepository; + private final SearchContext context; /** * Construct a new SearchKey with all information that defines a search. @@ -70,16 +71,20 @@ public class DiscoveryKeyUtils { * @param sortingMethod The method to sort the results by. * @param sleuthkitCase The SleuthkitCase being searched. * @param centralRepository The Central Repository being searched. + * @param context The SearchContext which reflects the search + * being performed to get results for this + * key. */ SearchKey(String userName, List filters, DiscoveryAttributes.AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, ResultsSorter.SortingMethod sortingMethod, - SleuthkitCase sleuthkitCase, CentralRepository centralRepository) { + SleuthkitCase sleuthkitCase, CentralRepository centralRepository, SearchContext context) { this.groupAttributeType = groupAttributeType; this.groupSortingType = groupSortingType; this.sortingMethod = sortingMethod; this.filters = filters; + this.context = context; StringBuilder searchStringBuilder = new StringBuilder(); searchStringBuilder.append(userName); @@ -93,8 +98,8 @@ public class DiscoveryKeyUtils { } /** - * Construct a SearchKey without a SleuthkitCase or CentralRepositry - * instance. + * Construct a SearchKey without a SearchContext, SleuthkitCase or + * CentralRepositry instance. * * @param userName The name of the user performing the search. * @param filters The Filters being used for the search. @@ -107,7 +112,7 @@ public class DiscoveryKeyUtils { Group.GroupSortingAlgorithm groupSortingType, ResultsSorter.SortingMethod sortingMethod) { this(userName, filters, groupAttributeType, groupSortingType, - sortingMethod, null, null); + sortingMethod, null, null, null); } @Override @@ -141,6 +146,10 @@ public class DiscoveryKeyUtils { return hash; } + SearchContext getContext() { + return context; + } + /** * Get the String representation of this key. * diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java index caffcfb27a..41f11c6fa8 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.discovery.search; import java.awt.Image; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; @@ -65,8 +66,8 @@ public class DomainSearch { } /** - * Run the domain search to get the search results caching new results for - * access at later time. + * Run the domain search to get the group keys and sizes. Clears cache of + * search results, caching new results for access at later time. * * @param userName The name of the user performing the search. * @param filters The filters to apply. @@ -78,19 +79,31 @@ public class DomainSearch { * @param centralRepoDb The central repository database. Can be null * if not needed. * - * @return Domain search results matching the given parameters. + * @return A LinkedHashMap grouped and sorted according to the parameters. * * @throws DiscoveryException */ - public Map> getSearchResults(String userName, + public Map getGroupSizes(String userName, List filters, DiscoveryAttributes.AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, ResultsSorter.SortingMethod domainSortingMethod, - SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { - return searchCache.get( + SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { + + final Map> searchResults = searchCache.get( userName, filters, groupAttributeType, groupSortingType, - domainSortingMethod, caseDb, centralRepoDb); + domainSortingMethod, caseDb, centralRepoDb, context); + + // Transform the cached results into a map of group key to group size. + final LinkedHashMap groupSizes = new LinkedHashMap<>(); + for (GroupKey groupKey : searchResults.keySet()) { + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled before group sizes were finished being calculated"); + } + groupSizes.put(groupKey, searchResults.get(groupKey).size()); + } + + return groupSizes; } /** @@ -121,11 +134,11 @@ public class DomainSearch { Group.GroupSortingAlgorithm groupSortingType, ResultsSorter.SortingMethod domainSortingMethod, GroupKey groupKey, int startingEntry, int numberOfEntries, - SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { final Map> searchResults = searchCache.get( userName, filters, groupAttributeType, groupSortingType, - domainSortingMethod, caseDb, centralRepoDb); + domainSortingMethod, caseDb, centralRepoDb, context); final List domainsInGroup = searchResults.get(groupKey); final List page = new ArrayList<>(); for (int i = startingEntry; (i < startingEntry + numberOfEntries) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java index 306a66b287..38def5e4c0 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java @@ -65,10 +65,10 @@ class DomainSearchCache { DiscoveryAttributes.AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, ResultsSorter.SortingMethod domainSortingMethod, - SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { try { final SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, - groupSortingType, domainSortingMethod, caseDb, centralRepoDb); + groupSortingType, domainSortingMethod, caseDb, centralRepoDb, context); return cache.get(searchKey); } catch (ExecutionException ex) { throw new DiscoveryException("Error fetching results from cache", ex.getCause()); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java index db2ada61de..6a302fdab1 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoader.java @@ -73,7 +73,7 @@ class DomainSearchCacheLoader extends CacheLoader results = SearchFiltering.runQueries(filters, caseDb, centralRepoDb); + List results = SearchFiltering.runQueries(filters, caseDb, centralRepoDb, context); // Add the data to resultFiles for any attributes needed for sorting and grouping - addAttributes(attributesNeededForGroupingOrSorting, results, caseDb, centralRepoDb); + addAttributes(attributesNeededForGroupingOrSorting, results, caseDb, centralRepoDb, context); // Collect everything in the search results SearchResults searchResults = new SearchResults(groupSortingType, groupAttributeType, fileSortingMethod); @@ -124,11 +124,14 @@ public class FileSearch { AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, ResultsSorter.SortingMethod fileSortingMethod, - SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { Map> searchResults = runFileSearch(userName, filters, - groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb); + groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb, context); LinkedHashMap groupSizes = new LinkedHashMap<>(); for (GroupKey groupKey : searchResults.keySet()) { + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled before group sizes were finished being calculated"); + } groupSizes.put(groupKey, searchResults.get(groupKey).size()); } return groupSizes; @@ -164,7 +167,7 @@ public class FileSearch { GroupKey groupKey, int startingEntry, int numberOfEntries, - SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { //the group should be in the cache at this point List filesInGroup = null; SearchKey searchKey = new SearchKey(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod); @@ -178,7 +181,7 @@ public class FileSearch { List page = new ArrayList<>(); if (filesInGroup == null) { logger.log(Level.INFO, "Group {0} was not cached, performing search to cache all groups again", groupKey); - runFileSearch(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb); + runFileSearch(userName, filters, groupAttributeType, groupSortingType, fileSortingMethod, caseDb, centralRepoDb, context); synchronized (searchCache) { resultsMap = searchCache.getIfPresent(searchKey.getKeyString()); } @@ -218,7 +221,6 @@ public class FileSearch { TextSummarizer localSummarizer; synchronized (searchCache) { localSummarizer = SummaryHelpers.getLocalSummarizer(); - } if (localSummarizer != null) { try { @@ -257,7 +259,7 @@ public class FileSearch { AttributeType groupAttributeType, Group.GroupSortingAlgorithm groupSortingType, ResultsSorter.SortingMethod fileSortingMethod, - SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { // Make a list of attributes that we want to add values for. This ensures the // ResultFile objects will have all needed fields set when it's time to group @@ -268,10 +270,10 @@ public class FileSearch { attributesNeededForGroupingOrSorting.addAll(fileSortingMethod.getRequiredAttributes()); // Run the queries for each filter - List results = SearchFiltering.runQueries(filters, caseDb, centralRepoDb); + List results = SearchFiltering.runQueries(filters, caseDb, centralRepoDb, context); // Add the data to resultFiles for any attributes needed for sorting and grouping - addAttributes(attributesNeededForGroupingOrSorting, results, caseDb, centralRepoDb); + addAttributes(attributesNeededForGroupingOrSorting, results, caseDb, centralRepoDb, context); // Collect everything in the search results SearchResults searchResults = new SearchResults(groupSortingType, groupAttributeType, fileSortingMethod); @@ -298,10 +300,10 @@ public class FileSearch { * * @throws DiscoveryException */ - private static void addAttributes(List attrs, List results, SleuthkitCase caseDb, CentralRepository centralRepoDb) - throws DiscoveryException { + private static void addAttributes(List attrs, List results, SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) + throws DiscoveryException, SearchCancellationException { for (AttributeType attr : attrs) { - attr.addAttributeToResults(results, caseDb, centralRepoDb); + attr.addAttributeToResults(results, caseDb, centralRepoDb, context); } } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchCancellationException.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchCancellationException.java new file mode 100644 index 0000000000..f268e20518 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchCancellationException.java @@ -0,0 +1,31 @@ +/* + * Autopsy + * + * Copyright 2021 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.discovery.search; + +import java.util.concurrent.CancellationException; + +public class SearchCancellationException extends CancellationException { + + private static final long serialVersionUID = 1L; + + SearchCancellationException(String message) { + super(message); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchContext.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchContext.java new file mode 100644 index 0000000000..effde3d353 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchContext.java @@ -0,0 +1,24 @@ +/* + * Autopsy + * + * Copyright 2021 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.discovery.search; + +public interface SearchContext { + + boolean searchIsCancelled(); +} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index 29a4dd698c..9eae2b1513 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -63,7 +63,7 @@ public class SearchFiltering { * * @return List of Results from the search performed. */ - static List runQueries(List filters, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws DiscoveryException { + static List runQueries(List filters, SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { if (caseDb == null) { throw new DiscoveryException("Case DB parameter is null"); // NON-NLS } @@ -82,8 +82,13 @@ public class SearchFiltering { // The file search filter is required, so this should never be empty. throw new DiscoveryException("Selected filters do not include a case database query"); } + if (context.searchIsCancelled()) { + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled before result list could be retrieved."); + } + } try { - return getResultList(filters, combinedQuery, caseDb, centralRepoDb); + return getResultList(filters, combinedQuery, caseDb, centralRepoDb, context); } catch (TskCoreException ex) { throw new DiscoveryException("Error querying case database", ex); // NON-NLS } @@ -103,11 +108,13 @@ public class SearchFiltering { * @throws TskCoreException * @throws DiscoveryException */ - private static List getResultList(List filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb) throws TskCoreException, DiscoveryException { + private static List getResultList(List filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws TskCoreException, DiscoveryException, SearchCancellationException { // Get all matching abstract files List resultList = new ArrayList<>(); List sqlResults = caseDb.findAllFilesWhere(combinedQuery); - + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while the case database query was being performed."); + } // If there are no results, return now if (sqlResults.isEmpty()) { return resultList; @@ -120,8 +127,11 @@ public class SearchFiltering { // Now run any non-SQL filters. for (AbstractFilter filter : filters) { + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while alternate filters were being applied."); + } if (filter.useAlternateFilter()) { - resultList = filter.applyAlternateFilter(resultList, caseDb, centralRepoDb); + resultList = filter.applyAlternateFilter(resultList, caseDb, centralRepoDb, context); } // There are no matches for the filters run so far, so return if (resultList.isEmpty()) { @@ -227,7 +237,7 @@ public class SearchFiltering { public Collection getTypes() { return Collections.unmodifiableCollection(types); } - + private StringJoiner joinStandardArtifactTypes() { StringJoiner joiner = new StringJoiner(","); for (ARTIFACT_TYPE type : types) { @@ -241,9 +251,10 @@ public class SearchFiltering { StringJoiner joiner = joinStandardArtifactTypes(); return "artifact_type_id IN (" + joiner + ")"; } - + /** - * Used by backend domain search code to query for additional artifact types. + * Used by backend domain search code to query for additional artifact + * types. */ String getWhereClause(List nonVisibleArtifactTypesToInclude) { StringJoiner joiner = joinStandardArtifactTypes(); @@ -674,14 +685,17 @@ public class SearchFiltering { @Override public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { + CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { // Set the frequency for each file DiscoveryAttributes.FrequencyAttribute freqAttr = new DiscoveryAttributes.FrequencyAttribute(); - freqAttr.addAttributeToResults(currentResults, caseDb, centralRepoDb); + freqAttr.addAttributeToResults(currentResults, caseDb, centralRepoDb, context); // If the frequency matches the filter, add the file to the results List frequencyResults = new ArrayList<>(); for (Result file : currentResults) { + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while Frequency alternate filter was being applied."); + } if (frequencies.contains(file.getFrequency())) { frequencyResults.add(file); } @@ -705,7 +719,7 @@ public class SearchFiltering { return Bundle.SearchFiltering_FrequencyFilter_desc(desc); } } - + /** * A filter for domains with known account types. */ @@ -715,17 +729,20 @@ public class SearchFiltering { public String getWhereClause() { throw new UnsupportedOperationException("Not supported, this is an alternative filter."); } - + @Override public boolean useAlternateFilter() { return true; } - + @Override public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { + CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { List filteredResults = new ArrayList<>(); for (Result result : currentResults) { + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while Known Account Type alternate filter was being applied."); + } if (result instanceof ResultDomain) { ResultDomain domain = (ResultDomain) result; if (domain.hasKnownAccountType()) { @@ -745,9 +762,9 @@ public class SearchFiltering { public String getDesc() { return Bundle.SearchFiltering_KnownAccountTypeFilter_desc(); } - + } - + /** * A filter for previously notable content in the central repository. */ @@ -757,19 +774,22 @@ public class SearchFiltering { public String getWhereClause() { throw new UnsupportedOperationException("Not supported, this is an alternative filter."); } - + @Override public boolean useAlternateFilter() { return true; } - + @Override public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { + CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { DiscoveryAttributes.PreviouslyNotableAttribute previouslyNotableAttr = new DiscoveryAttributes.PreviouslyNotableAttribute(); - previouslyNotableAttr.addAttributeToResults(currentResults, caseDb, centralRepoDb); + previouslyNotableAttr.addAttributeToResults(currentResults, caseDb, centralRepoDb, context); List filteredResults = new ArrayList<>(); for (Result file : currentResults) { + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while Previously Notable alternate filter was being applied."); + } if (file.getPreviouslyNotableInCR() == SearchData.PreviouslyNotable.PREVIOUSLY_NOTABLE) { filteredResults.add(file); } @@ -784,7 +804,7 @@ public class SearchFiltering { public String getDesc() { return Bundle.SearchFiltering_PreviouslyNotableFilter_desc(); } - + } /** @@ -1068,7 +1088,7 @@ public class SearchFiltering { @Override public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, - CentralRepository centralRepoDb) throws DiscoveryException { + CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { if (centralRepoDb == null) { throw new DiscoveryException("Can not run Previously Notable filter with null Central Repository DB"); // NON-NLS @@ -1087,6 +1107,9 @@ public class SearchFiltering { CorrelationAttributeInstance.Type type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID); for (Result result : currentResults) { + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while Notable alternate filter was being applied."); + } ResultFile file = (ResultFile) result; if (result.getType() == SearchData.Type.DOMAIN) { break; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index fe2c61b38d..74baf390c6 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -794,4 +794,5 @@ final class DiscoveryDialog extends javax.swing.JDialog { return false; } } + } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java index 491e618683..e5e23fe4aa 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java @@ -36,6 +36,8 @@ import org.sleuthkit.autopsy.discovery.search.DiscoveryException; import org.sleuthkit.autopsy.discovery.search.DomainSearch; import org.sleuthkit.autopsy.discovery.search.ResultsSorter; import org.sleuthkit.autopsy.discovery.search.Result; +import org.sleuthkit.autopsy.discovery.search.SearchCancellationException; +import org.sleuthkit.autopsy.discovery.search.SearchContext; /** * SwingWorker to retrieve the contents of a page. @@ -87,7 +89,7 @@ final class PageWorker extends SwingWorker { @Override protected Void doInBackground() throws Exception { - + SearchContext context = new SwingWorkerSearchContext(this); try { // Run the search if (resultType == SearchData.Type.DOMAIN) { @@ -96,17 +98,22 @@ final class PageWorker extends SwingWorker { groupingAttribute, groupSort, fileSortMethod, groupKey, startingEntry, pageSize, - Case.getCurrentCase().getSleuthkitCase(), centralRepo)); + Case.getCurrentCase().getSleuthkitCase(), centralRepo, context)); } else { results.addAll(FileSearch.getFilesInGroup(System.getProperty(USER_NAME_PROPERTY), searchfilters, groupingAttribute, groupSort, fileSortMethod, groupKey, startingEntry, pageSize, - Case.getCurrentCase().getSleuthkitCase(), centralRepo)); + Case.getCurrentCase().getSleuthkitCase(), centralRepo, context)); } } catch (DiscoveryException ex) { logger.log(Level.SEVERE, "Error running file search test", ex); cancel(true); + } catch (SearchCancellationException ex) { + //The does not explicitly have a way to cancell the loading of a page + //but they could have cancelled the search during the loading of the first page + //So this may or may not be an issue depending on when this occurred. + logger.log(Level.WARNING, "Search was cancelled while retrieving data for results page with starting entry: " + startingEntry, ex); } return null; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java index 7f9ee22c16..e507a8082b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java @@ -34,8 +34,9 @@ import org.sleuthkit.autopsy.discovery.search.Group; import org.sleuthkit.autopsy.discovery.search.FileSearch; import org.sleuthkit.autopsy.discovery.search.DiscoveryException; import org.sleuthkit.autopsy.discovery.search.DomainSearch; -import org.sleuthkit.autopsy.discovery.search.Result; import org.sleuthkit.autopsy.discovery.search.ResultsSorter; +import org.sleuthkit.autopsy.discovery.search.SearchCancellationException; +import org.sleuthkit.autopsy.discovery.search.SearchContext; import org.sleuthkit.autopsy.discovery.search.SearchData; /** @@ -76,35 +77,30 @@ final class SearchWorker extends SwingWorker { protected Void doInBackground() throws Exception { try { // Run the search + SearchContext context = new SwingWorkerSearchContext(this); if (searchType == SearchData.Type.DOMAIN) { DomainSearch domainSearch = new DomainSearch(); - final Map> searchResults = domainSearch.getSearchResults(System.getProperty(USER_NAME_PROPERTY), filters, + results.putAll(domainSearch.getGroupSizes(System.getProperty(USER_NAME_PROPERTY), filters, groupingAttr, groupSortAlgorithm, fileSort, - Case.getCurrentCase().getSleuthkitCase(), centralRepoDb); - // Transform the cached results into a map of group key to group size. - final LinkedHashMap groupSizes = new LinkedHashMap<>(); - for (GroupKey groupKey : searchResults.keySet()) { - if (isCancelled()) { - return null; - } - results.put(groupKey, searchResults.get(groupKey).size()); - } + Case.getCurrentCase().getSleuthkitCase(), centralRepoDb, context)); } else { - Map> searchResults = FileSearch.runFileSearch(System.getProperty(USER_NAME_PROPERTY), filters, - groupingAttr, groupSortAlgorithm, fileSort, Case.getCurrentCase().getSleuthkitCase(), centralRepoDb); - for (GroupKey groupKey : searchResults.keySet()) { - if (isCancelled()) { - return null; - } - results.put(groupKey, searchResults.get(groupKey).size()); - } + results.putAll(FileSearch.getGroupSizes(System.getProperty(USER_NAME_PROPERTY), filters, + groupingAttr, + groupSortAlgorithm, + fileSort, + Case.getCurrentCase().getSleuthkitCase(), centralRepoDb, context)); } } catch (DiscoveryException ex) { - logger.log(Level.SEVERE, "Error running file search test", ex); + logger.log(Level.SEVERE, "Error running file search test.", ex); cancel(true); + } catch (SearchCancellationException ex) { + //search cancellation exceptions should indicate that the user chose to cancell this search + //so would not be a problem but we might be curious what was being done when it was cancelled + logger.log(Level.INFO, "Discovery search was cancelled.", ex); } + return null; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SwingWorkerSearchContext.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SwingWorkerSearchContext.java new file mode 100644 index 0000000000..5af00e3f77 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SwingWorkerSearchContext.java @@ -0,0 +1,37 @@ +/* + * Autopsy + * + * Copyright 2021 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.discovery.ui; + +import javax.swing.SwingWorker; +import org.sleuthkit.autopsy.discovery.search.SearchContext; + + + class SwingWorkerSearchContext implements SearchContext { + + private final SwingWorker searchWorker; + + SwingWorkerSearchContext(SwingWorker worker) { + searchWorker = worker; + } + + @Override + public boolean searchIsCancelled() { + return searchWorker.isCancelled(); + } + } From 519d201ccfc1b4836474dafd1b2ed2b1843b9417 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 19 Aug 2021 13:08:26 -0400 Subject: [PATCH 43/76] Removed unused imports --- .../datamodel/DataSourceInfoUtilities.java | 2 - .../ui/TimelinePanel.java.bak | 358 ------------------ 2 files changed, 360 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java.bak diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java index dfbe49c282..becd78f418 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java @@ -30,8 +30,6 @@ import java.util.TreeMap; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.apache.commons.lang.StringUtils; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.Type; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java.bak b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java.bak deleted file mode 100755 index 6b1292139e..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java.bak +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2020-2021 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.datasourcesummary.ui; - -import java.awt.Color; -import java.text.DateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.logging.Level; -import org.apache.commons.collections.CollectionUtils; -import org.joda.time.DateTime; -import org.joda.time.Interval; -import org.openide.util.NbBundle.Messages; -import org.openide.util.actions.CallableSystemAction; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.OrderedKey; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.BarChartItem; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel; -import org.sleuthkit.autopsy.timeline.OpenTimelineAction; -import org.sleuthkit.autopsy.timeline.TimeLineController; -import org.sleuthkit.autopsy.timeline.TimeLineModule; -import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * A tab shown in data source summary displaying information about a data - * source's timeline events. - */ -@Messages({ - "TimelinePanel_earliestLabel_title=Earliest", - "TimelinePanel_latestLabel_title=Latest", - "TimlinePanel_last30DaysChart_title=Last 30 Days", - "TimlinePanel_last30DaysChart_fileEvts_title=File Events", - "TimlinePanel_last30DaysChart_artifactEvts_title=Result Events",}) -public class TimelinePanel extends BaseDataSourceSummaryPanel { - - private static final Logger logger = Logger.getLogger(TimelinePanel.class.getName()); - private static final long serialVersionUID = 1L; - - private static final String EARLIEST_LATEST_FORMAT_STR = "MMM d, yyyy"; - private static final DateFormat EARLIEST_LATEST_FORMAT = TimelineSummary.getUtcFormat(EARLIEST_LATEST_FORMAT_STR); - private static final DateFormat CHART_FORMAT = TimelineSummary.getUtcFormat("MMM d, yyyy"); - private static final int MOST_RECENT_DAYS_COUNT = 30; - - // components displayed in the tab - private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel(); - private final LoadableLabel earliestLabel = new LoadableLabel(Bundle.TimelinePanel_earliestLabel_title()); - private final LoadableLabel latestLabel = new LoadableLabel(Bundle.TimelinePanel_latestLabel_title()); - private final BarChartPanel last30DaysChart = new BarChartPanel(Bundle.TimlinePanel_last30DaysChart_title(), "", ""); - private final TimelineDataSourceUtils timelineUtils = TimelineDataSourceUtils.getInstance(); - - // all loadable components on this tab - private final List> loadableComponents = Arrays.asList(earliestLabel, latestLabel, last30DaysChart); - - private final DataFetcher dataFetcher; - - // actions to load data for this tab - private final List> dataFetchComponents; - - public TimelinePanel() { - this(new TimelineSummaryGetter()); - } - - /** - * Creates new form PastCasesPanel - */ - public TimelinePanel(TimelineSummaryGetter timelineData) { - super(timelineData); - - dataFetcher = (dataSource) -> timelineData.getData(dataSource, MOST_RECENT_DAYS_COUNT); - - // set up data acquisition methods - dataFetchComponents = Arrays.asList( - new DataFetchWorker.DataFetchComponents<>(dataFetcher, (result) -> handleResult(result))); - - initComponents(); - } - - private static final Color FILE_EVT_COLOR = new Color(228, 22, 28); - private static final Color ARTIFACT_EVT_COLOR = new Color(21, 227, 100); - - /** - * Converts DailyActivityAmount data retrieved from TimelineSummaryGetter - * into data to be displayed as a bar chart. - * - * @param recentDaysActivity The data retrieved from - * TimelineSummaryGetter. - * @param showIntermediateDates If true, shows all dates. If false, shows - * only first and last date. - * - * @return The data to be displayed in the BarChart. - */ - private List parseChartData(List recentDaysActivity, boolean showIntermediateDates) { - // if no data, return null indicating no result. - if (CollectionUtils.isEmpty(recentDaysActivity)) { - return null; - } - - // Create a bar chart item for each recent days activity item - List fileEvtCounts = new ArrayList<>(); - List artifactEvtCounts = new ArrayList<>(); - - for (int i = 0; i < recentDaysActivity.size(); i++) { - DailyActivityAmount curItem = recentDaysActivity.get(i); - - long fileAmt = curItem.getFileActivityCount(); - long artifactAmt = curItem.getArtifactActivityCount() * 100; - String formattedDate = (showIntermediateDates || i == 0 || i == recentDaysActivity.size() - 1) - ? TimelineSummary.formatDate(curItem.getDay(), CHART_FORMAT) : ""; - - OrderedKey thisKey = new OrderedKey(formattedDate, i); - fileEvtCounts.add(new BarChartItem(thisKey, fileAmt)); - artifactEvtCounts.add(new BarChartItem(thisKey, artifactAmt)); - } - - return Arrays.asList( - new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_fileEvts_title(), FILE_EVT_COLOR, fileEvtCounts), - new BarChartSeries(Bundle.TimlinePanel_last30DaysChart_artifactEvts_title(), ARTIFACT_EVT_COLOR, artifactEvtCounts)); - } - - private final Object timelineBtnLock = new Object(); - private TimelineSummaryData curTimelineData = null; - - /** - * Handles displaying the result for each displayable item in the - * TimelinePanel by breaking the TimelineSummaryData result into its - * constituent parts and then sending each data item to the pertinent - * component. - * - * @param result The result to be displayed on this tab. - */ - private void handleResult(DataFetchResult result) { - earliestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> TimelineSummary.formatDate(r.getMinDate(), EARLIEST_LATEST_FORMAT))); - latestLabel.showDataFetchResult(DataFetchResult.getSubResult(result, r -> TimelineSummary.formatDate(r.getMaxDate(), EARLIEST_LATEST_FORMAT))); - last30DaysChart.showDataFetchResult(DataFetchResult.getSubResult(result, r -> parseChartData(r.getMostRecentDaysActivity(), false))); - - if (result != null - && result.getResultType() == DataFetchResult.ResultType.SUCCESS - && result.getData() != null) { - - synchronized (this.timelineBtnLock) { - this.curTimelineData = result.getData(); - this.viewInTimelineBtn.setEnabled(true); - } - } else { - synchronized (this.timelineBtnLock) { - this.viewInTimelineBtn.setEnabled(false); - } - } - } - - /** - * Action that occurs when 'View in Timeline' button is pressed. - */ - private void openFilteredChart() { - DataSource dataSource = null; - Date minDate = null; - Date maxDate = null; - - // get date from current timelineData if that data exists. - synchronized (this.timelineBtnLock) { - if (curTimelineData == null) { - return; - } - - dataSource = curTimelineData.getDataSource(); - if (CollectionUtils.isNotEmpty(curTimelineData.getMostRecentDaysActivity())) { - minDate = curTimelineData.getMostRecentDaysActivity().get(0).getDay(); - maxDate = curTimelineData.getMostRecentDaysActivity().get(curTimelineData.getMostRecentDaysActivity().size() - 1).getDay(); - // set outer bound to end of day instead of beginning - if (maxDate != null) { - maxDate = new Date(maxDate.getTime() + 1000 * 60 * 60 * 24); - } - } - } - - openFilteredChart(dataSource, minDate, maxDate); - } - - /** - * Action that occurs when 'View in Timeline' button is pressed. - * - * @param dataSource The data source to filter to. - * @param minDate The min date for the zoom of the window. - * @param maxDate The max date for the zoom of the window. - */ - private void openFilteredChart(DataSource dataSource, Date minDate, Date maxDate) { - OpenTimelineAction openTimelineAction = CallableSystemAction.get(OpenTimelineAction.class); - if (openTimelineAction == null) { - logger.log(Level.WARNING, "No OpenTimelineAction provided by CallableSystemAction; taking no redirect action."); - } - - // notify dialog (if in dialog) should close. - TimelinePanel.this.notifyParentClose(); - - Interval timeSpan = null; - - try { - final TimeLineController controller = TimeLineModule.getController(); - - if (dataSource != null) { - controller.pushFilters(TimelineSummary.getDataSourceFilterState(dataSource)); - } - - if (minDate != null && maxDate != null) { - timeSpan = new Interval(new DateTime(minDate), new DateTime(maxDate)); - } - } catch (NoCurrentCaseException | TskCoreException ex) { - logger.log(Level.WARNING, "Unable to view time range in Timeline view", ex); - } - - try { - openTimelineAction.showTimeline(timeSpan); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "An unexpected exception occurred while opening the timeline.", ex); - } - } - - @Override - protected void fetchInformation(DataSource dataSource) { - fetchInformation(dataFetchComponents, dataSource); - } - - @Override - protected void onNewDataSource(DataSource dataSource) { - onNewDataSource(dataFetchComponents, loadableComponents, dataSource); - } - - @Override - public void close() { - ingestRunningLabel.unregister(); - super.close(); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - javax.swing.JScrollPane mainScrollPane = new javax.swing.JScrollPane(); - javax.swing.JPanel mainContentPanel = new javax.swing.JPanel(); - javax.swing.JPanel ingestRunningPanel = ingestRunningLabel; - javax.swing.JLabel activityRangeLabel = new javax.swing.JLabel(); - javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); - javax.swing.JPanel earliestLabelPanel = earliestLabel; - javax.swing.JPanel latestLabelPanel = latestLabel; - javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); - javax.swing.JPanel last30DaysPanel = last30DaysChart; - viewInTimelineBtn = new javax.swing.JButton(); - javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767)); - - mainContentPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10)); - mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS)); - - ingestRunningPanel.setAlignmentX(0.0F); - ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 25)); - ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 25)); - ingestRunningPanel.setPreferredSize(new java.awt.Dimension(10, 25)); - mainContentPanel.add(ingestRunningPanel); - - activityRangeLabel.setFont(new java.awt.Font("Segoe UI", 1, 12)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(activityRangeLabel, org.openide.util.NbBundle.getMessage(TimelinePanel.class, "TimelinePanel.activityRangeLabel.text")); // NOI18N - mainContentPanel.add(activityRangeLabel); - activityRangeLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(TimelinePanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N - - filler1.setAlignmentX(0.0F); - mainContentPanel.add(filler1); - - earliestLabelPanel.setAlignmentX(0.0F); - earliestLabelPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); - earliestLabelPanel.setMinimumSize(new java.awt.Dimension(100, 20)); - earliestLabelPanel.setPreferredSize(new java.awt.Dimension(100, 20)); - mainContentPanel.add(earliestLabelPanel); - - latestLabelPanel.setAlignmentX(0.0F); - latestLabelPanel.setMaximumSize(new java.awt.Dimension(32767, 20)); - latestLabelPanel.setMinimumSize(new java.awt.Dimension(100, 20)); - latestLabelPanel.setPreferredSize(new java.awt.Dimension(100, 20)); - mainContentPanel.add(latestLabelPanel); - - filler2.setAlignmentX(0.0F); - mainContentPanel.add(filler2); - - last30DaysPanel.setAlignmentX(0.0F); - last30DaysPanel.setMaximumSize(new java.awt.Dimension(600, 300)); - last30DaysPanel.setMinimumSize(new java.awt.Dimension(600, 300)); - last30DaysPanel.setPreferredSize(new java.awt.Dimension(600, 300)); - last30DaysPanel.setVerifyInputWhenFocusTarget(false); - mainContentPanel.add(last30DaysPanel); - - org.openide.awt.Mnemonics.setLocalizedText(viewInTimelineBtn, org.openide.util.NbBundle.getMessage(TimelinePanel.class, "TimelinePanel.viewInTimelineBtn.text")); // NOI18N - viewInTimelineBtn.setEnabled(false); - viewInTimelineBtn.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - viewInTimelineBtnActionPerformed(evt); - } - }); - mainContentPanel.add(viewInTimelineBtn); - - filler5.setAlignmentX(0.0F); - mainContentPanel.add(filler5); - - mainScrollPane.setViewportView(mainContentPanel); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE) - ); - }// //GEN-END:initComponents - - private void viewInTimelineBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewInTimelineBtnActionPerformed - openFilteredChart(); - }//GEN-LAST:event_viewInTimelineBtnActionPerformed - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton viewInTimelineBtn; - // End of variables declaration//GEN-END:variables - -} From a9f09cd35b0a2aec2505c38733f5da966c986c02 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 19 Aug 2021 14:00:06 -0400 Subject: [PATCH 44/76] 7877 fix tests with test SearchContext implementation --- .../search/DomainSearchCacheLoaderTest.java | 10 +- .../discovery/search/DomainSearchTest.java | 100 +++++++++--------- .../search/TestSearchContextImpl.java | 37 +++++++ 3 files changed, 93 insertions(+), 54 deletions(-) create mode 100644 Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/TestSearchContextImpl.java diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java index 66a77cf617..32e1b2d657 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java @@ -48,11 +48,12 @@ public class DomainSearchCacheLoaderTest { SleuthkitCase caseDb = mock(SleuthkitCase.class); when(caseDb.getBlackboardArtifacts(TSK_WEB_CATEGORIZATION)).thenReturn(new ArrayList<>()); + //null checks are being performed on the context allowing the context argument to be null during the test. SearchKey key = new SearchKey(null, new ArrayList<>(), new DiscoveryAttributes.DataSourceAttribute(), Group.GroupSortingAlgorithm.BY_GROUP_NAME, ResultsSorter.SortingMethod.BY_DOMAIN_NAME, - caseDb, null); + caseDb, null, new TestSearchContextImpl(false)); DomainSearchCacheLoader loader = mock(DomainSearchCacheLoader.class); when(loader.getResultDomainsFromDatabase(key)).thenReturn(domains); @@ -88,7 +89,7 @@ public class DomainSearchCacheLoaderTest { new DiscoveryAttributes.NoGroupingAttribute(), Group.GroupSortingAlgorithm.BY_GROUP_NAME, ResultsSorter.SortingMethod.BY_DOMAIN_NAME, - caseDb, null); + caseDb, null, new TestSearchContextImpl(false)); DomainSearchCacheLoader loader = mock(DomainSearchCacheLoader.class); when(loader.getResultDomainsFromDatabase(key)).thenReturn(domains); @@ -121,7 +122,7 @@ public class DomainSearchCacheLoaderTest { new DiscoveryAttributes.NoGroupingAttribute(), Group.GroupSortingAlgorithm.BY_GROUP_NAME, ResultsSorter.SortingMethod.BY_DATA_SOURCE, - caseDb, null); + caseDb, null, new TestSearchContextImpl(false)); DomainSearchCacheLoader loader = mock(DomainSearchCacheLoader.class); when(loader.getResultDomainsFromDatabase(key)).thenReturn(domains); @@ -155,7 +156,7 @@ public class DomainSearchCacheLoaderTest { new DiscoveryAttributes.DataSourceAttribute(), Group.GroupSortingAlgorithm.BY_GROUP_SIZE, ResultsSorter.SortingMethod.BY_DOMAIN_NAME, - caseDb, null); + caseDb, null, new TestSearchContextImpl(false)); DomainSearchCacheLoader loader = mock(DomainSearchCacheLoader.class); when(loader.getResultDomainsFromDatabase(key)).thenReturn(domains); @@ -173,4 +174,5 @@ public class DomainSearchCacheLoaderTest { } } } + } diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java index 7dcffed663..31f4737e6b 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -46,11 +46,11 @@ public class DomainSearchTest { ); } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); - Map sizes = domainSearch.getGroupSizes(null, - new ArrayList<>(), null, null, null, null, null); + Map sizes = domainSearch.getGroupSizes(null, + new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false)); assertEquals(4, sizes.get(groupOne).longValue()); } @@ -81,11 +81,11 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); - Map sizes = domainSearch.getGroupSizes(null, - new ArrayList<>(), null, null, null, null, null); + Map sizes = domainSearch.getGroupSizes(null, + new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false)); assertEquals(4, sizes.get(groupOne).longValue()); assertEquals(3, sizes.get(groupTwo).longValue()); assertEquals(1, sizes.get(groupThree).longValue()); @@ -95,11 +95,11 @@ public class DomainSearchTest { public void groupSizes_EmptyGroup_ShouldBeSizeZero() throws DiscoveryException { DomainSearchCache cache = mock(DomainSearchCache.class); - when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(new HashMap<>()); + when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(new HashMap<>()); DomainSearch domainSearch = new DomainSearch(cache, null, null); - Map sizes = domainSearch.getGroupSizes(null, - new ArrayList<>(), null, null, null, null, null); + Map sizes = domainSearch.getGroupSizes(null, + new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false)); assertEquals(0, sizes.size()); } @@ -120,17 +120,17 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); - List firstPage = domainSearch.getDomainsInGroup(null, - new ArrayList<>(), null, null, null, groupOne, 0, 3, null, null); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, 0, 3, null, null, new TestSearchContextImpl(false)); assertEquals(3, firstPage.size()); for (int i = 0; i < firstPage.size(); i++) { assertEquals(domains.get(i), firstPage.get(i)); } } - + @Test public void getDomains_SingleGroupOverSizedPage_ShouldContainAllDomains() throws DiscoveryException { DomainSearchCache cache = mock(DomainSearchCache.class); @@ -148,17 +148,17 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); - List firstPage = domainSearch.getDomainsInGroup(null, - new ArrayList<>(), null, null, null, groupOne, 0, 100, null, null); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, 0, 100, null, null, new TestSearchContextImpl(false)); assertEquals(4, firstPage.size()); for (int i = 0; i < firstPage.size(); i++) { assertEquals(domains.get(i), firstPage.get(i)); } } - + @Test public void getDomains_SingleGroupHalfPage_ShouldContainHalfDomains() throws DiscoveryException { DomainSearchCache cache = mock(DomainSearchCache.class); @@ -176,18 +176,18 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); - List firstPage = domainSearch.getDomainsInGroup(null, - new ArrayList<>(), null, null, null, groupOne, 0, 2, null, null); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, 0, 2, null, null, new TestSearchContextImpl(false)); assertEquals(2, firstPage.size()); for (int i = 0; i < firstPage.size(); i++) { assertEquals(domains.get(i), firstPage.get(i)); } } - - @Test + + @Test public void getDomains_SingleGroupLastPageLastDomain_ShouldContainLastDomain() throws DiscoveryException { DomainSearchCache cache = mock(DomainSearchCache.class); @@ -204,15 +204,15 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); - List firstPage = domainSearch.getDomainsInGroup(null, - new ArrayList<>(), null, null, null, groupOne, 3, 1, null, null); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, 3, 1, null, null, new TestSearchContextImpl(false)); assertEquals(1, firstPage.size()); assertEquals(domains.get(domains.size() - 1), firstPage.get(0)); } - + @Test public void getDomains_SingleGroupOversizedOffset_ShouldContainNoDomains() throws DiscoveryException { DomainSearchCache cache = mock(DomainSearchCache.class); @@ -230,14 +230,14 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); - List firstPage = domainSearch.getDomainsInGroup(null, - new ArrayList<>(), null, null, null, groupOne, 20, 5, null, null); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, 20, 5, null, null, new TestSearchContextImpl(false)); assertEquals(0, firstPage.size()); } - + @Test public void getDomains_SingleGroupZeroSizedPage_ShouldContainNoDomains() throws DiscoveryException { DomainSearchCache cache = mock(DomainSearchCache.class); @@ -255,14 +255,14 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); - List firstPage = domainSearch.getDomainsInGroup(null, - new ArrayList<>(), null, null, null, groupOne, 0, 0, null, null); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, 0, 0, null, null, new TestSearchContextImpl(false)); assertEquals(0, firstPage.size()); } - + @Test public void getDomains_MultipleGroupsFullPage_ShouldContainAllDomainsInGroup() throws DiscoveryException { DomainSearchCache cache = mock(DomainSearchCache.class); @@ -290,14 +290,14 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); - List firstPage = domainSearch.getDomainsInGroup(null, - new ArrayList<>(), null, null, null, groupOne, 0, 3, null, null); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, 0, 3, null, null, new TestSearchContextImpl(false)); assertEquals(3, firstPage.size()); } - + @Test public void getDomains_MultipleGroupsHalfPage_ShouldContainHalfDomainsInGroup() throws DiscoveryException { DomainSearchCache cache = mock(DomainSearchCache.class); @@ -325,17 +325,17 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); - List firstPage = domainSearch.getDomainsInGroup(null, - new ArrayList<>(), null, null, null, groupTwo, 1, 2, null, null); + List firstPage = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupTwo, 1, 2, null, null, new TestSearchContextImpl(false)); assertEquals(2, firstPage.size()); for (int i = 0; i < firstPage.size(); i++) { assertEquals(dummyData.get(groupTwo).get(i + 1), firstPage.get(i)); } } - + @Test public void getDomains_SingleGroupSimulatedPaging_ShouldPageThroughAllDomains() throws DiscoveryException { DomainSearchCache cache = mock(DomainSearchCache.class); @@ -357,20 +357,20 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null)).thenReturn(dummyData); + when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); - + int start = 0; int size = 2; while (start + size <= domains.size()) { - List page = domainSearch.getDomainsInGroup(null, - new ArrayList<>(), null, null, null, groupOne, start, size, null, null); + List page = domainSearch.getDomainsInGroup(null, + new ArrayList<>(), null, null, null, groupOne, start, size, null, null, new TestSearchContextImpl(false)); assertEquals(2, page.size()); - for(int i = 0; i < page.size(); i++) { + for (int i = 0; i < page.size(); i++) { assertEquals(domains.get(start + i), page.get(i)); } - + start += size; } } @@ -379,7 +379,7 @@ public class DomainSearchTest { private final String name; - public DummyKey(String name) { + DummyKey(String name) { this.name = name; } diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/TestSearchContextImpl.java b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/TestSearchContextImpl.java new file mode 100644 index 0000000000..838988e9ee --- /dev/null +++ b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/TestSearchContextImpl.java @@ -0,0 +1,37 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 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.discovery.search; + +/** + * Implementation of SearchContext for testing to ensure NPEs are not thrown and + * the context indicates the expected cancellation status. + */ +public class TestSearchContextImpl implements SearchContext { + + private final boolean isCancelled; + + TestSearchContextImpl(boolean hasBeenCancelled) { + isCancelled = hasBeenCancelled; + } + + @Override + public boolean searchIsCancelled() { + return isCancelled; + } +} From e2930d877608a5868ed85c0a903ba8ee1cbedcf8 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 19 Aug 2021 14:01:32 -0400 Subject: [PATCH 45/76] 7877 added comments and a few additional cancelation checks --- .../discovery/search/AbstractFilter.java | 4 +- .../discovery/search/DiscoveryAttributes.java | 104 ++++++++++++++++-- .../discovery/search/DiscoveryKeyUtils.java | 7 ++ .../discovery/search/DomainSearch.java | 2 +- .../discovery/search/SearchFiltering.java | 4 +- 5 files changed, 106 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java index 3fc2b33966..7980346730 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java @@ -1,7 +1,7 @@ /* * Autopsy * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -54,6 +54,8 @@ public abstract class AbstractFilter { * @param caseDb The case database * @param centralRepoDb The central repo database. Can be null if the * filter does not require it. + * @param context The SearchContext the search which is applying this + * filter is being performed from. * * @return The list of results that match this filter (and any that came * before it) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index 3f44b796f9..1b9a5c1a9a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -78,8 +78,12 @@ public class DiscoveryAttributes { * @param caseDb The case database. * @param centralRepoDb The central repository database. Can be null if * not needed. + * @param context The SearchContext the search which is applying + * this filter is being performed from. * * @throws DiscoveryException + * @throws SearchCancellationException - Thrown when the user has + * cancelled the search. */ public void addAttributeToResults(List results, SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { // Default is to do nothing @@ -175,6 +179,17 @@ public class DiscoveryAttributes { * Loads all TSK_WEB_CATEGORY artifacts and maps the domain attribute to * the category name attribute. Each ResultDomain is then parsed and * matched against this map of values. + * + * @param caseDb The case database. + * @param context The SearchContext the search which is applying this + * filter is being performed from. + * + * @return + * + * @throws TskCoreException + * @throws InterruptedException + * @throws SearchCancellationException - Thrown when the user has + * cancelled the search. */ private Map> getDomainsWithWebCategories(SleuthkitCase caseDb, SearchContext context) throws TskCoreException, InterruptedException, SearchCancellationException { Map> domainToCategory = new HashMap<>(); @@ -287,6 +302,20 @@ public class DiscoveryAttributes { * this map, all domain instances that represent google.com can be updated * after one simple lookup. */ + /** + * + * @param domainsBatch The list of ResultDomains to organize. + * @param attributeType The type of correlation attribute being organized. + * @param context The SearchContext the search which is applying this + * filter is being performed from. + * + * @return resultDomainTable - A map of the normalized domain name to the + * list of ResultDomain objects which are part of that normalized + * domain. + * + * @throws SearchCancellationException - Thrown when the user has cancelled + * the search. + */ private static Map> organizeByValue(List domainsBatch, CorrelationAttributeInstance.Type attributeType, SearchContext context) throws SearchCancellationException { final Map> resultDomainTable = new HashMap<>(); for (ResultDomain domainInstance : domainsBatch) { @@ -340,6 +369,21 @@ public class DiscoveryAttributes { } } + /** + * + * Helper method to batch the domain results and check for notability. + * + * @param results The results which are being checked for previously + * being notable in the CR. + * @param centralRepo The central repository being used to check for + * notability. + * @param context The SearchContext the search which is applying + * this filter is being performed from. + * + * @throws DiscoveryException + * @throws SearchCancellationException - Thrown when the user has + * cancelled the search. + */ private void processFilesWithCr(List results, CentralRepository centralRepo, SearchContext context) throws DiscoveryException, SearchCancellationException { List domainsBatch = new ArrayList<>(); @@ -359,6 +403,21 @@ public class DiscoveryAttributes { queryPreviouslyNotable(domainsBatch, centralRepo, context); } + /** + * Helper method to check a batch of domains for notability. + * + * + * @param domainsBatch The list of ResultDomains to check for + * notability. + * @param centralRepo The central repository being used to check for + * notability. + * @param context The SearchContext the search which is applying + * this filter is being performed from. + * + * @throws DiscoveryException + * @throws SearchCancellationException - Thrown when the user has + * cancelled the search. + */ private void queryPreviouslyNotable(List domainsBatch, CentralRepository centralRepo, SearchContext context) throws DiscoveryException, SearchCancellationException { if (domainsBatch.isEmpty()) { return; @@ -368,7 +427,9 @@ public class DiscoveryAttributes { final CorrelationAttributeInstance.Type attributeType = centralRepo.getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID); final Map> resultDomainTable = organizeByValue(domainsBatch, attributeType, context); final String values = createCSV(resultDomainTable.keySet()); - + if (context.searchIsCancelled()) { + throw new SearchCancellationException("Search was cancelled while checking for previously notable domains."); + } final String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(attributeType); final String domainFrequencyQuery = " value AS domain_name " + "FROM " + tableName + " " @@ -451,9 +512,16 @@ public class DiscoveryAttributes { * Private helper method for adding Frequency attribute when CR is * enabled. * - * @param files The list of ResultFiles to caluclate frequency - * for. - * @param centralRepoDb The central repository currently in use. + * @param results The results which are having their frequency + * checked. + * @param centralRepoDb The central repository being used to check + * frequency. + * @param context The SearchContext the search which is applying + * this filter is being performed from. + * + * @throws DiscoveryException + * @throws SearchCancellationException - Thrown when the user has + * cancelled the search. */ private void processResultFilesForCR(List results, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { @@ -479,7 +547,7 @@ public class DiscoveryAttributes { } if (hashesToLookUp.size() >= BATCH_SIZE) { - computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); + computeFrequency(hashesToLookUp, currentFiles, centralRepoDb, context); hashesToLookUp.clear(); currentFiles.clear(); @@ -495,7 +563,7 @@ public class DiscoveryAttributes { } queryDomainFrequency(domainsToQuery, centralRepoDb, context); - computeFrequency(hashesToLookUp, currentFiles, centralRepoDb); + computeFrequency(hashesToLookUp, currentFiles, centralRepoDb, context); } } @@ -503,9 +571,14 @@ public class DiscoveryAttributes { * Query to get the frequency of a domain. * * @param domainsToQuery List of domains to check the frequency of. - * @param centralRepository The central repository to query. + * @param centralRepository The central repository being used to check + * frequency. + * @param context The SearchContext the search which is applying + * this filter is being performed from. * * @throws DiscoveryException + * @throws SearchCancellationException - Thrown when the user has cancelled + * the search. */ private static void queryDomainFrequency(List domainsToQuery, CentralRepository centralRepository, SearchContext context) throws DiscoveryException, SearchCancellationException { if (domainsToQuery.isEmpty()) { @@ -524,8 +597,11 @@ public class DiscoveryAttributes { + ")) AS foo GROUP BY value"; final DomainFrequencyCallback frequencyCallback = new DomainFrequencyCallback(resultDomainTable); - centralRepository.processSelectClause(domainFrequencyQuery, frequencyCallback); + centralRepository.processSelectClause(domainFrequencyQuery, frequencyCallback); + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while Domain frequency was being queried with the CR."); + } if (frequencyCallback.getCause() != null) { throw frequencyCallback.getCause(); } @@ -1023,14 +1099,20 @@ public class DiscoveryAttributes { } /** + * * Computes the CR frequency of all the given hashes and updates the list of * files. * * @param hashesToLookUp Hashes to find the frequency of. * @param currentFiles List of files to update with frequencies. * @param centralRepoDb The central repository being used. + * @param context The SearchContext the search which is applying this + * filter is being performed from. + * + * @throws SearchCancellationException - Thrown when the user has cancelled + * the search. */ - private static void computeFrequency(Set hashesToLookUp, List currentFiles, CentralRepository centralRepoDb) { + private static void computeFrequency(Set hashesToLookUp, List currentFiles, CentralRepository centralRepoDb, SearchContext context) throws SearchCancellationException { if (hashesToLookUp.isEmpty()) { return; @@ -1050,7 +1132,9 @@ public class DiscoveryAttributes { FrequencyCallback callback = new FrequencyCallback(currentFiles); centralRepoDb.processSelectClause(selectClause, callback); - + if (context.searchIsCancelled()) { + throw new SearchCancellationException("The search was cancelled while Domain frequency was being queried with the CR."); + } } catch (CentralRepoException ex) { logger.log(Level.WARNING, "Error getting frequency counts from Central Repository", ex); // NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index 7d2a482afb..cf2ae8a425 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -113,6 +113,7 @@ public class DiscoveryKeyUtils { ResultsSorter.SortingMethod sortingMethod) { this(userName, filters, groupAttributeType, groupSortingType, sortingMethod, null, null, null); + //this constructor should only be used putting things directly into a map or getting if present since casedb, cr, and search context will be null } @Override @@ -146,6 +147,12 @@ public class DiscoveryKeyUtils { return hash; } + /** + * Get the SearchContext for the search this key is being used in. + * + * @return The SearchContext the search key is being used in. + * + */ SearchContext getContext() { return context; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java index 41f11c6fa8..35c993952f 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java @@ -134,7 +134,7 @@ public class DomainSearch { Group.GroupSortingAlgorithm groupSortingType, ResultsSorter.SortingMethod domainSortingMethod, GroupKey groupKey, int startingEntry, int numberOfEntries, - SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { + SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { final Map> searchResults = searchCache.get( userName, filters, groupAttributeType, groupSortingType, diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index 9eae2b1513..309547f901 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -83,9 +83,7 @@ public class SearchFiltering { throw new DiscoveryException("Selected filters do not include a case database query"); } if (context.searchIsCancelled()) { - if (context.searchIsCancelled()) { - throw new SearchCancellationException("The search was cancelled before result list could be retrieved."); - } + throw new SearchCancellationException("The search was cancelled before result list could be retrieved."); } try { return getResultList(filters, combinedQuery, caseDb, centralRepoDb, context); From 5be0543ebb772c1eb22f2053db8a44df251c7d4f Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 19 Aug 2021 14:46:51 -0400 Subject: [PATCH 46/76] 7877 clean up comments and dates --- .../discovery/search/AbstractFilter.java | 2 ++ .../discovery/search/DiscoveryAttributes.java | 6 ++-- .../discovery/search/DiscoveryKeyUtils.java | 9 +++++- .../discovery/search/DomainSearch.java | 3 ++ .../discovery/search/DomainSearchCache.java | 6 +++- .../autopsy/discovery/search/FileSearch.java | 20 +++++++++++++ .../search/SearchCancellationException.java | 9 ++++++ .../discovery/search/SearchContext.java | 11 ++++++- .../discovery/search/SearchFiltering.java | 12 +++++++- .../autopsy/discovery/ui/DiscoveryDialog.java | 4 --- .../autopsy/discovery/ui/PageWorker.java | 4 +-- .../autopsy/discovery/ui/SearchWorker.java | 1 - .../ui/SwingWorkerSearchContext.java | 30 ++++++++++++------- .../search/DomainSearchCacheLoaderTest.java | 3 +- 14 files changed, 92 insertions(+), 28 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java b/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java index 7980346730..eed8a106f4 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/AbstractFilter.java @@ -61,6 +61,8 @@ public abstract class AbstractFilter { * before it) * * @throws DiscoveryException + * @throws SearchCancellationException Thrown when the user has cancelled + * the search. */ public List applyAlternateFilter(List currentResults, SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java index 1b9a5c1a9a..c1436ff890 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryAttributes.java @@ -184,7 +184,8 @@ public class DiscoveryAttributes { * @param context The SearchContext the search which is applying this * filter is being performed from. * - * @return + * @return domainToCategory - A map of the domain names to the category + * name attribute they are classified as. * * @throws TskCoreException * @throws InterruptedException @@ -301,8 +302,6 @@ public class DiscoveryAttributes { * Example: query for notable status of google.com. Result: notable With * this map, all domain instances that represent google.com can be updated * after one simple lookup. - */ - /** * * @param domainsBatch The list of ResultDomains to organize. * @param attributeType The type of correlation attribute being organized. @@ -370,7 +369,6 @@ public class DiscoveryAttributes { } /** - * * Helper method to batch the domain results and check for notability. * * @param results The results which are being checked for previously diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java index cf2ae8a425..ca1828d02c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DiscoveryKeyUtils.java @@ -152,8 +152,15 @@ public class DiscoveryKeyUtils { * * @return The SearchContext the search key is being used in. * + * @throws DiscoveryException Thrown when the key being used has a null + * context indicating it was not created with + * knowledge of the case or central + * repository databases. */ - SearchContext getContext() { + SearchContext getContext() throws DiscoveryException { + if (context == null) { + throw new DiscoveryException("The key in use was created without a context and does not support retrieving information from the databases."); + } return context; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java index 35c993952f..0557808758 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearch.java @@ -78,10 +78,13 @@ public class DomainSearch { * @param caseDb The case database. * @param centralRepoDb The central repository database. Can be null * if not needed. + * @param context The SearchContext the search is being performed from. * * @return A LinkedHashMap grouped and sorted according to the parameters. * * @throws DiscoveryException + * @throws SearchCancellationException - Thrown when the user has cancelled + * the search. */ public Map getGroupSizes(String userName, List filters, diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java index 38def5e4c0..ee677a6972 100755 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCache.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -55,10 +55,14 @@ class DomainSearchCache { * @param caseDb The case database. * @param centralRepoDb The central repository database. Can be null if * not needed. + * @param context The SearchContext the search is being performed + * from. * * @return Domain search results matching the given parameters. * * @throws DiscoveryException + * @throws SearchCancellationException - Thrown when the user has cancelled + * the search. */ Map> get(String userName, List filters, diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java index bdc3e4f2fc..9b827180c2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/FileSearch.java @@ -62,10 +62,14 @@ public class FileSearch { * @param caseDb The case database * @param centralRepoDb The central repository database. Can be null if * not needed. + * @param context The SearchContext the search is being performed + * from. * * @return The raw search results * * @throws DiscoveryException + * @throws SearchCancellationException - Thrown when the user has cancelled + * the search. */ static SearchResults runFileSearchDebug(String userName, List filters, @@ -114,10 +118,14 @@ public class FileSearch { * @param caseDb The case database * @param centralRepoDb The central repository database. Can be null if * not needed. + * @param context The SearchContext the search is being performed + * from. * * @return A LinkedHashMap grouped and sorted according to the parameters * * @throws DiscoveryException + * @throws SearchCancellationException - Thrown when the user has cancelled + * the search. */ public static Map getGroupSizes(String userName, List filters, @@ -154,10 +162,14 @@ public class FileSearch { * @param caseDb The case database * @param centralRepoDb The central repository database. Can be null if * not needed. + * @param context The SearchContext the search is being performed + * from. * * @return A LinkedHashMap grouped and sorted according to the parameters * * @throws DiscoveryException + * @throws SearchCancellationException - Thrown when the user has cancelled + * the search. */ public static List getFilesInGroup(String userName, List filters, @@ -249,10 +261,14 @@ public class FileSearch { * @param caseDb The case database * @param centralRepoDb The central repository database. Can be null if * not needed. + * @param context The SearchContext the search is being performed + * from. * * @return A LinkedHashMap grouped and sorted according to the parameters * * @throws DiscoveryException + * @throws SearchCancellationException - Thrown when the user has cancelled + * the search. */ public static Map> runFileSearch(String userName, List filters, @@ -297,8 +313,12 @@ public class FileSearch { * @param caseDb The case database * @param centralRepoDb The central repository database. Can be null if not * needed. + * @param context The SearchContext the search is being performed + * from. * * @throws DiscoveryException + * @throws SearchCancellationException - Thrown when the user has cancelled + * the search. */ private static void addAttributes(List attrs, List results, SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchCancellationException.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchCancellationException.java index f268e20518..2587777382 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchCancellationException.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchCancellationException.java @@ -20,10 +20,19 @@ package org.sleuthkit.autopsy.discovery.search; import java.util.concurrent.CancellationException; +/** + * Exception to be thrown when the search has been intentionally cancelled to + * provide information on where the code was when the cancellation took place. + */ public class SearchCancellationException extends CancellationException { private static final long serialVersionUID = 1L; + /** + * Construct a new SearchCancellationException with the specified message. + * + * @param message The text to use as the message for the exception. + */ SearchCancellationException(String message) { super(message); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchContext.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchContext.java index effde3d353..e0ce318b58 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchContext.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchContext.java @@ -18,7 +18,16 @@ */ package org.sleuthkit.autopsy.discovery.search; +/** + * Interface for providing feedback on if a search has been cancelled. + * + */ public interface SearchContext { - + + /** + * Returns true if the search has been cancelled, false otherwise. + * + * @return True if the search has been cancelled, false otherwise. + */ boolean searchIsCancelled(); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java index 309547f901..eba1402ccf 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/search/SearchFiltering.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019-2020 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -60,8 +60,14 @@ public class SearchFiltering { * @param caseDb The case database. * @param centralRepoDb The central repo. Can be null as long as no filters * need it. + * @param context The SearchContext the search is being performed + * from. * * @return List of Results from the search performed. + * + * @throws DiscoveryException + * @throws SearchCancellationException - Thrown when the user has cancelled + * the search. */ static List runQueries(List filters, SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws DiscoveryException, SearchCancellationException { if (caseDb == null) { @@ -100,11 +106,15 @@ public class SearchFiltering { * @param caseDb The case database. * @param centralRepoDb The central repo. Can be null as long as no filters * need it. + * @param context The SearchContext the search is being performed + * from. * * @return An ArrayList of Results returned by the query. * * @throws TskCoreException * @throws DiscoveryException + * @throws SearchCancellationException - Thrown when the user has cancelled + * the search. */ private static List getResultList(List filters, String combinedQuery, SleuthkitCase caseDb, CentralRepository centralRepoDb, SearchContext context) throws TskCoreException, DiscoveryException, SearchCancellationException { // Get all matching abstract files diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java index 74baf390c6..63bbf673a8 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DiscoveryDialog.java @@ -89,7 +89,6 @@ final class DiscoveryDialog extends javax.swing.JDialog { if (discDialog == null) { discDialog = new DiscoveryDialog(); } - if (shouldUpdate) { discDialog.updateSearchSettings(); shouldUpdate = false; @@ -618,7 +617,6 @@ final class DiscoveryDialog extends javax.swing.JDialog { } searchWorker = new SearchWorker(centralRepoDb, type, filters, groupingAttr, groupSortAlgorithm, fileSort); searchWorker.execute(); - tc.toFront(); tc.requestActive(); }//GEN-LAST:event_searchButtonActionPerformed @@ -752,7 +750,6 @@ final class DiscoveryDialog extends javax.swing.JDialog { || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) { shouldUpdate = shouldUpdateFilters(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), eventData, interestingItems); } - } } catch (NoCurrentCaseException notUsed) { // Case is closed, do nothing. @@ -794,5 +791,4 @@ final class DiscoveryDialog extends javax.swing.JDialog { return false; } } - } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java index e5e23fe4aa..8718f60a74 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/PageWorker.java @@ -1,7 +1,7 @@ /* * Autopsy * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -110,7 +110,7 @@ final class PageWorker extends SwingWorker { logger.log(Level.SEVERE, "Error running file search test", ex); cancel(true); } catch (SearchCancellationException ex) { - //The does not explicitly have a way to cancell the loading of a page + //The user does not explicitly have a way to cancel the loading of a page //but they could have cancelled the search during the loading of the first page //So this may or may not be an issue depending on when this occurred. logger.log(Level.WARNING, "Search was cancelled while retrieving data for results page with starting entry: " + startingEntry, ex); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java index e507a8082b..6ba7a75fd2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SearchWorker.java @@ -100,7 +100,6 @@ final class SearchWorker extends SwingWorker { //so would not be a problem but we might be curious what was being done when it was cancelled logger.log(Level.INFO, "Discovery search was cancelled.", ex); } - return null; } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/SwingWorkerSearchContext.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/SwingWorkerSearchContext.java index 5af00e3f77..2d51d755f9 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/SwingWorkerSearchContext.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/SwingWorkerSearchContext.java @@ -21,17 +21,25 @@ package org.sleuthkit.autopsy.discovery.ui; import javax.swing.SwingWorker; import org.sleuthkit.autopsy.discovery.search.SearchContext; +/** + * Implementation of SearchContext for searches being performed in the + * background thread of a SwingWorker. + */ +class SwingWorkerSearchContext implements SearchContext { - class SwingWorkerSearchContext implements SearchContext { + private final SwingWorker searchWorker; - private final SwingWorker searchWorker; - - SwingWorkerSearchContext(SwingWorker worker) { - searchWorker = worker; - } - - @Override - public boolean searchIsCancelled() { - return searchWorker.isCancelled(); - } + /** + * Construct a new SwingWorkerSearchContext. + * + * @param worker The SwingWorker the search is being performed in. + */ + SwingWorkerSearchContext(SwingWorker worker) { + searchWorker = worker; } + + @Override + public boolean searchIsCancelled() { + return searchWorker.isCancelled(); + } +} diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java index 32e1b2d657..b9eb3aeefc 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchCacheLoaderTest.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -48,7 +48,6 @@ public class DomainSearchCacheLoaderTest { SleuthkitCase caseDb = mock(SleuthkitCase.class); when(caseDb.getBlackboardArtifacts(TSK_WEB_CATEGORIZATION)).thenReturn(new ArrayList<>()); - //null checks are being performed on the context allowing the context argument to be null during the test. SearchKey key = new SearchKey(null, new ArrayList<>(), new DiscoveryAttributes.DataSourceAttribute(), Group.GroupSortingAlgorithm.BY_GROUP_NAME, From d67a050c405c7cf6737422b02fcb1f55764824f0 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 19 Aug 2021 16:41:17 -0400 Subject: [PATCH 47/76] 7877 fix tests to compare arguments correctly --- .../discovery/search/DomainSearchTest.java | 25 +++++++++---------- .../search/TestSearchContextImpl.java | 2 +- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java index 31f4737e6b..2037bbf8b3 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/DomainSearchTest.java @@ -24,7 +24,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Test; - import static org.mockito.Mockito.*; import static org.junit.Assert.*; import org.sleuthkit.autopsy.discovery.search.DiscoveryKeyUtils.GroupKey; @@ -46,7 +45,7 @@ public class DomainSearchTest { ); } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); + when(cache.get(isNull(), eq(new ArrayList<>()), isNull(), isNull(), isNull(), isNull(), isNull(), any(SearchContext.class))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); Map sizes = domainSearch.getGroupSizes(null, @@ -81,7 +80,7 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); + when(cache.get(isNull(), eq(new ArrayList<>()), isNull(), isNull(), isNull(), isNull(), isNull(), any(SearchContext.class))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); Map sizes = domainSearch.getGroupSizes(null, @@ -95,7 +94,7 @@ public class DomainSearchTest { public void groupSizes_EmptyGroup_ShouldBeSizeZero() throws DiscoveryException { DomainSearchCache cache = mock(DomainSearchCache.class); - when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(new HashMap<>()); + when(cache.get(isNull(), eq(new ArrayList<>()), isNull(), isNull(), isNull(), isNull(), isNull(), any(SearchContext.class))).thenReturn(new HashMap<>()); DomainSearch domainSearch = new DomainSearch(cache, null, null); Map sizes = domainSearch.getGroupSizes(null, @@ -120,7 +119,7 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); + when(cache.get(isNull(), eq(new ArrayList<>()), isNull(), isNull(), isNull(), isNull(), isNull(), any(SearchContext.class))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); List firstPage = domainSearch.getDomainsInGroup(null, @@ -148,7 +147,7 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); + when(cache.get(isNull(), eq(new ArrayList<>()), isNull(), isNull(), isNull(), isNull(), isNull(), any(SearchContext.class))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); List firstPage = domainSearch.getDomainsInGroup(null, @@ -176,7 +175,7 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); + when(cache.get(isNull(), eq(new ArrayList<>()), isNull(), isNull(), isNull(), isNull(), isNull(), any(SearchContext.class))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); List firstPage = domainSearch.getDomainsInGroup(null, @@ -204,7 +203,7 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); + when(cache.get(isNull(), eq(new ArrayList<>()), isNull(), isNull(), isNull(), isNull(), isNull(), any(SearchContext.class))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); List firstPage = domainSearch.getDomainsInGroup(null, @@ -230,7 +229,7 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); + when(cache.get(isNull(), eq(new ArrayList<>()), isNull(), isNull(), isNull(), isNull(), isNull(), any(SearchContext.class))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); List firstPage = domainSearch.getDomainsInGroup(null, @@ -255,7 +254,7 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); + when(cache.get(isNull(), eq(new ArrayList<>()), isNull(), isNull(), isNull(), isNull(), isNull(), any(SearchContext.class))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); List firstPage = domainSearch.getDomainsInGroup(null, @@ -290,7 +289,7 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); + when(cache.get(isNull(), eq(new ArrayList<>()), isNull(), isNull(), isNull(), isNull(), isNull(), any(SearchContext.class))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); List firstPage = domainSearch.getDomainsInGroup(null, @@ -325,7 +324,7 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); + when(cache.get(isNull(), eq(new ArrayList<>()), isNull(), isNull(), isNull(), isNull(), isNull(), any(SearchContext.class))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); List firstPage = domainSearch.getDomainsInGroup(null, @@ -357,7 +356,7 @@ public class DomainSearchTest { } }; - when(cache.get(null, new ArrayList<>(), null, null, null, null, null, new TestSearchContextImpl(false))).thenReturn(dummyData); + when(cache.get(isNull(), eq(new ArrayList<>()), isNull(), isNull(), isNull(), isNull(), isNull(), any(SearchContext.class))).thenReturn(dummyData); DomainSearch domainSearch = new DomainSearch(cache, null, null); diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/TestSearchContextImpl.java b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/TestSearchContextImpl.java index 838988e9ee..128038eeed 100644 --- a/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/TestSearchContextImpl.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/discovery/search/TestSearchContextImpl.java @@ -26,7 +26,7 @@ public class TestSearchContextImpl implements SearchContext { private final boolean isCancelled; - TestSearchContextImpl(boolean hasBeenCancelled) { + public TestSearchContextImpl(boolean hasBeenCancelled) { isCancelled = hasBeenCancelled; } From af68f025f09089a51e0231ed78d1ac6989d988a8 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 23 Aug 2021 12:36:43 -0400 Subject: [PATCH 48/76] Review feedback --- .../datamodel/Bundle_ja.properties | 3 + .../CaseDataSourcesSummary.java | 2 +- .../DataSourceLabeledValueCallback.java | 2 +- .../DataSourceSingleValueCallback.java | 2 +- .../datamodel/MimeTypeSummary.java | 151 ++++++++++++++++++ .../ui/AnalysisSummaryGetter.java | 2 +- .../ui/ContainerSummaryGetter.java | 2 +- .../ui/DataSourceBrowser.java | 1 + .../ui/GeolocationSummaryGetter.java | 3 +- .../ui/MimeTypeSummaryGetter.java | 47 +----- .../ui/PastCasesSummaryGetter.java | 8 +- .../ui/RecentFilesGetter.java | 2 +- .../ui/TimelineSummaryGetter.java | 2 +- .../datasourcesummary/ui/TypesPanel.java | 4 +- .../ui/TypesSummaryGetter.java | 2 +- .../ui/UserActivitySummaryGetter.java | 41 ----- .../datasourcesummaryexport/ExportTypes.java | 65 +------- 17 files changed, 179 insertions(+), 160 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle_ja.properties rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{ui => datamodel}/CaseDataSourcesSummary.java (99%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{ui => datamodel}/DataSourceLabeledValueCallback.java (97%) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{ui => datamodel}/DataSourceSingleValueCallback.java (97%) create mode 100755 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle_ja.properties new file mode 100755 index 0000000000..a8185f73ff --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/Bundle_ja.properties @@ -0,0 +1,3 @@ +#Mon Jun 14 12:23:19 UTC 2021 +DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=\u901a\u8a71\u8a18\u9332 +DataSourceUserActivitySummary_getRecentAccounts_emailMessage=\u30e1\u30fc\u30eb\u30e1\u30c3\u30bb\u30fc\u30b8 diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/CaseDataSourcesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/CaseDataSourcesSummary.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/CaseDataSourcesSummary.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/CaseDataSourcesSummary.java index 4181af5b8e..50e883e29a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/CaseDataSourcesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/CaseDataSourcesSummary.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.ui; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.util.Collections; import java.util.HashMap; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceLabeledValueCallback.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceLabeledValueCallback.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceLabeledValueCallback.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceLabeledValueCallback.java index cbb4b18e86..6c9c918667 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceLabeledValueCallback.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceLabeledValueCallback.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.ui; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.sql.ResultSet; import java.sql.SQLException; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSingleValueCallback.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceSingleValueCallback.java similarity index 97% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSingleValueCallback.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceSingleValueCallback.java index 901c3d9416..6b1ff205fa 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSingleValueCallback.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceSingleValueCallback.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.ui; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.sql.ResultSet; import java.sql.SQLException; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java new file mode 100755 index 0000000000..ced8e85d95 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java @@ -0,0 +1,151 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020-2021 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.datasourcesummary.datamodel; + +import java.sql.SQLException; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Wrapper class for converting org.sleuthkit.autopsy.contentutils.TypesSummary + * functionality into a DefaultArtifactUpdateGovernor used by TypesPanel tab. + */ +public class MimeTypeSummary { + + private final SleuthkitCaseProvider provider; + + /** + * Main constructor. + */ + public MimeTypeSummary() { + this(SleuthkitCaseProvider.DEFAULT); + } + + /** + * Main constructor. + * + * @param provider The means of obtaining a sleuthkit case. + */ + public MimeTypeSummary(SleuthkitCaseProvider provider) { + this.provider = provider; + } + + /** + * Get the number of files in the case database for the current data source + * which have the specified mimetypes. + * + * @param currentDataSource the data source which we are finding a file + * count + * + * @param setOfMimeTypes the set of mime types which we are finding the + * number of occurences of + * + * @return a Long value which represents the number of occurrences of the + * specified mime types in the current case for the specified data + * source, null if no count was retrieved + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + * @throws SQLException + */ + public Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set setOfMimeTypes) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, "mime_type IN " + getSqlSet(setOfMimeTypes)); + } + + /** + * Get the number of files in the case database for the current data source + * which do not have the specified mimetypes. + * + * @param currentDataSource the data source which we are finding a file + * count + * + * @param setOfMimeTypes the set of mime types that should be excluded. + * + * @return a Long value which represents the number of files that do not + * have the specific mime type, but do have a mime type. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + * @throws SQLException + */ + public Long getCountOfFilesNotInMimeTypes(DataSource currentDataSource, Set setOfMimeTypes) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, + "mime_type NOT IN " + getSqlSet(setOfMimeTypes) + + " AND mime_type IS NOT NULL AND mime_type <> '' "); + } + + /** + * Get a count of all regular files in a datasource. + * + * @param dataSource The datasource. + * + * @return The count of regular files. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + * @throws SQLException + */ + public Long getCountOfAllRegularFiles(DataSource dataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), dataSource, null); + } + + /** + * Gets the number of files in the data source with no assigned mime type. + * + * @param currentDataSource The data source. + * + * @return The number of files with no mime type or null if there is an + * issue searching the data source. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + * @throws SQLException + */ + public Long getCountOfFilesWithNoMimeType(DataSource currentDataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { + return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, "(mime_type IS NULL OR mime_type = '') "); + } + + /** + * Derives a sql set string (i.e. "('val1', 'val2', 'val3')"). A naive + * attempt is made to sanitize the strings by removing single quotes from + * values. + * + * @param setValues The values that should be present in the set. Single + * quotes are removed. + * + * @return The sql set string. + */ + private String getSqlSet(Set setValues) { + List quotedValues = setValues + .stream() + .map(str -> String.format("'%s'", str.replace("'", ""))) + .collect(Collectors.toList()); + + String commaSeparatedQuoted = String.join(", ", quotedValues); + return String.format("(%s) ", commaSeparatedQuoted); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisSummaryGetter.java index f4891a0b37..135a5ef757 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisSummaryGetter.java @@ -45,7 +45,7 @@ public class AnalysisSummaryGetter implements DefaultArtifactUpdateGovernor { ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() )); - AnalysisSummary analysisSummary; + private final AnalysisSummary analysisSummary; /** * Main constructor. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerSummaryGetter.java index 4770359911..41be8c4644 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerSummaryGetter.java @@ -44,7 +44,7 @@ public class ContainerSummaryGetter implements DefaultArtifactUpdateGovernor { BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE.getTypeID() )); - private ContainerSummary containerSummary; + private final ContainerSummary containerSummary; /** * Main constructor. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceBrowser.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceBrowser.java index 5d2694f9ff..e6942058e9 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceBrowser.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.datasourcesummary.ui; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.CaseDataSourcesSummary; import java.awt.Cursor; import org.sleuthkit.autopsy.datasourcesummary.uiutils.RightAlignedTableCellRenderer; import java.awt.EventQueue; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationSummaryGetter.java index cea19db803..2278b4ac60 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationSummaryGetter.java @@ -28,7 +28,6 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGove import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; /** * Wrapper class for converting @@ -37,7 +36,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; */ public class GeolocationSummaryGetter implements DefaultArtifactUpdateGovernor { - private GeolocationSummary geoSummary; + private final GeolocationSummary geoSummary; /** * Default constructor. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/MimeTypeSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/MimeTypeSummaryGetter.java index e4b06262ca..5468ec668a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/MimeTypeSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/MimeTypeSummaryGetter.java @@ -23,12 +23,10 @@ import java.sql.SQLException; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; -import java.util.List; import java.util.Set; -import java.util.stream.Collectors; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceInfoUtilities; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; @@ -44,22 +42,13 @@ public class MimeTypeSummaryGetter implements DefaultUpdateGovernor { private static final Set INGEST_JOB_EVENTS = new HashSet<>( Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED)); - private final SleuthkitCaseProvider provider; + private final MimeTypeSummary mimeTypeSummary; /** * Main constructor. */ public MimeTypeSummaryGetter() { - this(SleuthkitCaseProvider.DEFAULT); - } - - /** - * Main constructor. - * - * @param provider The means of obtaining a sleuthkit case. - */ - public MimeTypeSummaryGetter(SleuthkitCaseProvider provider) { - this.provider = provider; + mimeTypeSummary = new MimeTypeSummary(); } @Override @@ -102,7 +91,7 @@ public class MimeTypeSummaryGetter implements DefaultUpdateGovernor { */ public Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set setOfMimeTypes) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, "mime_type IN " + getSqlSet(setOfMimeTypes)); + return mimeTypeSummary.getCountOfFilesForMimeTypes(currentDataSource, setOfMimeTypes); } /** @@ -123,9 +112,7 @@ public class MimeTypeSummaryGetter implements DefaultUpdateGovernor { */ public Long getCountOfFilesNotInMimeTypes(DataSource currentDataSource, Set setOfMimeTypes) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, - "mime_type NOT IN " + getSqlSet(setOfMimeTypes) - + " AND mime_type IS NOT NULL AND mime_type <> '' "); + return mimeTypeSummary.getCountOfFilesNotInMimeTypes(currentDataSource, setOfMimeTypes); } /** @@ -141,7 +128,7 @@ public class MimeTypeSummaryGetter implements DefaultUpdateGovernor { */ public Long getCountOfAllRegularFiles(DataSource dataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), dataSource, null); + return mimeTypeSummary.getCountOfAllRegularFiles(dataSource); } /** @@ -158,26 +145,6 @@ public class MimeTypeSummaryGetter implements DefaultUpdateGovernor { */ public Long getCountOfFilesWithNoMimeType(DataSource currentDataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException { - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, "(mime_type IS NULL OR mime_type = '') "); - } - - /** - * Derives a sql set string (i.e. "('val1', 'val2', 'val3')"). A naive - * attempt is made to sanitize the strings by removing single quotes from - * values. - * - * @param setValues The values that should be present in the set. Single - * quotes are removed. - * - * @return The sql set string. - */ - private String getSqlSet(Set setValues) { - List quotedValues = setValues - .stream() - .map(str -> String.format("'%s'", str.replace("'", ""))) - .collect(Collectors.toList()); - - String commaSeparatedQuoted = String.join(", ", quotedValues); - return String.format("(%s) ", commaSeparatedQuoted); + return mimeTypeSummary.getCountOfFilesWithNoMimeType(currentDataSource); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesSummaryGetter.java index c4ed083852..2a2c0b8a55 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesSummaryGetter.java @@ -22,7 +22,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; @@ -44,7 +43,7 @@ public class PastCasesSummaryGetter implements DefaultArtifactUpdateGovernor { ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() )); - private PastCasesSummary pastSummary; + private final PastCasesSummary pastSummary; public PastCasesSummaryGetter() { pastSummary = new PastCasesSummary(); @@ -67,11 +66,6 @@ public class PastCasesSummaryGetter implements DefaultArtifactUpdateGovernor { */ public PastCasesResult getPastCasesData(DataSource dataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { - - if (dataSource == null) { - return null; - } - return pastSummary.getPastCasesData(dataSource); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesGetter.java index 02824dacb7..5275ec2c62 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesGetter.java @@ -48,7 +48,7 @@ public class RecentFilesGetter implements DefaultArtifactUpdateGovernor { BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() )); - private RecentFilesSummary recentSummary; + private final RecentFilesSummary recentSummary; /** * Default constructor. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelineSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelineSummaryGetter.java index 4ea7a51f36..81be37577f 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelineSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelineSummaryGetter.java @@ -40,7 +40,7 @@ public class TimelineSummaryGetter implements DefaultUpdateGovernor { private static final Set INGEST_JOB_EVENTS = new HashSet<>( Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED)); - private TimelineSummary timelineSummary; + private final TimelineSummary timelineSummary; /** * Default constructor. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index 45eba82918..e34288449a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -171,7 +171,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { /** * Creates a new TypesPanel. */ - public TypesPanel() { + TypesPanel() { this(new MimeTypeSummaryGetter(), new TypesSummaryGetter(), new ContainerSummaryGetter()); } @@ -188,7 +188,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel { * @param typeData The service for file types data. * @param containerData The service for container information. */ - public TypesPanel( + TypesPanel( MimeTypeSummaryGetter mimeTypeData, TypesSummaryGetter typeData, ContainerSummaryGetter containerData) { diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesSummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesSummaryGetter.java index 3b0887c52f..fee3f178cc 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesSummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesSummaryGetter.java @@ -43,7 +43,7 @@ public class TypesSummaryGetter implements DefaultUpdateGovernor { private static final Set INGEST_JOB_EVENTS = new HashSet<>( Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED)); - private TypesSummary typesSummary; + private final TypesSummary typesSummary; /** * Main constructor. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java index 70ad958be5..e9f9dd30b0 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivitySummaryGetter.java @@ -64,17 +64,6 @@ public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor return Collections.unmodifiableSet(ARTIFACT_UPDATE_TYPE_IDS); } - /** - * Throws an IllegalArgumentException if count <= 0. - * - * @param count The count being checked. - */ - private void assertValidCount(int count) { - if (count <= 0) { - throw new IllegalArgumentException("Count must be greater than 0"); - } - } - /** * Gets a list of recent domains based on the datasource. * @@ -86,12 +75,6 @@ public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor * @throws InterruptedException */ public List getRecentDomains(DataSource dataSource, int count) throws TskCoreException, SleuthkitCaseProviderException { - assertValidCount(count); - - if (dataSource == null) { - return Collections.emptyList(); - } - return userActivity.getRecentDomains(dataSource, count); } @@ -111,12 +94,6 @@ public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor * @throws TskCoreException */ public List getMostRecentWebSearches(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { - assertValidCount(count); - - if (dataSource == null) { - return Collections.emptyList(); - } - return userActivity.getMostRecentWebSearches(dataSource, count); } @@ -135,12 +112,6 @@ public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor * @throws TskCoreException */ public List getRecentDevices(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { - assertValidCount(count); - - if (dataSource == null) { - return Collections.emptyList(); - } - return userActivity.getRecentDevices(dataSource, count); } @@ -163,12 +134,6 @@ public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor "DataSourceUserActivitySummary_getRecentAccounts_emailMessage=Email Message", "DataSourceUserActivitySummary_getRecentAccounts_calllogMessage=Call Log",}) public List getRecentAccounts(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { - assertValidCount(count); - - if (dataSource == null) { - return Collections.emptyList(); - } - return userActivity.getRecentAccounts(dataSource, count); } @@ -192,12 +157,6 @@ public class UserActivitySummaryGetter implements DefaultArtifactUpdateGovernor * @throws TskCoreException */ public List getTopPrograms(DataSource dataSource, int count) throws SleuthkitCaseProviderException, TskCoreException { - assertValidCount(count); - - if (dataSource == null) { - return Collections.emptyList(); - } - return userActivity.getTopPrograms(dataSource, count); } } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java index 1321a4b511..3d1687eb91 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java @@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory; import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceInfoUtilities; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary.FileTypeCategoryData; @@ -101,6 +102,7 @@ class ExportTypes { } } + private final MimeTypeSummary mimeTypeSummary; private final ContainerSummary containerSummary; private final TypesSummary typesSummary; private final SleuthkitCaseProvider provider; @@ -128,64 +130,7 @@ class ExportTypes { this.provider = SleuthkitCaseProvider.DEFAULT; containerSummary = new ContainerSummary(); typesSummary = new TypesSummary(); - } - - /** - * Derives a sql set string (i.e. "('val1', 'val2', 'val3')"). A naive - * attempt is made to sanitize the strings by removing single quotes from - * values. - * - * @param setValues The values that should be present in the set. Single - * quotes are removed. - * - * @return The sql set string. - */ - private static String getSqlSet(Set setValues) { - List quotedValues = setValues - .stream() - .map(str -> String.format("'%s'", str.replace("'", ""))) - .collect(Collectors.toList()); - - String commaSeparatedQuoted = String.join(", ", quotedValues); - return String.format("(%s) ", commaSeparatedQuoted); - } - - /** - * Get the number of files in the case database for the current data source - * which have the specified mimetypes. - * - * @param currentDataSource the data source which we are finding a file - * count - * - * @param setOfMimeTypes the set of mime types which we are finding the - * number of occurences of - * - * @return a Long value which represents the number of occurrences of the - * specified mime types in the current case for the specified data - * source, null if no count was retrieved - * - * @throws NoCurrentCaseException - * @throws TskCoreException - * @throws SQLException - */ - private Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set setOfMimeTypes) throws TskCoreException, SQLException, SleuthkitCaseProvider.SleuthkitCaseProviderException { - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, "mime_type IN " + getSqlSet(setOfMimeTypes)); - } - - /** - * Gets the number of files in the data source with no assigned mime type. - * - * @param currentDataSource The data source. - * - * @return The number of files with no mime type or null if there is an - * issue searching the data source. - * - * @throws NoCurrentCaseException - * @throws TskCoreException - * @throws SQLException - */ - private Long getCountOfFilesWithNoMimeType(DataSource currentDataSource) throws TskCoreException, SQLException, SleuthkitCaseProvider.SleuthkitCaseProviderException { - return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource, "(mime_type IS NULL OR mime_type = '') "); + mimeTypeSummary = new MimeTypeSummary(); } /** @@ -208,7 +153,7 @@ class ExportTypes { long categoryTotalCount = 0; for (FileTypeCategoryData cat : FILE_MIME_TYPE_CATEGORIES) { - long thisValue = DataSourceInfoUtilities.getLongOrZero(getCountOfFilesForMimeTypes(dataSource, cat.getMimeTypes())); + long thisValue = DataSourceInfoUtilities.getLongOrZero(mimeTypeSummary.getCountOfFilesForMimeTypes(dataSource, cat.getMimeTypes())); categoryTotalCount += thisValue; fileCategoryItems.add(new PieChartItem( @@ -218,7 +163,7 @@ class ExportTypes { } // get a count of all files with no mime type - long noMimeTypeCount = DataSourceInfoUtilities.getLongOrZero(getCountOfFilesWithNoMimeType(dataSource)); + long noMimeTypeCount = DataSourceInfoUtilities.getLongOrZero(mimeTypeSummary.getCountOfFilesWithNoMimeType(dataSource)); // get a count of all regular files long allRegularFiles = DataSourceInfoUtilities.getLongOrZero(DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), dataSource, null)); From b4a32c3d2eedfa4fb5fb1acfa7553eb61742c2a8 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 23 Aug 2021 14:39:07 -0400 Subject: [PATCH 49/76] Using DataFetcher from datasourcesummary package instead --- .../{uiutils => datamodel}/DataFetcher.java | 2 +- .../datasourcesummary/ui/AnalysisPanel.java | 2 +- .../ui/BaseDataSourceSummaryPanel.java | 2 +- .../datasourcesummary/ui/ContainerPanel.java | 2 +- .../ui/GeolocationPanel.java | 2 +- .../datasourcesummary/ui/PastCasesPanel.java | 2 +- .../ui/RecentFilesPanel.java | 2 +- .../datasourcesummary/ui/TimelinePanel.java | 2 +- .../datasourcesummary/ui/TypesPanel.java | 2 +- .../ui/UserActivityPanel.java | 2 +- .../uiutils/DataFetchWorker.java | 1 + .../datasourcesummaryexport/DataFetcher.java | 43 ------------------- .../ExcelExportAction.java | 1 + .../ExportAnalysisResults.java | 1 + .../ExportContainerInfo.java | 1 + .../ExportGeolocation.java | 1 + .../ExportPastCases.java | 1 + .../ExportRecentFiles.java | 1 + .../ExportTimeline.java | 1 + .../datasourcesummaryexport/ExportTypes.java | 3 +- .../ExportUserActivity.java | 1 + 21 files changed, 20 insertions(+), 55 deletions(-) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/{uiutils => datamodel}/DataFetcher.java (96%) delete mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataFetcher.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetcher.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataFetcher.java similarity index 96% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetcher.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataFetcher.java index 6eabe79634..45dcae5f35 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetcher.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataFetcher.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourcesummary.uiutils; +package org.sleuthkit.autopsy.datasourcesummary.datamodel; /** * A function that accepts input of type I and outputs type O. This function is diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index 929f2d2364..c8b708d371 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -25,7 +25,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java index 6ac490eb11..1cf103052a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/BaseDataSourceSummaryPanel.java @@ -41,7 +41,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.EventUpdateHandler; import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.DefaultMenuItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.MenuItem; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java index fc313d1ef8..9278b3e349 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/ContainerPanel.java @@ -32,7 +32,7 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary.Contai import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary.ImageDetails; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor; import org.sleuthkit.autopsy.datasourcesummary.uiutils.UpdateGovernor; import org.sleuthkit.datamodel.DataSource; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java index 55d37a3d2e..2551e7a3ae 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/GeolocationPanel.java @@ -42,7 +42,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index f893098313..08679169d3 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -27,7 +27,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java index 1794c24aec..0bc09d59ec 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/RecentFilesPanel.java @@ -34,7 +34,7 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.Rece import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.MenuItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java index eed41cda3d..9eaf3bb130 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java @@ -42,7 +42,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.BarChartIt import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java index e34288449a..f1421665c5 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TypesPanel.java @@ -36,7 +36,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java index bb81dc9b2e..46f5deca36 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/UserActivityPanel.java @@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.Top import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopWebSearchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.ColumnModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetcher; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultCellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.MenuItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetchWorker.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetchWorker.java index 46e68a1f55..8d007c2a01 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetchWorker.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/DataFetchWorker.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.datasourcesummary.uiutils; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import java.util.concurrent.ExecutionException; import java.util.function.Consumer; import javax.swing.SwingWorker; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataFetcher.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataFetcher.java deleted file mode 100755 index b513762280..0000000000 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/DataFetcher.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2020 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.report.modules.datasourcesummaryexport; - -/** - * A function that accepts input of type I and outputs type O. This function is - * meant to be utilized with DataFetchWorker and can therefore, throw an - * interrupted exception if the processing is cancelled or an Exception of on - * another type in the event that the fetching encountered an error. - */ -@FunctionalInterface -interface DataFetcher { - - /** - * A function that accepts an input argument and outputs a result. Since it - * is meant to be used with the DataFetchWorker, it may throw an interrupted - * exception if the thread has been interrupted. It throws another type of - * exception if there is an error during fetching. - * - * @param input The input argument. - * - * @return The output result. - * - * @throws Exception - */ - O runQuery(I input) throws Exception; -} diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java index 3d7f303ea5..f9b1b2b988 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExcelExportAction.java @@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.report.ReportProgressPanel; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelExportException; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelSheetExport; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java index 8d154bd847..57786f1f8e 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportAnalysisResults.java @@ -24,6 +24,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.datamodel.AnalysisSummary; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelSheetExport; import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getTableExport; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java index e6af2ce2a0..44ede9064c 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportContainerInfo.java @@ -25,6 +25,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary.ContainerDetails; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary.ImageDetails; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java index 8cdecf8338..a0a6b0874c 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportGeolocation.java @@ -27,6 +27,7 @@ import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityCountsList; import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityData; import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityRecordCount; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java index da91b8744e..be824477a1 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.List; import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.PastCasesResult; import static org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExportAction.getFetchResult; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java index 38dbc59a78..a7d5471343 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportRecentFiles.java @@ -28,6 +28,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails; import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java index efefa6bc97..8e51199678 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java @@ -27,6 +27,7 @@ import java.util.Date; import java.util.List; import org.apache.commons.collections.CollectionUtils; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java index 3d1687eb91..c5c04acb52 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java @@ -25,13 +25,12 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceInfoUtilities; import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java index 7be189cc1b..f1a4198b42 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportUserActivity.java @@ -30,6 +30,7 @@ import java.util.stream.Stream; import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle.Messages; import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.LastAccessedArtifact; import org.sleuthkit.autopsy.datasourcesummary.datamodel.UserActivitySummary.TopAccountResult; From b056881cd9d8896028523c719c7ed82343545022 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 23 Aug 2021 14:43:58 -0400 Subject: [PATCH 50/76] Minor --- .../autopsy/datasourcesummary/datamodel/MimeTypeSummary.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java index ced8e85d95..4c5e0331eb 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/MimeTypeSummary.java @@ -27,8 +27,8 @@ import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; /** - * Wrapper class for converting org.sleuthkit.autopsy.contentutils.TypesSummary - * functionality into a DefaultArtifactUpdateGovernor used by TypesPanel tab. + * Class to export summary information used by TypesPanel tab on the known files + * present in the specified DataSource. */ public class MimeTypeSummary { From 53610835bc61ccd23cdcaffc90e8fa248b516572 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 23 Aug 2021 15:22:26 -0400 Subject: [PATCH 51/76] Optimized CR code to use fewer DB queries --- .../datamodel/CorrelationAttributeUtil.java | 263 +++++++++++++----- 1 file changed, 189 insertions(+), 74 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index f9b3c8642d..2e023f82c0 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -37,7 +37,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.DataArtifact; import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.InvalidAccountIDException; import org.sleuthkit.datamodel.TskCoreException; @@ -110,7 +110,7 @@ public class CorrelationAttributeUtil { * @param artifact An artifact. * * @return A list, possibly empty, of correlation attribute instances for - * the artifact. + * the artifact. */ public static List makeCorrAttrsToSave(BlackboardArtifact artifact) { if (SOURCE_TYPES_FOR_CR_INSERT.contains(artifact.getArtifactTypeID())) { @@ -145,68 +145,92 @@ public class CorrelationAttributeUtil { * @param artifact An artifact. * * @return A list, possibly empty, of correlation attribute instances for - * the artifact. + * the artifact. */ public static List makeCorrAttrsForCorrelation(BlackboardArtifact artifact) { List correlationAttrs = new ArrayList<>(); try { BlackboardArtifact sourceArtifact = getCorrAttrSourceArtifact(artifact); if (sourceArtifact != null) { + + List attributes = sourceArtifact.getAttributes(); + int artifactTypeID = sourceArtifact.getArtifactTypeID(); if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - BlackboardAttribute setNameAttr = sourceArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); + BlackboardAttribute setNameAttr = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) { - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID, attributes); } } else if (DOMAIN_ARTIFACT_TYPE_IDS.contains(artifactTypeID)) { - BlackboardAttribute domainAttr = sourceArtifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN)); + BlackboardAttribute domainAttr = getAttribute(attributes, new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN)); if ((domainAttr != null) && !domainsToSkip.contains(domainAttr.getValueString())) { - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID, attributes); } } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID); - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); + // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times + Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID()); + Content dataSource = sourceContent.getDataSource(); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID, + attributes, sourceContent, dataSource); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID, + attributes, sourceContent, dataSource); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID, attributes); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID, attributes); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID); - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); + // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times + Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID()); + Content dataSource = sourceContent.getDataSource(); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID, + attributes, sourceContent, dataSource); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID, + attributes, sourceContent, dataSource); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID, + attributes, sourceContent, dataSource); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); + // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times + Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID()); + Content dataSource = sourceContent.getDataSource(); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID, + attributes, sourceContent, dataSource); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID, + attributes, sourceContent, dataSource); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID); - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID); + // prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times + Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID()); + Content dataSource = sourceContent.getDataSource(); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID, + attributes, sourceContent, dataSource); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID, + attributes, sourceContent, dataSource); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { makeCorrAttrFromAcctArtifact(correlationAttrs, sourceArtifact); } else if (artifactTypeID == ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID()) { - BlackboardAttribute setNameAttr = sourceArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH)); + BlackboardAttribute setNameAttr = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH)); String pathAttrString = null; if (setNameAttr != null) { pathAttrString = setNameAttr.getValueString(); } if (pathAttrString != null && !pathAttrString.isEmpty()) { - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes); } else { - makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes); } } else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) { - makeCorrAttrsFromCommunicationArtifacts(correlationAttrs, sourceArtifact); + makeCorrAttrsFromCommunicationArtifacts(correlationAttrs, sourceArtifact, attributes); } } } catch (CorrelationAttributeNormalizationException ex) { @@ -227,33 +251,57 @@ public class CorrelationAttributeUtil { } return correlationAttrs; } - + + /** + * Gets a specific attribute from a list of attributes. + * + * @param attributes List of attributes + * @param attributeType Attribute type of interest + * + * @return Attribute of interest, null if not found. + * + * @throws TskCoreException + */ + private static BlackboardAttribute getAttribute(List attributes, BlackboardAttribute.Type attributeType) throws TskCoreException { + for (BlackboardAttribute attribute : attributes) { + if (attribute.getAttributeType().equals(attributeType)) { + return attribute; + } + } + return null; + } + /** * Makes a correlation attribute instance from a phone number attribute of * an artifact. * * @param corrAttrInstances Correlation attributes will be added to this. - * @param artifact An artifact with a phone number attribute. + * @param artifact An artifact with a phone number attribute. * - * @throws TskCoreException If there is an error querying the case database. - * @throws CentralRepoException If there is an error querying the central - * repository. + * @throws TskCoreException If there is an error + * querying the case + * database. + * @throws CentralRepoException If there is an error + * querying the central + * repository. * @throws CorrelationAttributeNormalizationException If there is an error - * in normalizing the attribute. + * in normalizing the + * attribute. */ - private static void makeCorrAttrsFromCommunicationArtifacts(List corrAttrInstances, BlackboardArtifact artifact) throws TskCoreException, CentralRepoException, CorrelationAttributeNormalizationException { + private static void makeCorrAttrsFromCommunicationArtifacts(List corrAttrInstances, BlackboardArtifact artifact, + List attributes) throws TskCoreException, CentralRepoException, CorrelationAttributeNormalizationException { CorrelationAttributeInstance corrAttr = null; /* * Extract the phone number from the artifact attribute. */ String value = null; - if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) { - value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString(); - } else if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) { - value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString(); - } else if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) { - value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString(); + if (null != getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) { + value = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString(); + } else if (null != getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) { + value = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString(); + } else if (null != getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) { + value = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString(); } /* @@ -271,17 +319,17 @@ public class CorrelationAttributeUtil { } /** - * Gets the associated artifact of a "meta-artifact" such as an interesting - * artifact hit artifact. + * Gets the associated artifact of a "meta-artifact" such as an "interesting + * artifact hit" or "previously seen" artifact. * * @param artifact An artifact. * * @return The associated artifact if the input artifact is a - * "meta-artifact", otherwise the input artifact. + * "meta-artifact", otherwise the input artifact. * * @throws NoCurrentCaseException If there is no open case. - * @throws TskCoreException If there is an error querying thew case - * database. + * @throws TskCoreException If there is an error querying thew case + * database. */ private static BlackboardArtifact getCorrAttrSourceArtifact(BlackboardArtifact artifact) throws NoCurrentCaseException, TskCoreException { BlackboardArtifact sourceArtifact = null; @@ -290,7 +338,16 @@ public class CorrelationAttributeUtil { if (assocArtifactAttr != null) { sourceArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(assocArtifactAttr.getValueLong()); } - } else { + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_PREVIOUSLY_SEEN.getTypeID() == artifact.getArtifactTypeID() + || BlackboardArtifact.ARTIFACT_TYPE.TSK_PREVIOUSLY_NOTABLE.getTypeID() == artifact.getArtifactTypeID() + || BlackboardArtifact.ARTIFACT_TYPE.TSK_PREVIOUSLY_UNSEEN.getTypeID() == artifact.getArtifactTypeID()) { + Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); + if (content instanceof DataArtifact) { + sourceArtifact = (BlackboardArtifact) content; + } + } + + if (sourceArtifact == null) { sourceArtifact = artifact; } return sourceArtifact; @@ -305,7 +362,7 @@ public class CorrelationAttributeUtil { * repository by this method. * * @param corrAttrInstances A list of correlation attribute instances. - * @param acctArtifact An account artifact. + * @param acctArtifact An account artifact. * * @return The correlation attribute instance. */ @@ -328,7 +385,7 @@ public class CorrelationAttributeUtil { return; } CentralRepoAccountType crAccountType = optCrAccountType.get(); - + int corrTypeId = crAccountType.getCorrelationTypeId(); CorrelationAttributeInstance.Type corrType = CentralRepository.getInstance().getCorrelationTypeById(corrTypeId); @@ -353,21 +410,28 @@ public class CorrelationAttributeUtil { * artifact. The correlation attribute instance is added to an input list. * * @param corrAttrInstances A list of correlation attribute instances. - * @param artifact An artifact. - * @param artAttrType The type of the atrribute of the artifact that is to - * be made into a correlatin attribute instance. - * @param typeId The type ID for the desired correlation attribute instance. + * @param artifact An artifact. + * @param artAttrType The type of the atrribute of the artifact that + * is to be made into a correlatin attribute + * instance. + * @param typeId The type ID for the desired correlation + * attribute instance. + * @param sourceContent The source content object. + * @param dataSource The data source content object. * * @throws CentralRepoException If there is an error querying the central - * repository. - * @throws TskCoreException If there is an error querying the case database. + * repository. + * @throws TskCoreException If there is an error querying the case + * database. */ - private static void makeCorrAttrFromArtifactAttr(List corrAttrInstances, BlackboardArtifact artifact, ATTRIBUTE_TYPE artAttrType, int typeId) throws CentralRepoException, TskCoreException { - BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(artAttrType)); + private static void makeCorrAttrFromArtifactAttr(List corrAttrInstances, BlackboardArtifact artifact, ATTRIBUTE_TYPE artAttrType, int typeId, + List attributes, Content sourceContent, Content dataSource) throws CentralRepoException, TskCoreException { + + BlackboardAttribute attribute = getAttribute(attributes, new BlackboardAttribute.Type(artAttrType)); if (attribute != null) { String value = attribute.getValueString(); if ((null != value) && (value.isEmpty() == false)) { - CorrelationAttributeInstance inst = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(typeId), value); + CorrelationAttributeInstance inst = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(typeId), value, sourceContent, dataSource); if (inst != null) { corrAttrInstances.add(inst); } @@ -375,12 +439,35 @@ public class CorrelationAttributeUtil { } } + /** + * Makes a correlation attribute instance from a specified attribute of an + * artifact. The correlation attribute instance is added to an input list. + * + * @param corrAttrInstances A list of correlation attribute instances. + * @param artifact An artifact. + * @param artAttrType The type of the atrribute of the artifact that + * is to be made into a correlatin attribute + * instance. + * @param typeId The type ID for the desired correlation + * attribute instance. + * + * @throws CentralRepoException If there is an error querying the central + * repository. + * @throws TskCoreException If there is an error querying the case + * database. + */ + private static void makeCorrAttrFromArtifactAttr(List corrAttrInstances, BlackboardArtifact artifact, ATTRIBUTE_TYPE artAttrType, int typeId, + List attributes) throws CentralRepoException, TskCoreException { + + makeCorrAttrFromArtifactAttr(corrAttrInstances, artifact, artAttrType, typeId, attributes, null, null); + } + /** * Makes a correlation attribute instance of a given type from an artifact. * - * @param artifact The artifact. + * @param artifact The artifact. * @param correlationType the correlation attribute type. - * @param value The correlation attribute value. + * @param value The correlation attribute value. * * TODO (Jira-6088): The methods in this low-level, utility class should * throw exceptions instead of logging them. The reason for this is that the @@ -393,18 +480,46 @@ public class CorrelationAttributeUtil { * @return The correlation attribute instance or null, if an error occurred. */ private static CorrelationAttributeInstance makeCorrAttr(BlackboardArtifact artifact, CorrelationAttributeInstance.Type correlationType, String value) { + return makeCorrAttr(artifact, correlationType, value, null, null); + } + + /** + * Makes a correlation attribute instance of a given type from an artifact. + * + * @param artifact The artifact. + * @param correlationType the correlation attribute type. + * @param value The correlation attribute value. + * @param sourceContent The source content object. + * @param dataSource The data source content object. + * + * TODO (Jira-6088): The methods in this low-level, utility class should + * throw exceptions instead of logging them. The reason for this is that the + * clients of the utility class, not the utility class itself, should be in + * charge of error handling policy, per the Autopsy Coding Standard. Note + * that clients of several of these methods currently cannot determine + * whether receiving a null return value is an error or not, plus null + * checking is easy to forget, while catching exceptions is enforced. + * + * @return The correlation attribute instance or null, if an error occurred. + */ + private static CorrelationAttributeInstance makeCorrAttr(BlackboardArtifact artifact, CorrelationAttributeInstance.Type correlationType, String value, + Content sourceContent, Content dataSource) { try { - Case currentCase = Case.getCurrentCaseThrows(); - Content sourceContent = currentCase.getSleuthkitCase().getContentById(artifact.getObjectID()); + + if (sourceContent == null) { + sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); + } if (null == sourceContent) { - logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Failed to load content with ID: {1} associated with artifact with ID: {2}", + logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Failed to load content with ID: {1} associated with artifact with ID: {2}", new Object[]{correlationType.getDisplayName(), artifact.getObjectID(), artifact.getId()}); // NON-NLS return null; } - - Content ds = sourceContent.getDataSource(); - if (ds == null) { - logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Failed to load data source for content with ID: {1}", + + if (dataSource == null) { + dataSource = sourceContent.getDataSource(); + } + if (dataSource == null) { + logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Failed to load data source for content with ID: {1}", new Object[]{correlationType.getDisplayName(), artifact.getObjectID()}); // NON-NLS return null; } @@ -415,28 +530,28 @@ public class CorrelationAttributeUtil { correlationType, value, correlationCase, - CorrelationDataSource.fromTSKDataSource(correlationCase, ds), + CorrelationDataSource.fromTSKDataSource(correlationCase, dataSource), "", "", TskData.FileKnown.UNKNOWN, sourceContent.getId()); } else { - if (! (sourceContent instanceof AbstractFile)) { - logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Source content of artifact with ID: {1} is not an AbstractFile", + if (!(sourceContent instanceof AbstractFile)) { + logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Source content of artifact with ID: {1} is not an AbstractFile", new Object[]{correlationType.getDisplayName(), artifact.getId()}); return null; } AbstractFile bbSourceFile = (AbstractFile) sourceContent; - + return new CorrelationAttributeInstance( - correlationType, - value, - correlationCase, - CorrelationDataSource.fromTSKDataSource(correlationCase, ds), - bbSourceFile.getParentPath() + bbSourceFile.getName(), - "", - TskData.FileKnown.UNKNOWN, - bbSourceFile.getId()); + correlationType, + value, + correlationCase, + CorrelationDataSource.fromTSKDataSource(correlationCase, dataSource), + bbSourceFile.getParentPath() + bbSourceFile.getName(), + "", + TskData.FileKnown.UNKNOWN, + bbSourceFile.getId()); } } catch (TskCoreException ex) { logger.log(Level.SEVERE, String.format("Error getting querying case database (%s)", artifact), ex); // NON-NLS @@ -467,7 +582,7 @@ public class CorrelationAttributeUtil { * checking is easy to forget, while catching exceptions is enforced. * * @return The correlation attribute instance or null, if no such - * correlation attribute instance was found or an error occurred. + * correlation attribute instance was found or an error occurred. */ public static CorrelationAttributeInstance getCorrAttrForFile(AbstractFile file) { From fcfb17c5251e58f0ae16dbdb1dd9deb0038d3233 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Tue, 24 Aug 2021 09:18:28 -0400 Subject: [PATCH 52/76] Reusing BarChartSeries and PieChartItem classes --- .../datasourcesummary/ui/TimelinePanel.java | 4 +- .../uiutils/BarChartPanel.java | 78 -------- .../uiutils/BarChartSeries.java | 78 ++++++++ .../BarChartExport.java | 1 + .../BarChartSeries.java | 178 ------------------ .../ExportTimeline.java | 5 +- .../datasourcesummaryexport/ExportTypes.java | 1 + .../PieChartExport.java | 1 + .../datasourcesummaryexport/PieChartItem.java | 67 ------- 9 files changed, 86 insertions(+), 327 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartSeries.java delete mode 100755 Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartItem.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java index 9eaf3bb130..4b16aef7a3 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/TimelinePanel.java @@ -36,13 +36,13 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData; import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries; -import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.OrderedKey; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.OrderedKey; import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.BarChartItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents; import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries; import org.sleuthkit.autopsy.datasourcesummary.uiutils.IngestRunningLabel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent; import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableLabel; diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartPanel.java index 21f3bca572..eb363a8a47 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartPanel.java @@ -39,84 +39,6 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.BarChartIt */ public class BarChartPanel extends AbstractLoadableComponent> { - /** - * JFreeChart bar charts don't preserve the order of bars provided to the - * chart, but instead uses the comparable nature to order items. This - * provides order using a provided index as well as the value for the axis. - */ - public static class OrderedKey implements Comparable { - - private final Object keyValue; - private final int keyIndex; - - /** - * Main constructor. - * - * @param keyValue The value for the key to be displayed in the domain - * axis. - * @param keyIndex The index at which it will be displayed. - */ - public OrderedKey(Object keyValue, int keyIndex) { - this.keyValue = keyValue; - this.keyIndex = keyIndex; - } - - /** - * @return The value for the key to be displayed in the domain axis. - */ - Object getKeyValue() { - return keyValue; - } - - /** - * @return The index at which it will be displayed. - */ - int getKeyIndex() { - return keyIndex; - } - - @Override - public int compareTo(OrderedKey o) { - // this will have a higher value than null. - if (o == null) { - return 1; - } - - // compare by index - return Integer.compare(this.getKeyIndex(), o.getKeyIndex()); - } - - @Override - public int hashCode() { - int hash = 3; - 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 OrderedKey other = (OrderedKey) obj; - if (this.keyIndex != other.keyIndex) { - return false; - } - return true; - } - - @Override - public String toString() { - // use toString on the key. - return this.getKeyValue() == null ? null : this.getKeyValue().toString(); - } - } - private static final long serialVersionUID = 1L; private static final Font DEFAULT_FONT = new JLabel().getFont(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartSeries.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartSeries.java index c1626f34b2..8709fc8ae1 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartSeries.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/BarChartSeries.java @@ -98,4 +98,82 @@ public class BarChartSeries { return key; } + /** + * JFreeChart bar charts don't preserve the order of bars provided to the + * chart, but instead uses the comparable nature to order items. This + * provides order using a provided index as well as the value for the axis. + */ + public static class OrderedKey implements Comparable { + + private final Object keyValue; + private final int keyIndex; + + /** + * Main constructor. + * + * @param keyValue The value for the key to be displayed in the domain + * axis. + * @param keyIndex The index at which it will be displayed. + */ + public OrderedKey(Object keyValue, int keyIndex) { + this.keyValue = keyValue; + this.keyIndex = keyIndex; + } + + /** + * @return The value for the key to be displayed in the domain axis. + */ + Object getKeyValue() { + return keyValue; + } + + /** + * @return The index at which it will be displayed. + */ + int getKeyIndex() { + return keyIndex; + } + + @Override + public int compareTo(OrderedKey o) { + // this will have a higher value than null. + if (o == null) { + return 1; + } + + // compare by index + return Integer.compare(this.getKeyIndex(), o.getKeyIndex()); + } + + @Override + public int hashCode() { + int hash = 3; + 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 OrderedKey other = (OrderedKey) obj; + if (this.keyIndex != other.keyIndex) { + return false; + } + return true; + } + + @Override + public String toString() { + // use toString on the key. + return this.getKeyValue() == null ? null : this.getKeyValue().toString(); + } + } + } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartExport.java index 8ff16075e3..330aac4cff 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartExport.java @@ -49,6 +49,7 @@ import org.apache.poi.xssf.usermodel.XSSFChart; import org.apache.poi.xssf.usermodel.XSSFClientAnchor; import org.apache.poi.xssf.usermodel.XSSFDrawing; import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelExportException; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelSheetExport; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.ExcelItemExportable; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartSeries.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartSeries.java deleted file mode 100755 index 99a5d1b557..0000000000 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/BarChartSeries.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2021 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.report.modules.datasourcesummaryexport; - -import java.awt.Color; -import java.util.Collections; -import java.util.List; - -/** - * Represents a series in a bar chart where all items pertain to one category. - */ -class BarChartSeries { - - /** - * An individual bar to be displayed in the bar chart. - */ - static class BarChartItem { - - private final Comparable key; - private final double value; - - /** - * Main constructor. - * - * @param key The key. - * @param value The value for this item. - */ - BarChartItem(Comparable key, double value) { - this.key = key; - this.value = value; - } - - /** - * @return The key for this item. - */ - Comparable getKey() { - return key; - } - - /** - * @return The value for this item. - */ - double getValue() { - return value; - } - } - private final Comparable key; - private final Color color; - private final List items; - - /** - * Main constructor. - * - * @param key The key. - * @param color The color for this series. - * @param items The bars to be displayed for this series. - */ - BarChartSeries(Comparable key, Color color, List items) { - this.key = key; - this.color = color; - this.items = (items == null) ? Collections.emptyList() : Collections.unmodifiableList(items); - } - - /** - * @return The color for this series. - */ - Color getColor() { - return color; - } - - /** - * @return The bars to be displayed for this series. - */ - List getItems() { - return items; - } - - /** - * @return The key for this item. - */ - Comparable getKey() { - return key; - } - - /** - * JFreeChart bar charts don't preserve the order of bars provided to the - * chart, but instead uses the comparable nature to order items. This - * provides order using a provided index as well as the value for the axis. - */ - static class OrderedKey implements Comparable { - - private final Object keyValue; - private final int keyIndex; - - /** - * Main constructor. - * - * @param keyValue The value for the key to be displayed in the domain - * axis. - * @param keyIndex The index at which it will be displayed. - */ - OrderedKey(Object keyValue, int keyIndex) { - this.keyValue = keyValue; - this.keyIndex = keyIndex; - } - - /** - * @return The value for the key to be displayed in the domain axis. - */ - Object getKeyValue() { - return keyValue; - } - - /** - * @return The index at which it will be displayed. - */ - int getKeyIndex() { - return keyIndex; - } - - @Override - public int compareTo(OrderedKey o) { - // this will have a higher value than null. - if (o == null) { - return 1; - } - - // compare by index - return Integer.compare(this.getKeyIndex(), o.getKeyIndex()); - } - - @Override - public int hashCode() { - int hash = 3; - 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 OrderedKey other = (OrderedKey) obj; - if (this.keyIndex != other.keyIndex) { - return false; - } - return true; - } - - @Override - public String toString() { - // use toString on the key. - return this.getKeyValue() == null ? null : this.getKeyValue().toString(); - } - } -} diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java index 8e51199678..cbb385b60a 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTimeline.java @@ -27,12 +27,13 @@ import java.util.Date; import java.util.List; import org.apache.commons.collections.CollectionUtils; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.BarChartItem; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.OrderedKey; import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount; import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData; -import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.BarChartSeries.BarChartItem; -import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.BarChartSeries.OrderedKey; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.KeyValueItemExportable; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.TitledExportable; import org.sleuthkit.datamodel.DataSource; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java index c5c04acb52..f3787a4a98 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportTypes.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartItem; import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummary; import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory; import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartExport.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartExport.java index 33ed70cb21..395637acb1 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartExport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartExport.java @@ -35,6 +35,7 @@ import org.apache.poi.xssf.usermodel.XSSFClientAnchor; import org.apache.poi.xssf.usermodel.XSSFDrawing; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.openxmlformats.schemas.drawingml.x2006.chart.CTPieChart; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.PieChartItem; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelExportException; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelExport.ExcelSheetExport; import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.ExcelItemExportable; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartItem.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartItem.java deleted file mode 100755 index 4db4f41bfe..0000000000 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/PieChartItem.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2021 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.report.modules.datasourcesummaryexport; - -import java.awt.Color; - -/** - * An individual pie chart slice in the pie chart. - */ -class PieChartItem { - - private final String label; - private final double value; - private final Color color; - - /** - * Main constructor. - * - * @param label The label for this pie slice. - * @param value The value for this item. - * @param color The color for the pie slice. Can be null for - * auto-determined. - */ - PieChartItem(String label, double value, Color color) { - this.label = label; - this.value = value; - this.color = color; - } - - /** - * @return The label for this item. - */ - String getLabel() { - return label; - } - - /** - * @return The value for this item. - */ - double getValue() { - return value; - } - - /** - * @return The color for the pie slice or null for auto-determined. - */ - Color getColor() { - return color; - } - -} From 39e21a046a552de912f476bfefd0cf45c014ff5a Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Tue, 24 Aug 2021 17:51:05 -0400 Subject: [PATCH 53/76] Moved CR OS Account logic to Utils --- .../datamodel/CorrelationAttributeUtil.java | 47 +++++++++++++++++++ .../eventlisteners/CaseEventListener.java | 34 ++++---------- 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index 2e023f82c0..6d2ff51c01 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -40,6 +40,8 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DataArtifact; import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.InvalidAccountIDException; +import org.sleuthkit.datamodel.OsAccount; +import org.sleuthkit.datamodel.OsAccountInstance; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -568,6 +570,51 @@ public class CorrelationAttributeUtil { } } + /** + * Makes a correlation attribute instance of a given type from an OS + * account. Checks address if it is null, or one of the ones always present + * on a windows system and thus not unique. + * + * @param osAccoun The OS account. + * @param dataSource The data source content object. + * + * @return The correlation attribute instance or null, if an error occurred. + */ + public static CorrelationAttributeInstance makeCorrAttr(OsAccount osAccount, Content dataSource) { + + Optional accountAddr = osAccount.getAddr(); + // Check address if it is null or one of the ones below we want to ignore it since they will always be one a windows system + // and they are not unique + if (!accountAddr.isPresent() || accountAddr.get().equals("S-1-5-18") || accountAddr.get().equals("S-1-5-19") || accountAddr.get().equals("S-1-5-20")) { + return null; + } + try { + + CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows()); + CorrelationAttributeInstance correlationAttributeInstance = new CorrelationAttributeInstance( + CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.OSACCOUNT_TYPE_ID), + accountAddr.get(), + correlationCase, + CorrelationDataSource.fromTSKDataSource(correlationCase, dataSource), + "", + "", + TskData.FileKnown.KNOWN, + osAccount.getId()); + + return correlationAttributeInstance; + + } catch (CentralRepoException ex) { + logger.log(Level.SEVERE, String.format("Cannot get central repository for OsAccount: %s.", accountAddr.get()), ex); //NON-NLS + return null; + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return null; + } catch (CorrelationAttributeNormalizationException ex) { + logger.log(Level.SEVERE, "Exception with Correlation Attribute Normalization.", ex); //NON-NLS + return null; + } + } + /** * Gets the correlation attribute instance for a file. * diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index a3ccca4ccf..474ac1cd85 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -661,7 +661,8 @@ public final class CaseEventListener implements PropertyChangeListener { "CaseEventsListener.prevCaseComment.text=Users seen in previous cases", "CaseEventsListener.prevExists.text=Previously Seen Users (Central Repository)"}) /** - * Add OsAccount Instance to CR and find interesting items based on the OsAccount + * Add OsAccount Instance to CR and find interesting items based on the + * OsAccount */ private final class OsAccountInstancesAddedTask implements Runnable { @@ -677,7 +678,7 @@ public final class CaseEventListener implements PropertyChangeListener { @Override public void run() { //Nothing to do here if the central repo is not enabled or if ingest is running but is set to not save data/make artifacts - if (!CentralRepository.isEnabled() + if (!CentralRepository.isEnabled() || (IngestManager.getInstance().isIngestRunning() && !(IngestEventsListener.isFlagSeenDevices() || IngestEventsListener.shouldCreateCrProperties()))) { return; } @@ -687,27 +688,15 @@ public final class CaseEventListener implements PropertyChangeListener { for (OsAccountInstance osAccountInstance : addedOsAccountNew) { try { OsAccount osAccount = osAccountInstance.getOsAccount(); - Optional accountAddr = osAccount.getAddr(); - // Check address if it is null or one of the ones below we want to ignore it since they will always be one a windows system - // and they are not unique - if (!accountAddr.isPresent() || accountAddr.get().equals("S-1-5-18") || accountAddr.get().equals("S-1-5-19") || accountAddr.get().equals("S-1-5-20")) { + CorrelationAttributeInstance correlationAttributeInstance = CorrelationAttributeUtil.makeCorrAttr(osAccount, osAccountInstance.getDataSource()); + if (correlationAttributeInstance == null) { return; } + + Optional accountAddr = osAccount.getAddr(); try { - - CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows()); - CorrelationAttributeInstance correlationAttributeInstance = new CorrelationAttributeInstance( - CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.OSACCOUNT_TYPE_ID), - accountAddr.get(), - correlationCase, - CorrelationDataSource.fromTSKDataSource(correlationCase, osAccountInstance.getDataSource()), - "", - "", - TskData.FileKnown.KNOWN, - osAccount.getId()); - // Save to the database if requested - if(IngestEventsListener.shouldCreateCrProperties()) { + if (IngestEventsListener.shouldCreateCrProperties()) { dbManager.addArtifactInstance(correlationAttributeInstance); } @@ -740,14 +729,11 @@ public final class CaseEventListener implements PropertyChangeListener { } } - } catch (CentralRepoException ex) { - LOGGER.log(Level.SEVERE, String.format("Cannot get central repository for OsAccount: %s.", accountAddr.get()), ex); //NON-NLS - } catch (NoCurrentCaseException ex) { - LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS } catch (CorrelationAttributeNormalizationException ex) { LOGGER.log(Level.SEVERE, "Exception with Correlation Attribute Normalization.", ex); //NON-NLS + } catch (CentralRepoException ex) { + LOGGER.log(Level.SEVERE, String.format("Cannot get central repository for OsAccount: %s.", accountAddr.get()), ex); //NON-NLS } - } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Cannot get central repository for OsAccount: " + "OsAccount", ex); } From 6c7f899c8085f1cd3bda1515d8c7028cb6f6dd09 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 25 Aug 2021 16:28:11 -0400 Subject: [PATCH 54/76] Fix to not call Paths.get() all the time --- .../experimental/autoingest/Manifest.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java index 5a42a01e80..c2b7ae5259 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Manifest.java @@ -30,32 +30,35 @@ import javax.annotation.concurrent.Immutable; public final class Manifest implements Serializable { private static final long serialVersionUID = 1L; - private final String filePath; + private final Path filePath; private final Date dateFileCreated; private final String caseName; private final String deviceId; - private final String dataSourcePath; + private final Path dataSourcePath; + private final String dataSourceFileName; private final Map manifestProperties; public Manifest(Path manifestFilePath, Date dateFileCreated, String caseName, String deviceId, Path dataSourcePath, Map manifestProperties) { - this.filePath = manifestFilePath.toString(); - this.dateFileCreated = dateFileCreated; + this.filePath = Paths.get(manifestFilePath.toString()); + this.dateFileCreated = new Date(dateFileCreated.getTime()); this.caseName = caseName; this.deviceId = deviceId; if (null != dataSourcePath) { - this.dataSourcePath = dataSourcePath.toString(); + this.dataSourcePath = Paths.get(dataSourcePath.toString()); + dataSourceFileName = dataSourcePath.getFileName().toString(); } else { - this.dataSourcePath = ""; + this.dataSourcePath = Paths.get(""); + dataSourceFileName = ""; } this.manifestProperties = new HashMap<>(manifestProperties); } public Path getFilePath() { - return Paths.get(this.filePath); + return this.filePath; } public Date getDateFileCreated() { - return new Date(this.dateFileCreated.getTime()); + return dateFileCreated; } public String getCaseName() { @@ -67,11 +70,11 @@ public final class Manifest implements Serializable { } public Path getDataSourcePath() { - return Paths.get(dataSourcePath); + return dataSourcePath; } public String getDataSourceFileName() { - return Paths.get(dataSourcePath).getFileName().toString(); + return dataSourceFileName; } public Map getManifestProperties() { From ef518c2af01b67a7a2fc59566842cbb4bfbea670 Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Thu, 26 Aug 2021 09:29:39 -0400 Subject: [PATCH 55/76] Update ChromeCacheExtractor.java Move creation of chromecache directory to only happen if chromecache files present --- .../recentactivity/ChromeCacheExtractor.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java index f3e073e7f9..42be2d0233 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java @@ -177,14 +177,6 @@ final class ChromeCacheExtractor { currentCase = Case.getCurrentCaseThrows(); fileManager = currentCase.getServices().getFileManager(); - // Create an output folder to save any derived files - absOutputFolderName = RAImageIngestModule.getRAOutputPath(currentCase, moduleName, context.getJobId()); - relOutputFolderName = Paths.get(RAImageIngestModule.getRelModuleOutputPath(currentCase, moduleName, context.getJobId())).normalize().toString(); - - File dir = new File(absOutputFolderName); - if (dir.exists() == false) { - dir.mkdirs(); - } } catch (NoCurrentCaseException ex) { String msg = "Failed to get current case."; //NON-NLS throw new IngestModuleException(msg, ex); @@ -279,6 +271,17 @@ final class ChromeCacheExtractor { // Identify each cache folder by searching for the index files in each List indexFiles = findIndexFiles(); + if (indexFiles.size() > 0) { + // Create an output folder to save any derived files + absOutputFolderName = RAImageIngestModule.getRAOutputPath(currentCase, moduleName, context.getJobId()); + relOutputFolderName = Paths.get(RAImageIngestModule.getRelModuleOutputPath(currentCase, moduleName, context.getJobId())).normalize().toString(); + + File dir = new File(absOutputFolderName); + if (dir.exists() == false) { + dir.mkdirs(); + } + } + // Process each of the cache folders for (AbstractFile indexFile: indexFiles) { From c45e6e9e4664c059fd064d722b8dc94d01497b6c Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 26 Aug 2021 11:21:19 -0400 Subject: [PATCH 56/76] Refactorred Octer Occurrences viewer --- .../application/OtherOccurrences.java | 23 +++---------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java b/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java index 155ca727d5..80e4ada388 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java @@ -87,27 +87,10 @@ public final class OtherOccurrences { if (osAccountAddr.isPresent()) { try { - for (OsAccountInstance instance : osAccount.getOsAccountInstances()) { - DataSource osAccountDataSource = instance.getDataSource(); - try { - CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows()); - CorrelationAttributeInstance correlationAttributeInstance = new CorrelationAttributeInstance( - CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.OSACCOUNT_TYPE_ID), - osAccountAddr.get(), - correlationCase, - CorrelationDataSource.fromTSKDataSource(correlationCase, instance.getDataSource()), - "", - "", - TskData.FileKnown.KNOWN, - osAccount.getId()); - + for (OsAccountInstance instance : osAccount.getOsAccountInstances()) { + CorrelationAttributeInstance correlationAttributeInstance = CorrelationAttributeUtil.makeCorrAttr(instance.getOsAccount(), instance.getDataSource()); + if (correlationAttributeInstance != null) { ret.add(correlationAttributeInstance); - } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, String.format("Cannot get central repository for OsAccount: %s.", osAccountAddr.get()), ex); //NON-NLS - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, String.format("Exception while getting open case looking up osAccount %s.", osAccountAddr.get()), ex); //NON-NLS - } catch (CorrelationAttributeNormalizationException ex) { - logger.log(Level.SEVERE, String.format("Exception with Correlation Attribute Normalization for osAccount %s.", osAccountAddr.get()), ex); //NON-NLS } } } catch (TskCoreException ex) { From 961dc0fae2ecbb9dc7dd10d9cb7e816d39a49a75 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 27 Aug 2021 11:43:55 -0400 Subject: [PATCH 57/76] Fixed CVT Media Viewer thumbnail selection --- .../relationships/MediaViewer.java | 71 ++++++++++++++++--- 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java index 1473e7cd67..4038455c11 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java @@ -24,6 +24,7 @@ import java.awt.KeyboardFocusManager; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.logging.Level; @@ -38,6 +39,7 @@ import org.openide.nodes.AbstractNode; import org.openide.nodes.Node; import org.openide.util.Lookup; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.communications.ModifiableProxyLookup; import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.coreutils.Logger; @@ -46,8 +48,10 @@ import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; import org.sleuthkit.datamodel.AbstractContent; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT; +import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.SleuthkitCase; /** * A Panel that shows the media (thumbnails) for the selected account. @@ -65,6 +69,7 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM private final MessageDataContent contentViewer; private MediaViewerWorker worker; + private SelectionWorker selectionWorker; @Messages({ "MediaViewer_Name=Media Attachments" @@ -111,6 +116,10 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM if (worker != null) { worker.cancel(true); } + + if(selectionWorker != null) { + selectionWorker.cancel(true); + } worker = new MediaViewerWorker(info); @@ -181,21 +190,63 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM */ private void handleNodeSelectionChange() { final Node[] nodes = tableEM.getSelectedNodes(); + contentViewer.setNode(null); + + if(selectionWorker != null) { + selectionWorker.cancel(true); + } if (nodes != null && nodes.length == 1) { AbstractContent thumbnail = nodes[0].getLookup().lookup(AbstractContent.class); if (thumbnail != null) { - try { - Content parentContent = thumbnail.getParent(); - if (parentContent != null && parentContent instanceof BlackboardArtifact) { - contentViewer.setNode(new BlackboardArtifactNode((BlackboardArtifact) parentContent)); - } - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Unable to get parent Content from AbstraceContent instance.", ex); //NON-NLS + selectionWorker = new SelectionWorker(thumbnail); + worker.execute(); + } + } + } + + /** + * A SwingWorker to get the artifact associated with the selected thumbnail. + */ + private class SelectionWorker extends SwingWorker { + + private final AbstractContent thumbnail; + + // Construct a SelectionWorker. + SelectionWorker(AbstractContent thumbnail) { + this.thumbnail = thumbnail; + } + + @Override + protected BlackboardArtifact doInBackground() throws Exception { + SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); + List artifactsList = skCase.getBlackboardArtifacts(TSK_ASSOCIATED_OBJECT, thumbnail.getId()); + for (BlackboardArtifact contextArtifact : artifactsList) { + BlackboardAttribute associatedArtifactAttribute = contextArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); + if (associatedArtifactAttribute != null) { + long artifactId = associatedArtifactAttribute.getValueLong(); + return contextArtifact.getSleuthkitCase().getBlackboardArtifact(artifactId); } } - } else { - contentViewer.setNode(null); + return null; + } + + @Override + protected void done() { + if (isCancelled()) { + return; + } + + try { + BlackboardArtifact artifact = get(); + if (artifact != null) { + contentViewer.setNode(new BlackboardArtifactNode(artifact)); + } else { + contentViewer.setNode(null); + } + } catch (InterruptedException | ExecutionException ex) { + logger.log(Level.SEVERE, "Failed message viewer based on thumbnail selection. thumbnailID = " + thumbnail.getId(), ex); + } } } From 633ef5a3b319677c3e19baf241d4cb6633a74142 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 27 Aug 2021 16:07:11 -0400 Subject: [PATCH 58/76] Format AnalysisResultsContentViewer.java --- .../AnalysisResultsContentViewer.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java index 634d5c61db..ef623f44cf 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java @@ -40,18 +40,17 @@ import org.sleuthkit.datamodel.TskCoreException; */ @ServiceProvider(service = DataContentViewer.class, position = 7) public class AnalysisResultsContentViewer implements DataContentViewer { + private static final Logger logger = Logger.getLogger(AnalysisResultsContentPanel.class.getName()); - + // isPreferred value private static final int PREFERRED_VALUE = 3; - + private final AnalysisResultsViewModel viewModel = new AnalysisResultsViewModel(); private final AnalysisResultsContentPanel panel = new AnalysisResultsContentPanel(); - + private SwingWorker worker = null; - - @NbBundle.Messages({ "AnalysisResultsContentViewer_title=Analysis Results" }) @@ -135,11 +134,11 @@ public class AnalysisResultsContentViewer implements DataContentViewer { if (content instanceof AnalysisResult) { return true; } - + if (content == null || content instanceof BlackboardArtifact) { continue; } - + try { if (Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().hasAnalysisResults(content.getId())) { return true; @@ -148,7 +147,7 @@ public class AnalysisResultsContentViewer implements DataContentViewer { logger.log(Level.SEVERE, "Unable to get analysis results for file with obj id " + content.getId(), ex); } } - + return false; } From 187dae19e6706fa9fd5a267092093f809a3a6378 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 27 Aug 2021 17:07:08 -0400 Subject: [PATCH 59/76] Format AnalysisResultsViewModel.java --- .../analysisresults/AnalysisResultsViewModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java index 00cc170b14..03720e0cbe 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java @@ -252,7 +252,7 @@ public class AnalysisResultsViewModel { try { nodeContent = Optional.of(content); - + // get the aggregate score of that content aggregateScore = Optional.ofNullable(content.getAggregateScore()); From 192c2913cd2d4a6d060ef68c40b441399f664a6a Mon Sep 17 00:00:00 2001 From: Seb2lyon Date: Sun, 29 Aug 2021 15:02:07 +0200 Subject: [PATCH 60/76] Updated translation main page : link to doc's original version --- docs/doxygen-user_fr/main.dox | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/doxygen-user_fr/main.dox b/docs/doxygen-user_fr/main.dox index aabf341c7c..936de4aee8 100644 --- a/docs/doxygen-user_fr/main.dox +++ b/docs/doxygen-user_fr/main.dox @@ -8,6 +8,9 @@ Ceci est le guide de l'utilisateur de la "Options" et décritent dans cette documentation sont accessibles via la barre de menu système sous "Préférences" ou via le raccourci Cmd +, (touche "Cmd" + touche "plus"). +Version originale de ce guide: +- Dernière version à jour + Rubriques d'aide ------- Les rubriques suivantes sont disponibles: From 3380edc2ff12091a5448b1108d6aa86427bc31e1 Mon Sep 17 00:00:00 2001 From: Seb2lyon Date: Sun, 29 Aug 2021 15:09:55 +0200 Subject: [PATCH 61/76] Add lastupdated file : contain the commit number that the french translation was updated to --- docs/doxygen-user_fr/lastupdated | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 docs/doxygen-user_fr/lastupdated diff --git a/docs/doxygen-user_fr/lastupdated b/docs/doxygen-user_fr/lastupdated new file mode 100644 index 0000000000..6873d4c1a4 --- /dev/null +++ b/docs/doxygen-user_fr/lastupdated @@ -0,0 +1,2 @@ +# Sun Aug 29 15:02:07 2021 +0200 +user-docs_fr.lastupdated=4f62b90f652ba12dae1b2286fb3eb065f00e5311 \ No newline at end of file From f5f3e16d9372b2ee4792110a2a1b354392c8b054 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 30 Aug 2021 13:47:03 -0400 Subject: [PATCH 62/76] First cut --- .../CommandLineIngestSettingsPanel.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java index ca11d03f13..4b41a1c631 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java @@ -280,18 +280,16 @@ public class CommandLineIngestSettingsPanel extends javax.swing.JPanel { add(nodePanel, java.awt.BorderLayout.CENTER); }// //GEN-END:initComponents @Messages({ - "CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (commas not allowed):", + "CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (letters and digits only):", "CommandLineIngestSettingPanel_empty_report_name_mgs=Report profile name was empty, no profile created.", - "CommandLineIngestSettingPanel_existing_report_name_mgs=Report profile name was already exists, no profile created." + "CommandLineIngestSettingPanel_existing_report_name_mgs=Report profile name was already exists, no profile created.", + "CommandLineIngestSettingPanel_invalid_report_name_mgs=Report profile name contained only illegal characters, no profile created.", + "# {0} - sanitized report name", "CommandLineIngestSettingPanel_report_name_changed_mgs=Report profile name contained illegal characters. Sanitized report name is: {0}" }) private void bnEditReportSettingsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnEditReportSettingsActionPerformed String reportName = getReportName(); if (reportName.equals(Bundle.CommandListIngestSettingsPanel_Make_Config())) { reportName = JOptionPane.showInputDialog(this, Bundle.CommandListIngestSettingsPanel_Report_Name_Msg()); - - // sanitize report name. Remove all commas because in CommandLineOptionProcessor we use commas - // to separate multiple report names - reportName = reportName.replaceAll(",", ""); // User hit cancel if (reportName == null) { @@ -302,6 +300,18 @@ public class CommandLineIngestSettingsPanel extends javax.swing.JPanel { } else if (doesReportProfileNameExist(reportName)) { JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), Bundle.CommandLineIngestSettingPanel_existing_report_name_mgs()); return; + } else { + // sanitize report name + String originalReportName = reportName; + reportName = reportName.replaceAll("[^A-Za-z0-9]", ""); + if (reportName.isEmpty()) { + // report name contained only invalid characters, display error + JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), Bundle.CommandLineIngestSettingPanel_invalid_report_name_mgs()); + return; + } else if (!(originalReportName.equals(reportName))) { + // alert the user that the name has changed + JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), Bundle.CommandLineIngestSettingPanel_report_name_changed_mgs(reportName)); + } } } From 412ec720e40d99c5b0af719bbf93db0cc6e5ccf1 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 30 Aug 2021 14:35:52 -0400 Subject: [PATCH 63/76] move tskdbdiff to sleuthkit --- test/script/regression.py | 10 +- test/script/tskdbdiff.py | 1200 ------------------------------------- 2 files changed, 7 insertions(+), 1203 deletions(-) delete mode 100644 test/script/tskdbdiff.py diff --git a/test/script/regression.py b/test/script/regression.py index 1b42f623bc..e898bec3e5 100644 --- a/test/script/regression.py +++ b/test/script/regression.py @@ -16,18 +16,22 @@ # 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. +import sys +import subprocess +import os + +# import db_diff +sys.path.insert(0, os.path.join(subprocess.getoutput("cygpath -u $TSK_HOME"), "db_diff")) from tskdbdiff import TskDbDiff, TskDbDiffException, PGSettings import codecs import datetime import logging -import os + import re import shutil import socket import sqlite3 -import subprocess -import sys from sys import platform as _platform import time import traceback diff --git a/test/script/tskdbdiff.py b/test/script/tskdbdiff.py deleted file mode 100644 index f0aae2c2a5..0000000000 --- a/test/script/tskdbdiff.py +++ /dev/null @@ -1,1200 +0,0 @@ -# Requires python3 - -import re -import sqlite3 -import subprocess -import shutil -import os -import codecs -import datetime -import sys -from typing import Callable, Dict, Union, List - -import psycopg2 -import psycopg2.extras -import socket -import csv - -class TskDbDiff(object): - """Compares two TSK/Autospy SQLite databases. - - Attributes: - gold_artifacts: - autopsy_artifacts: - gold_attributes: - autopsy_attributes: - gold_objects: - autopsy_objects: - artifact_comparison: - attribute_comparision: - report_errors: a listof_listof_String, the error messages that will be - printed to screen in the run_diff method - passed: a boolean, did the diff pass? - autopsy_db_file: - gold_db_file: - """ - def __init__(self, output_db, gold_db, output_dir=None, gold_bb_dump=None, gold_dump=None, verbose=False, isMultiUser=False, pgSettings=None): - """Constructor for TskDbDiff. - - Args: - output_db_path: path to output database (non-gold standard) - gold_db_path: path to gold database - output_dir: (optional) Path to folder where generated files will be put. - gold_bb_dump: (optional) path to file where the gold blackboard dump is located - gold_dump: (optional) path to file where the gold non-blackboard dump is located - verbose: (optional) a boolean, if true, diff results are sent to stdout. - """ - - self.output_db_file = output_db - self.gold_db_file = gold_db - self.output_dir = output_dir - self.gold_bb_dump = gold_bb_dump - self.gold_dump = gold_dump - self._generate_gold_dump = False - self._generate_gold_bb_dump = False - self._bb_dump_diff = "" - self._dump_diff = "" - self._bb_dump = "" - self._dump = "" - self.verbose = verbose - self.isMultiUser = isMultiUser - self.pgSettings = pgSettings - - if self.isMultiUser and not self.pgSettings: - print("Missing PostgreSQL database connection settings data.") - sys.exit(1) - - if self.gold_bb_dump is None: - self._generate_gold_bb_dump = True - if self.gold_dump is None: - self._generate_gold_dump = True - - def run_diff(self): - """Compare the databases. - - Raises: - TskDbDiffException: if an error occurs while diffing or dumping the database - """ - - self._init_diff() - id_obj_path_table = -1 - # generate the gold database dumps if necessary - if self._generate_gold_dump: - id_obj_path_table = TskDbDiff._dump_output_db_nonbb(self.gold_db_file, self.gold_dump, self.isMultiUser, self.pgSettings) - if self._generate_gold_bb_dump: - TskDbDiff._dump_output_db_bb(self.gold_db_file, self.gold_bb_dump, self.isMultiUser, self.pgSettings, id_obj_path_table) - - # generate the output database dumps (both DB and BB) - id_obj_path_table = TskDbDiff._dump_output_db_nonbb(self.output_db_file, self._dump, self.isMultiUser, self.pgSettings) - TskDbDiff._dump_output_db_bb(self.output_db_file, self._bb_dump, self.isMultiUser, self.pgSettings, id_obj_path_table) - - # Compare non-BB - dump_diff_pass = self._diff(self._dump, self.gold_dump, self._dump_diff) - - # Compare BB - bb_dump_diff_pass = self._diff(self._bb_dump, self.gold_bb_dump, self._bb_dump_diff) - - self._cleanup_diff() - return dump_diff_pass, bb_dump_diff_pass - - - def _init_diff(self): - """Set up the necessary files based on the arguments given at construction""" - if self.output_dir is None: - # No stored files - self._bb_dump = TskDbDiff._get_tmp_file("BlackboardDump", ".txt") - self._bb_dump_diff = TskDbDiff._get_tmp_file("BlackboardDump-Diff", ".txt") - self._dump = TskDbDiff._get_tmp_file("DBDump", ".txt") - self._dump_diff = TskDbDiff._get_tmp_file("DBDump-Diff", ".txt") - else: - self._bb_dump = os.path.join(self.output_dir, "BlackboardDump.txt") - self._bb_dump_diff = os.path.join(self.output_dir, "BlackboardDump-Diff.txt") - self._dump = os.path.join(self.output_dir, "DBDump.txt") - self._dump_diff = os.path.join(self.output_dir, "DBDump-Diff.txt") - - # Sorting gold before comparing (sort behaves differently in different environments) - new_bb = TskDbDiff._get_tmp_file("GoldBlackboardDump", ".txt") - new_db = TskDbDiff._get_tmp_file("GoldDBDump", ".txt") - if self.gold_bb_dump is not None: - srtcmdlst = ["sort", self.gold_bb_dump, "-o", new_bb] - subprocess.call(srtcmdlst) - srtcmdlst = ["sort", self.gold_dump, "-o", new_db] - subprocess.call(srtcmdlst) - self.gold_bb_dump = new_bb - self.gold_dump = new_db - - - def _cleanup_diff(self): - if self.output_dir is None: - #cleanup temp files - os.remove(self._dump) - os.remove(self._bb_dump) - if os.path.isfile(self._dump_diff): - os.remove(self._dump_diff) - if os.path.isfile(self._bb_dump_diff): - os.remove(self._bb_dump_diff) - - if self.gold_bb_dump is None: - os.remove(self.gold_bb_dump) - os.remove(self.gold_dump) - - - def _diff(self, output_file, gold_file, diff_path): - """Compare two text files. - - Args: - output_file: a pathto_File, the latest text file - gold_file: a pathto_File, the gold text file - diff_path: The file to write the differences to - Returns False if different - """ - - if (not os.path.isfile(output_file)): - return False - - if (not os.path.isfile(gold_file)): - return False - - # It is faster to read the contents in and directly compare - output_data = codecs.open(output_file, "r", "utf_8").read() - gold_data = codecs.open(gold_file, "r", "utf_8").read() - if (gold_data == output_data): - return True - - # If they are different, invoke 'diff' - diff_file = codecs.open(diff_path, "wb", "utf_8") - # Gold needs to be passed in as 1st arg and output as 2nd - dffcmdlst = ["diff", gold_file, output_file] - subprocess.call(dffcmdlst, stdout = diff_file) - - # create file path for gold files inside output folder. In case of diff, both gold and current run files - # are available in the report output folder. Prefix Gold- is added to the filename. - gold_file_in_output_dir = os.path.join(os.path.dirname(output_file), "Gold-" + os.path.basename(output_file)) - shutil.copy(gold_file, gold_file_in_output_dir) - - return False - - - @staticmethod - def _get_associated_artifact_type(cur, artifact_id, isMultiUser): - if isMultiUser: - cur.execute( - "SELECT tsk_files.parent_path, blackboard_artifact_types.display_name FROM blackboard_artifact_types INNER JOIN blackboard_artifacts ON blackboard_artifact_types.artifact_type_id = blackboard_artifacts.artifact_type_id INNER JOIN tsk_files ON tsk_files.obj_id = blackboard_artifacts.obj_id WHERE artifact_id=%s", - [artifact_id]) - else: - cur.execute( - "SELECT tsk_files.parent_path, blackboard_artifact_types.display_name FROM blackboard_artifact_types INNER JOIN blackboard_artifacts ON blackboard_artifact_types.artifact_type_id = blackboard_artifacts.artifact_type_id INNER JOIN tsk_files ON tsk_files.obj_id = blackboard_artifacts.obj_id WHERE artifact_id=?", - [artifact_id]) - - info = cur.fetchone() - - return "File path: " + info[0] + " Artifact Type: " + info[1] - - - @staticmethod - def _dump_output_db_bb(db_file, bb_dump_file, isMultiUser, pgSettings, id_obj_path_table): - """Dumps sorted text results to the given output location. - - Smart method that deals with a blackboard comparison to avoid issues - with different IDs based on when artifacts were created. - - Args: - db_file: a pathto_File, the output database. - bb_dump_file: a pathto_File, the sorted dump file to write to - """ - - unsorted_dump = TskDbDiff._get_tmp_file("dump_data", ".txt") - if isMultiUser: - conn, unused_db = db_connect(db_file, isMultiUser, pgSettings) - artifact_cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) - else: # Use Sqlite - conn = sqlite3.connect(db_file) - conn.text_factory = lambda x: x.decode("utf-8", "ignore") - conn.row_factory = sqlite3.Row - artifact_cursor = conn.cursor() - # Get the list of all artifacts (along with type and associated file) - # @@@ Could add a SORT by parent_path in here since that is how we are going to later sort it. - artifact_cursor.execute("SELECT tsk_files.parent_path, tsk_files.name, blackboard_artifact_types.display_name, blackboard_artifacts.artifact_id FROM blackboard_artifact_types INNER JOIN blackboard_artifacts ON blackboard_artifact_types.artifact_type_id = blackboard_artifacts.artifact_type_id INNER JOIN tsk_files ON tsk_files.obj_id = blackboard_artifacts.obj_id") - database_log = codecs.open(unsorted_dump, "wb", "utf_8") - row = artifact_cursor.fetchone() - appnd = False - counter = 0 - artifact_count = 0 - artifact_fail = 0 - - # Cycle through artifacts - try: - while (row != None): - - # File Name and artifact type - # Remove parent object ID from Unalloc file name - normalizedName = re.sub('^Unalloc_[0-9]+_', 'Unalloc_', row["name"]) - if(row["parent_path"] != None): - database_log.write(row["parent_path"] + normalizedName + ' ') - else: - database_log.write(normalizedName + ' ') - - if isMultiUser: - attribute_cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) - else: - attribute_cursor = conn.cursor() - looptry = True - artifact_count += 1 - try: - art_id = "" - art_id = str(row["artifact_id"]) - - # Get attributes for this artifact - if isMultiUser: - attribute_cursor.execute("SELECT blackboard_attributes.source, blackboard_attributes.attribute_type_id, blackboard_attribute_types.display_name, blackboard_attributes.value_type, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double FROM blackboard_attributes INNER JOIN blackboard_attribute_types ON blackboard_attributes.attribute_type_id = blackboard_attribute_types.attribute_type_id WHERE artifact_id = %s ORDER BY blackboard_attributes.source, blackboard_attribute_types.display_name, blackboard_attributes.value_type, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double", [art_id]) - else: - attribute_cursor.execute("SELECT blackboard_attributes.source, blackboard_attributes.attribute_type_id, blackboard_attribute_types.display_name, blackboard_attributes.value_type, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double FROM blackboard_attributes INNER JOIN blackboard_attribute_types ON blackboard_attributes.attribute_type_id = blackboard_attribute_types.attribute_type_id WHERE artifact_id =? ORDER BY blackboard_attributes.source, blackboard_attribute_types.display_name, blackboard_attributes.value_type, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double", [art_id]) - - attributes = attribute_cursor.fetchall() - - # Print attributes - if (len(attributes) == 0): - # @@@@ This should be - database_log.write(' \n') - row = artifact_cursor.fetchone() - continue - - src = attributes[0][0] - for attr in attributes: - numvals = 0 - for x in range(3, 6): - if(attr[x] != None): - numvals += 1 - if(numvals > 1): - msg = "There were too many values for attribute type: " + attr["display_name"] + " for artifact with id #" + str(row["artifact_id"]) + ".\n" - - if(not attr["source"] == src): - msg = "There were inconsistent sources for artifact with id #" + str(row["artifact_id"]) + ".\n" - - try: - if attr["value_type"] == 0: - attr_value_as_string = str(attr["value_text"]) - elif attr["value_type"] == 1: - attr_value_as_string = str(attr["value_int32"]) - elif attr["value_type"] == 2: - attr_value_as_string = str(attr["value_int64"]) - if attr["attribute_type_id"] == 36 and id_obj_path_table != -1 and int(attr_value_as_string) > 0: #normalize positive TSK_PATH_IDs from being object id to a path if the obj_id_path_table was generated - attr_value_as_string = id_obj_path_table[int(attr_value_as_string)] - elif attr["value_type"] == 3: - attr_value_as_string = "%20.10f" % float((attr["value_double"])) #use exact format from db schema to avoid python auto format double value to (0E-10) scientific style - elif attr["value_type"] == 4: - attr_value_as_string = "bytes" - elif attr["value_type"] == 5: - attr_value_as_string = str(attr["value_int64"]) - if attr["display_name"] == "Associated Artifact": - attr_value_as_string = TskDbDiff._get_associated_artifact_type(attribute_cursor, attr_value_as_string, isMultiUser) - patrn = re.compile("[\n\0\a\b\r\f]") - attr_value_as_string = re.sub(patrn, ' ', attr_value_as_string) - if attr["source"] == "Keyword Search" and attr["display_name"] == "Keyword Preview": - attr_value_as_string = "" - database_log.write('') - except IOError as e: - print("IO error") - raise TskDbDiffException("Unexpected IO error while writing to database log." + str(e)) - - except sqlite3.Error as e: - msg = "Attributes in artifact id (in output DB)# " + str(row["artifact_id"]) + " encountered an error: " + str(e) +" .\n" - print("Attributes in artifact id (in output DB)# ", str(row["artifact_id"]), " encountered an error: ", str(e)) - print() - looptry = False - artifact_fail += 1 - database_log.write('Error Extracting Attributes') - database_log.close() - raise TskDbDiffException(msg) - finally: - attribute_cursor.close() - - - # @@@@ This should be - database_log.write(' \n') - row = artifact_cursor.fetchone() - - if(artifact_fail > 0): - msg ="There were " + str(artifact_count) + " artifacts and " + str(artifact_fail) + " threw an exception while loading.\n" - except Exception as e: - raise TskDbDiffException("Unexpected error while dumping blackboard database: " + str(e)) - finally: - database_log.close() - artifact_cursor.close() - conn.close() - - # Now sort the file - srtcmdlst = ["sort", unsorted_dump, "-o", bb_dump_file] - subprocess.call(srtcmdlst) - - @staticmethod - def _dump_output_db_nonbb(db_file, dump_file, isMultiUser, pgSettings): - """Dumps a database to a text file. - - Does not dump the artifact and attributes. - - Args: - db_file: a pathto_File, the database file to dump - dump_file: a pathto_File, the location to dump the non-blackboard database items - """ - - conn, backup_db_file = db_connect(db_file, isMultiUser, pgSettings) - guid_utils = TskGuidUtils.create(conn) - - if isMultiUser: - table_cols = get_pg_table_columns(conn) - schema = get_pg_schema(db_file, pgSettings.username, pgSettings.password, - pgSettings.pgHost, pgSettings.pgPort) - else: - table_cols = get_sqlite_table_columns(conn) - schema = get_sqlite_schema(conn) - - with codecs.open(dump_file, "wb", "utf_8") as output_file: - output_file.write(schema + "\n") - for table, cols in sorted(table_cols.items(), key=lambda pr: pr[0]): - normalizer = TABLE_NORMALIZATIONS[table] if table in TABLE_NORMALIZATIONS else None - write_normalized(guid_utils, output_file, conn, table, cols, normalizer) - - # Now sort the file - srtcmdlst = ["sort", dump_file, "-o", dump_file] - subprocess.call(srtcmdlst) - - conn.close() - # cleanup the backup - # if backup_db_file: - # os.remove(backup_db_file) - return guid_utils.obj_id_guids - - @staticmethod - def dump_output_db(db_file, dump_file, bb_dump_file, isMultiUser, pgSettings): - """Dumps the given database to text files for later comparison. - - Args: - db_file: a pathto_File, the database file to dump - dump_file: a pathto_File, the location to dump the non-blackboard database items - bb_dump_file: a pathto_File, the location to dump the blackboard database items - """ - id_obj_path_table = TskDbDiff._dump_output_db_nonbb(db_file, dump_file, isMultiUser, pgSettings) - TskDbDiff._dump_output_db_bb(db_file, bb_dump_file, isMultiUser, pgSettings, id_obj_path_table) - - @staticmethod - def _get_tmp_file(base, ext): - time = datetime.datetime.now().time().strftime("%H%M%f") - return os.path.join(os.environ['TMP'], base + time + ext) - - -class TskDbDiffException(Exception): - pass - -class PGSettings(object): - def __init__(self, pgHost=None, pgPort=5432, user=None, password=None): - self.pgHost = pgHost - self.pgPort = pgPort - self.username = user - self.password = password - - def get_pgHost(self): - return self.pgHost - - def get_pgPort(self): - return self.pgPort - - def get_username(self): - return self.username - - def get_password(self): - return self.password - - -class TskGuidUtils: - """ - This class provides guids for potentially volatile data. - """ - - @staticmethod - def _get_guid_dict(db_conn, select_statement, delim="", normalizer: Union[Callable[[str], str], None] = None): - """ - Retrieves a dictionary mapping the first item selected to a concatenation of the remaining values. - Args: - db_conn: The database connection. - select_statement: The select statement. - delim: The delimiter for how row data from index 1 to end shall be concatenated. - normalizer: Means of normalizing the generated string or None. - - Returns: A dictionary mapping the key (the first item in the select statement) to a concatenation of the remaining values. - - """ - cursor = db_conn.cursor() - cursor.execute(select_statement) - ret_dict = {} - for row in cursor: - # concatenate value rows with delimiter filtering out any null values. - value_str = delim.join([str(col) for col in filter(lambda col: col is not None, row[1:])]) - if normalizer: - value_str = normalizer(value_str) - ret_dict[row[0]] = value_str - - return ret_dict - - @staticmethod - def create(db_conn): - """ - Creates an instance of this class by querying for relevant guid data. - Args: - db_conn: The database connection. - - Returns: The instance of this class. - - """ - guid_files = TskGuidUtils._get_guid_dict(db_conn, "SELECT obj_id, parent_path, name FROM tsk_files", - normalizer=normalize_file_path) - guid_vs_parts = TskGuidUtils._get_guid_dict(db_conn, "SELECT obj_id, addr, start FROM tsk_vs_parts", "_") - guid_vs_info = TskGuidUtils._get_guid_dict(db_conn, "SELECT obj_id, vs_type, img_offset FROM tsk_vs_info", "_") - guid_fs_info = TskGuidUtils._get_guid_dict(db_conn, "SELECT obj_id, img_offset, fs_type FROM tsk_fs_info", "_") - guid_image_names = TskGuidUtils._get_guid_dict(db_conn, "SELECT obj_id, name FROM tsk_image_names " - "WHERE sequence=0", - normalizer=get_filename) - guid_os_accounts = TskGuidUtils._get_guid_dict(db_conn, "SELECT os_account_obj_id, addr FROM tsk_os_accounts") - guid_reports = TskGuidUtils._get_guid_dict(db_conn, "SELECT obj_id, path FROM reports", - normalizer=normalize_file_path) - - objid_artifacts = TskGuidUtils._get_guid_dict(db_conn, - "SELECT blackboard_artifacts.artifact_obj_id, " - "blackboard_artifact_types.type_name " - "FROM blackboard_artifacts " - "INNER JOIN blackboard_artifact_types " - "ON blackboard_artifact_types.artifact_type_id = " - "blackboard_artifacts.artifact_type_id") - - artifact_objid_artifacts = TskGuidUtils._get_guid_dict(db_conn, - "SELECT blackboard_artifacts.artifact_id, " - "blackboard_artifact_types.type_name " - "FROM blackboard_artifacts " - "INNER JOIN blackboard_artifact_types " - "ON blackboard_artifact_types.artifact_type_id = " - "blackboard_artifacts.artifact_type_id") - - cursor = db_conn.cursor() - cursor.execute("SELECT obj_id, par_obj_id FROM tsk_objects") - par_obj_objects = dict([(row[0], row[1]) for row in cursor]) - - guid_artifacts = {} - for k, v in objid_artifacts.items(): - if k in par_obj_objects: - par_obj_id = par_obj_objects[k] - - # check for artifact parent in files, images, reports - path = '' - for artifact_parent_dict in [guid_files, guid_image_names, guid_reports]: - if par_obj_id in artifact_parent_dict: - path = artifact_parent_dict[par_obj_id] - break - - guid_artifacts[k] = "/".join([path, v]) - - return TskGuidUtils( - # aggregate all the object id dictionaries together - obj_id_guids={**guid_files, **guid_reports, **guid_os_accounts, **guid_vs_parts, **guid_vs_info, - **guid_fs_info, **guid_fs_info, **guid_image_names, **guid_artifacts}, - artifact_types=artifact_objid_artifacts) - - artifact_types: Dict[int, str] - obj_id_guids: Dict[int, any] - - def __init__(self, obj_id_guids: Dict[int, any], artifact_types: Dict[int, str]): - """ - Main constructor. - Args: - obj_id_guids: A dictionary mapping object ids to their guids. - artifact_types: A dictionary mapping artifact ids to their types. - """ - self.artifact_types = artifact_types - self.obj_id_guids = obj_id_guids - - def get_guid_for_objid(self, obj_id, omitted_value: Union[str, None] = 'Object ID Omitted'): - """ - Returns the guid for the specified object id or returns omitted value if the object id is not found. - Args: - obj_id: The object id. - omitted_value: The value if no object id mapping is found. - - Returns: The relevant guid or the omitted_value. - - """ - return self.obj_id_guids[obj_id] if obj_id in self.obj_id_guids else omitted_value - - def get_guid_for_file_objid(self, obj_id, omitted_value: Union[str, None] = 'Object ID Omitted'): - # this method is just an alias for get_guid_for_objid - return self.get_guid_for_objid(obj_id, omitted_value) - - def get_guid_for_accountid(self, account_id, omitted_value: Union[str, None] = 'Account ID Omitted'): - # this method is just an alias for get_guid_for_objid - return self.get_guid_for_objid(account_id, omitted_value) - - def get_guid_for_artifactid(self, artifact_id, omitted_value: Union[str, None] = 'Artifact ID Omitted'): - """ - Returns the guid for the specified artifact id or returns omitted value if the artifact id is not found. - Args: - artifact_id: The artifact id. - omitted_value: The value if no object id mapping is found. - - Returns: The relevant guid or the omitted_value. - """ - return self.artifact_types[artifact_id] if artifact_id in self.artifact_types else omitted_value - - -class NormalizeRow: - """ - Given a dictionary representing a row (i.e. column name mapped to value), returns a normalized representation of - that row such that the values should be less volatile from run to run. - """ - row_masker: Callable[[TskGuidUtils, Dict[str, any]], Dict[str, any]] - - def __init__(self, row_masker: Callable[[TskGuidUtils, Dict[str, any]], Union[Dict[str, any], None]]): - """ - Main constructor. - Args: - row_masker: The function to be called to mask the specified row. - """ - self.row_masker = row_masker - - def normalize(self, guid_util: TskGuidUtils, row: Dict[str, any]) -> Union[Dict[str, any], None]: - """ - Normalizes a row such that the values should be less volatile from run to run. - Args: - guid_util: The TskGuidUtils instance providing guids for volatile ids. - row: The row values mapping column name to value. - - Returns: The normalized row or None if the row should be ignored. - - """ - return self.row_masker(guid_util, row) - - -class NormalizeColumns(NormalizeRow): - """ - Utility for normalizing specific column values of a row so they are not volatile values that will change from run - to run. - """ - - @classmethod - def _normalize_col_vals(cls, - col_mask: Dict[str, Union[any, Callable[[TskGuidUtils, any], any]]], - guid_util: TskGuidUtils, - row: Dict[str, any]): - """ - Normalizes column values for each column rule provided. - Args: - col_mask: A dictionary mapping columns to either the replacement value or a function to retrieve the - replacement value given the TskGuidUtils instance and original value as arguments. - guid_util: The TskGuidUtil used to provide guids for volatile values. - row: The dictionary representing the row mapping column names to values. - - Returns: The new row representation. - - """ - row_copy = row.copy() - for key, val in col_mask.items(): - # only replace values if present in row - if key in row_copy: - # if a column replacing function, call with original value - if isinstance(val, Callable): - row_copy[key] = val(guid_util, row[key]) - # otherwise, just replace with mask value - else: - row_copy[key] = val - - return row_copy - - def __init__(self, col_mask: Dict[str, Union[any, Callable[[any], any]]]): - super().__init__(lambda guid_util, row: NormalizeColumns._normalize_col_vals(col_mask, guid_util, row)) - - -def get_path_segs(path: Union[str, None]) -> Union[List[str], None]: - """ - Breaks a path string into its folders and filenames. - Args: - path: The path string or None. - - Returns: The path segments or None. - - """ - if path: - # split on backslash or forward slash - return list(filter(lambda x: len(x.strip()) > 0, [s for s in re.split(r"[\\/]", path)])) - else: - return None - - -def get_filename(path: Union[str, None]) -> Union[str, None]: - """ - Returns the last segment of a file path. - Args: - path: The path. - - Returns: The last segment of the path - - """ - path_segs = get_path_segs(path) - if path_segs is not None and len(path_segs) > 0: - return path_segs[-1] - else: - return None - - -def index_of(lst, search_item) -> int: - """ - Returns the index of the item in the list or -1. - Args: - lst: The list. - search_item: The item to search for. - - Returns: The index in the list of the item or -1. - - """ - for idx, item in enumerate(lst): - if item == search_item: - return idx - - return -1 - - -def get_sql_insert_value(val) -> str: - """ - Returns the value that would appear in a sql insert statement (i.e. string becomes 'string', None becomes NULL) - Args: - val: The original value. - - Returns: The sql insert equivalent value. - - """ - if val is None: - return "NULL" - - if isinstance(val, str): - escaped_val = val.replace('\n', '\\n').replace("'", "''") - return f"'{escaped_val}'" - - return str(val) - - -def get_sqlite_table_columns(conn) -> Dict[str, List[str]]: - """ - Retrieves a dictionary mapping table names to a list of all the columns for that table - where the columns are in ordinal value. - Args: - conn: The database connection. - - Returns: A dictionary of the form { table_name: [col_name1, col_name2...col_nameN] } - - """ - cur = conn.cursor() - cur.execute("SELECT name FROM sqlite_master tables WHERE tables.type='table'") - tables = list([table[0] for table in cur.fetchall()]) - cur.close() - - to_ret = {} - for table in tables: - cur = conn.cursor() - cur.execute('SELECT name FROM pragma_table_info(?) ORDER BY cid', [table]) - to_ret[table] = list([col[0] for col in cur.fetchall()]) - - return to_ret - - -def get_pg_table_columns(conn) -> Dict[str, List[str]]: - """ - Returns a dictionary mapping table names to the list of their columns in ordinal order. - Args: - conn: The pg database connection. - - Returns: The dictionary of tables mapped to a list of their ordinal-orderd column names. - """ - cursor = conn.cursor() - cursor.execute(""" - SELECT cols.table_name, cols.column_name - FROM information_schema.columns cols - WHERE cols.column_name IS NOT NULL - AND cols.table_name IS NOT NULL - AND cols.table_name IN ( - SELECT tables.tablename FROM pg_catalog.pg_tables tables - WHERE LOWER(schemaname) = 'public' - ) - ORDER by cols.table_name, cols.ordinal_position; - """) - mapping = {} - for row in cursor: - mapping.setdefault(row[0], []).append(row[1]) - - cursor.close() - return mapping - - -def sanitize_schema(original: str) -> str: - """ - Sanitizes sql script representing table/index creations. - Args: - original: The original sql schema creation script. - - Returns: The sanitized schema. - """ - sanitized_lines = [] - dump_line = '' - for line in original.splitlines(): - line = line.strip('\r\n ') - lower_line = line.lower() - # It's comment or alter statement or catalog entry or set idle entry or empty line - if (not line or - line.startswith('--') or - lower_line.startswith('set') or - " set default nextval" in lower_line or - " owner to " in lower_line or - " owned by " in lower_line or - "pg_catalog" in lower_line or - "idle_in_transaction_session_timeout" in lower_line): - continue - - # if there is no white space or parenthesis delimiter, add a space - if re.match(r'^.+?[^\s()]$', dump_line) and re.match(r'^[^\s()]', line): - dump_line += ' ' - - # append the line to the outputted line - dump_line += line - - # if line ends with ';' then this will be one statement in diff - if line.endswith(';'): - sanitized_lines.append(dump_line) - dump_line = '' - - if len(dump_line.strip()) > 0: - sanitized_lines.append(dump_line) - - return "\n".join(sanitized_lines) - - -def get_pg_schema(dbname: str, pg_username: str, pg_pword: str, pg_host: str, pg_port: Union[str, int]): - """ - Gets the schema to be added to the dump text from the postgres database. - Args: - dbname: The name of the database. - pg_username: The postgres user name. - pg_pword: The postgres password. - pg_host: The postgres host. - pg_port: The postgres port. - - Returns: The normalized schema. - - """ - os.environ['PGPASSWORD'] = pg_pword - pg_dump = ["pg_dump", "-U", pg_username, "-h", pg_host, "-p", str(pg_port), - "--schema-only", "-d", dbname, "-t", "public.*"] - output = subprocess.check_output(pg_dump) - output_str = output.decode('UTF-8') - return sanitize_schema(output_str) - - -def get_sqlite_schema(db_conn): - """ - Gets the schema to be added to the dump text from the sqlite database. - Args: - db_conn: The database connection. - - Returns: The normalized schema. - - """ - cursor = db_conn.cursor() - query = "SELECT sql FROM sqlite_master " \ - "WHERE type IN ('table', 'index') AND sql IS NOT NULL " \ - "ORDER BY type DESC, tbl_name ASC" - - cursor.execute(query) - schema = '\n'.join([str(row[0]) + ';' for row in cursor]) - return sanitize_schema(schema) - - -def _mask_event_desc(desc: str) -> str: - """ - Masks dynamic event descriptions of the form ":" so the artifact id is no longer - present. - Args: - desc: The original description. - - Returns: The normalized description. - - """ - - # Takes a string like "Shell Bags: 30840" and replaces with "ShellBags:" - match = re.search(r"^\s*(.+?)\s*:\s*\d+\s*$", desc.strip()) - if match: - return f"{match.group(1)}:" - - return desc - - -def normalize_tsk_event_descriptions(guid_util: TskGuidUtils, row: Dict[str, any]) -> Dict[str, any]: - """ - Normalizes event description rows masking possibly changing column values. - Args: - guid_util: Provides guids for ids that may change from run to run. - row: A dictionary mapping column names to values. - - Returns: The normalized event description row. - """ - row_copy = row.copy() - # replace object ids with information that is deterministic - row_copy['event_description_id'] = MASKED_ID - row_copy['content_obj_id'] = guid_util.get_guid_for_file_objid(row['content_obj_id']) - row_copy['artifact_id'] = guid_util.get_guid_for_artifactid(row['artifact_id']) \ - if row['artifact_id'] is not None else None - row_copy['data_source_obj_id'] = guid_util.get_guid_for_file_objid(row['data_source_obj_id']) - - if row['full_description'] == row['med_description'] == row['short_description']: - row_copy['full_description'] = _mask_event_desc(row['full_description']) - row_copy['med_description'] = _mask_event_desc(row['med_description']) - row_copy['short_description'] = _mask_event_desc(row['short_description']) - - return row_copy - - -def normalize_ingest_jobs(guid_util: TskGuidUtils, row: Dict[str, any]) -> Dict[str, any]: - """ - Normalizes ingest jobs table rows. - Args: - guid_util: Provides guids for ids that may change from run to run. - row: A dictionary mapping column names to values. - - Returns: The normalized ingest job row. - - """ - row_copy = row.copy() - row_copy['host_name'] = "{host_name}" - - start_time = row['start_date_time'] - end_time = row['end_date_time'] - if start_time <= end_time: - row_copy['start_date_time'] = MASKED_TIME - row_copy['end_date_time'] = MASKED_TIME - - return row_copy - - -def normalize_unalloc_files(path_str: Union[str, None]) -> Union[str, None]: - """ - Normalizes a path string removing timestamps from unalloc files. - Args: - path_str: The original path string. - - Returns: The path string where timestamps are removed from unalloc strings. - - """ - # takes a file name like "Unalloc_30580_7466496_2980941312" and removes the object id to become - # "Unalloc_7466496_2980941312" - return None if path_str is None else re.sub('Unalloc_[0-9]+_', 'Unalloc_', path_str) - - -def normalize_regripper_files(path_str: Union[str, None]) -> Union[str, None]: - """ - Normalizes a path string removing timestamps from regripper files. - Args: - path_str: The original path string. - - Returns: The path string where timestamps are removed from regripper paths. - - """ - # takes a file name like "regripper-12345-full" and removes the id to become "regripper-full" - return None if path_str is None else re.sub(r'regripper-[0-9]+-full', 'regripper-full', path_str) - - -def normalize_file_path(path_str: Union[str, None]) -> Union[str, None]: - """ - Normalizes file paths removing or replacing pieces that will change from run to run (i.e. object id) - Args: - path_str: The original path string. - - Returns: The normalized path string - """ - return normalize_unalloc_files(normalize_regripper_files(path_str)) - - -def normalize_tsk_files(guid_util: TskGuidUtils, row: Dict[str, any]) -> Dict[str, any]: - """ - Normalizes files table rows. - Args: - guid_util: Provides guids for ids that may change from run to run. - row: A dictionary mapping column names to values. - - Returns: The normalized files table row. - - """ - # Ignore TIFF size and hash if extracted from PDFs. - # See JIRA-6951 for more details. - row_copy = row.copy() - if row['extension'] is not None and row['extension'].strip().lower() == 'tif' and \ - row['parent_path'] is not None and row['parent_path'].strip().lower().endswith('.pdf/'): - row_copy['size'] = "SIZE_IGNORED" - row_copy['md5'] = "MD5_IGNORED" - row_copy['sha256'] = "SHA256_IGNORED" - - row_copy['data_source_obj_id'] = guid_util.get_guid_for_file_objid(row['data_source_obj_id']) - row_copy['obj_id'] = MASKED_OBJ_ID - row_copy['os_account_obj_id'] = 'MASKED_OS_ACCOUNT_OBJ_ID' - row_copy['parent_path'] = normalize_file_path(row['parent_path']) - row_copy['name'] = normalize_file_path(row['name']) - return row_copy - - -def normalize_tsk_files_path(guid_util: TskGuidUtils, row: Dict[str, any]) -> Dict[str, any]: - """ - Normalizes file path table rows. - Args: - guid_util: Provides guids for ids that may change from run to run. - row: A dictionary mapping column names to values. - - Returns: The normalized file path table row. - """ - row_copy = row.copy() - path = row['path'] - if path is not None: - path_parts = get_path_segs(path) - module_output_idx = index_of(path_parts, 'ModuleOutput') - if module_output_idx >= 0: - # remove everything up to and including ModuleOutput if ModuleOutput present - path_parts = path_parts[module_output_idx:] - if len(path_parts) > 2 and path_parts[1] == 'EFE': - # for embedded file extractor, the next folder is the object id and should be omitted - del path_parts[2] - - row_copy['path'] = os.path.join(*path_parts) if len(path_parts) > 0 else '/' - - row_copy['obj_id'] = guid_util.get_guid_for_file_objid(row['obj_id']) - return row_copy - - -def normalize_tsk_objects_path(guid_util: TskGuidUtils, objid: int, - no_path_placeholder: Union[str, None]) -> Union[str, None]: - """ - Returns a normalized path to be used in a tsk_objects table row. - Args: - guid_util: The utility for fetching guids. - objid: The object id of the item. - no_path_placeholder: text to return if no path value found. - - Returns: The 'no_path_placeholder' text if no path. Otherwise, the normalized path. - - """ - path = guid_util.get_guid_for_objid(objid, omitted_value=None) - - if path is None: - return no_path_placeholder - else: - # remove host name (for multi-user) and dates/times from path for reports - path_parts = get_path_segs(path) - module_output_idx = index_of(path_parts, 'ModuleOutput') - if module_output_idx >= 0: - # remove everything up to and including ModuleOutput if ModuleOutput present - path_parts = path_parts[module_output_idx:] - - if "BulkExtractor" in path_parts or "Smirk" in path_parts: - # chop off the last folder (which contains a date/time) - path_parts = path_parts[:-1] - - if path_parts and len(path_parts) >= 2: - for idx in range(0, len(path_parts) - 1): - if path_parts[idx].lower() == "reports" and \ - path_parts[idx + 1].lower().startswith("autopsytestcase html report"): - path_parts = ["Reports", "AutopsyTestCase HTML Report"] - break - - path = os.path.join(*path_parts) if len(path_parts) > 0 else '/' - - return path - - -def normalize_tsk_objects(guid_util: TskGuidUtils, row: Dict[str, any]) -> Dict[str, any]: - """ - Normalizes object table rows. - Args: - guid_util: Provides guids for ids that may change from run to run. - row: A dictionary mapping column names to values. - - Returns: The normalized object table row. - """ - row_copy = row.copy() - row_copy['obj_id'] = None if row['obj_id'] is None else \ - normalize_tsk_objects_path(guid_util, row['obj_id'], MASKED_OBJ_ID) - - row_copy['par_obj_id'] = None if row['par_obj_id'] is None else \ - normalize_tsk_objects_path(guid_util, row['par_obj_id'], 'MASKED_PARENT_OBJ_ID') - - return row_copy - - -MASKED_TIME = "MASKED_TIME" -MASKED_OBJ_ID = "MASKED_OBJ_ID" -MASKED_ID = "MASKED_ID" - -IGNORE_TABLE = "IGNORE_TABLE" - -TableNormalization = Union[IGNORE_TABLE, NormalizeRow] - -""" -This dictionary maps tables where data should be specially handled to how they should be handled. -""" -TABLE_NORMALIZATIONS: Dict[str, TableNormalization] = { - "blackboard_artifacts": IGNORE_TABLE, - "blackboard_attributes": IGNORE_TABLE, - "data_source_info": NormalizeColumns({ - "device_id": "{device id}", - "added_date_time": "{dateTime}" - }), - "image_gallery_groups": NormalizeColumns({ - "group_id": MASKED_ID, - "data_source_obj_id": lambda guid_util, col: guid_util.get_guid_for_objid(col, omitted_value=None), - }), - "image_gallery_groups_seen": IGNORE_TABLE, - "ingest_jobs": NormalizeRow(normalize_ingest_jobs), - "reports": NormalizeColumns({ - "obj_id": MASKED_OBJ_ID, - "path": "AutopsyTestCase", - "crtime": MASKED_TIME - }), - "tsk_aggregate_score": NormalizeColumns({ - "obj_id": lambda guid_util, col: guid_util.get_guid_for_objid(col, omitted_value="Object ID Omitted"), - "data_source_obj_id": lambda guid_util, col: guid_util.get_guid_for_objid(col, omitted_value="Data Source Object ID Omitted"), - }), - "tsk_analysis_results": NormalizeColumns({ - "artifact_obj_id": - lambda guid_util, col: guid_util.get_guid_for_objid(col, omitted_value="Artifact Object ID Omitted"), - }), - "tsk_data_artifacts": NormalizeColumns({ - "artifact_obj_id": - lambda guid_util, col: guid_util.get_guid_for_file_objid(col, omitted_value="Artifact Object ID Omitted"), - "os_account_obj_id": - lambda guid_util, col: guid_util.get_guid_for_file_objid(col, omitted_value="Account Object ID Omitted"), - }), - "tsk_event_descriptions": NormalizeRow(normalize_tsk_event_descriptions), - "tsk_events": NormalizeColumns({ - "event_id": "MASKED_EVENT_ID", - "event_description_id": 'ID OMITTED' - }), - "tsk_examiners": NormalizeColumns({ - "login_name": "{examiner_name}" - }), - "tsk_files": NormalizeRow(normalize_tsk_files), - "tsk_file_layout": NormalizeColumns({ - "obj_id": lambda guid_util, col: guid_util.get_guid_for_file_objid(col) - }), - "tsk_files_path": NormalizeRow(normalize_tsk_files_path), - "tsk_image_names": NormalizeColumns({ - "name": lambda guid_util, col: get_filename(col) - }), - "tsk_objects": NormalizeRow(normalize_tsk_objects), - "tsk_os_account_attributes": NormalizeColumns({ - "id": MASKED_ID, - "os_account_obj_id": lambda guid_util, col: guid_util.get_guid_for_accountid(col), - "source_obj_id": lambda guid_util, col: guid_util.get_guid_for_objid(col) - }), - "tsk_os_account_instances": NormalizeColumns({ - "id": MASKED_ID, - "os_account_obj_id": lambda guid_util, col: guid_util.get_guid_for_accountid(col) - }), - "tsk_os_accounts": NormalizeColumns({ - "os_account_obj_id": MASKED_OBJ_ID - }), - "tsk_vs_parts": NormalizeColumns({ - "obj_id": MASKED_OBJ_ID - }) -} - - -def write_normalized(guid_utils: TskGuidUtils, output_file, db_conn, table: str, column_names: List[str], - normalizer: Union[TableNormalization, None] = None): - """ - Outputs rows of a file as their normalized values (where values should not change from run to run). - Args: - guid_utils: Provides guids to replace values that would potentially change from run to run. - output_file: The file where the normalized dump will be written. - db_conn: The database connection. - table: The name of the table. - column_names: The name of the columns in the table in ordinal order. - normalizer: The normalizer (if any) to use so that data is properly normalized. - """ - if normalizer == IGNORE_TABLE: - return - - cursor = db_conn.cursor() - - joined_columns = ",".join([col for col in column_names]) - cursor.execute(f"SELECT {joined_columns} FROM {table}") - for row in cursor: - if len(row) != len(column_names): - print( - f"ERROR: in {table}, number of columns retrieved: {len(row)} but columns are" - f" {len(column_names)} with {str(column_names)}") - continue - - row_dict = {} - for col_idx in range(0, len(column_names)): - row_dict[column_names[col_idx]] = row[col_idx] - - if normalizer and isinstance(normalizer, NormalizeRow): - row_masker: NormalizeRow = normalizer - row_dict = row_masker.normalize(guid_utils, row_dict) - - if row_dict is not None: - # show row as json-like value - entries = [] - for column in column_names: - dict_value = row_dict[column] if column in row_dict and row_dict[column] is not None else None - value = get_sql_insert_value(dict_value) - if value is not None: - entries.append((column, value)) - insert_values = ", ".join([f"{pr[0]}: {pr[1]}" for pr in entries]) - insert_statement = f"{table}: {{{insert_values}}}\n" - output_file.write(insert_statement) - - -def db_connect(db_file, is_multi_user, pg_settings=None): - if is_multi_user: # use PostgreSQL - try: - return psycopg2.connect("dbname=" + db_file + " user=" + pg_settings.username + " host=" + - pg_settings.pgHost + " password=" + pg_settings.password), None - except: - print("Failed to connect to the database: " + db_file) - else: # Sqlite - # Make a copy that we can modify - backup_db_file = TskDbDiff._get_tmp_file("tsk_backup_db", ".db") - shutil.copy(db_file, backup_db_file) - # We sometimes get situations with messed up permissions - os.chmod(backup_db_file, 0o777) - return sqlite3.connect(backup_db_file), backup_db_file - - -def main(): - try: - sys.argv.pop(0) - output_db = sys.argv.pop(0) - gold_db = sys.argv.pop(0) - except: - print("usage: tskdbdiff [OUTPUT DB PATH] [GOLD DB PATH]") - sys.exit(1) - - db_diff = TskDbDiff(output_db, gold_db, output_dir=".") - dump_passed, bb_dump_passed = db_diff.run_diff() - - if dump_passed and bb_dump_passed: - print("Database comparison passed.") - if not dump_passed: - print("Non blackboard database comparison failed.") - if not bb_dump_passed: - print("Blackboard database comparison failed.") - - sys.exit(0) - - -if __name__ == "__main__": - if sys.hexversion < 0x03000000: - print("Python 3 required") - sys.exit(1) - - main() From 8c8444b12fc6cd5f3719a6f4c45346fd7b9b437a Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 30 Aug 2021 14:43:45 -0400 Subject: [PATCH 64/76] Implemented profile name verification --- .../Bundle.properties-MERGED | 3 +- .../CommandLineIngestSettingsPanel.java | 10 +--- .../autopsy/ingest/Bundle.properties-MERGED | 2 +- .../autopsy/ingest/Bundle_ja.properties | 1 - .../autopsy/ingest/ProfilePanel.java | 58 ++++++++----------- .../autopsy/ingest/ProfileSettingsPanel.java | 2 +- 6 files changed, 32 insertions(+), 44 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties-MERGED index 447b4e3038..c760c4b1c8 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties-MERGED @@ -1,8 +1,9 @@ CommandLineIngestSettingPanel_empty_report_name_mgs=Report profile name was empty, no profile created. CommandLineIngestSettingPanel_existing_report_name_mgs=Report profile name was already exists, no profile created. +CommandLineIngestSettingPanel_invalid_report_name_mgs=Report profile name contained illegal characters, no profile created. CommandListIngestSettingsPanel_Default_Report_DisplayName=Default CommandListIngestSettingsPanel_Make_Config=Make new profile... -CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (commas not allowed): +CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (letters and digits only): OpenIDE-Module-Name=CommandLineAutopsy OptionsCategory_Keywords_Command_Line_Ingest_Settings=Command Line Ingest Settings OptionsCategory_Keywords_General=Options diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java index 4b41a1c631..d4c7bd601e 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java @@ -283,8 +283,7 @@ public class CommandLineIngestSettingsPanel extends javax.swing.JPanel { "CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (letters and digits only):", "CommandLineIngestSettingPanel_empty_report_name_mgs=Report profile name was empty, no profile created.", "CommandLineIngestSettingPanel_existing_report_name_mgs=Report profile name was already exists, no profile created.", - "CommandLineIngestSettingPanel_invalid_report_name_mgs=Report profile name contained only illegal characters, no profile created.", - "# {0} - sanitized report name", "CommandLineIngestSettingPanel_report_name_changed_mgs=Report profile name contained illegal characters. Sanitized report name is: {0}" + "CommandLineIngestSettingPanel_invalid_report_name_mgs=Report profile name contained illegal characters, no profile created." }) private void bnEditReportSettingsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnEditReportSettingsActionPerformed String reportName = getReportName(); @@ -304,14 +303,11 @@ public class CommandLineIngestSettingsPanel extends javax.swing.JPanel { // sanitize report name String originalReportName = reportName; reportName = reportName.replaceAll("[^A-Za-z0-9]", ""); - if (reportName.isEmpty()) { + if (reportName.isEmpty() || (!(originalReportName.equals(reportName)))) { // report name contained only invalid characters, display error JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), Bundle.CommandLineIngestSettingPanel_invalid_report_name_mgs()); return; - } else if (!(originalReportName.equals(reportName))) { - // alert the user that the name has changed - JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), Bundle.CommandLineIngestSettingPanel_report_name_changed_mgs(reportName)); - } + } } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED index 9c1a1bfa5c..3165583373 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED @@ -115,7 +115,7 @@ IngestJobSettingsPanel.jButtonSelectAll.text=Select All IngestJobSettingsPanel.jButtonDeselectAll.text=Deselect All IngestManager.cancellingIngest.msgDlg.text=Cancelling all currently running ingest jobs IngestManager.serviceIsDown.msgDlg.text={0} is down -ProfilePanel.messages.profileNameContainsIllegalCharacter=Profile name contains an illegal character +ProfilePanel.messages.profileNameContainsIllegalCharacter=Profile name contains an illegal character. Only letters and digits are allowed. ProfilePanel.messages.profilesMustBeNamed=Ingest profile must be named. ProfilePanel.newProfileText=NewEmptyProfile ProfilePanel.profileDescLabel.text=Description: diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties index 1456e6922a..2b0efb2f0b 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties @@ -135,7 +135,6 @@ ModuleTableModel.colName.module=\u30e2\u30b8\u30e5\u30fc\u30eb OpenIDE-Module-Name=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8 OptionsCategory_Keywords_IngestOptions=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8 OptionsCategory_Name_IngestOptions=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8 -ProfilePanel.messages.profileNameContainsIllegalCharacter=\u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u540d\u306b\u4e0d\u6b63\u306a\u6587\u5b57\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3059 ProfilePanel.messages.profilesMustBeNamed=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u306b\u540d\u524d\u3092\u4ed8\u3051\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 ProfilePanel.newProfileText=NewEmptyProfile ProfilePanel.profileDescLabel.text=\u8aac\u660e\: diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index dc145a6824..86faece681 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -39,13 +39,12 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { "ProfilePanel.profileNameLabel.text=Profile Name:", "ProfilePanel.newProfileText=NewEmptyProfile", "ProfilePanel.messages.profilesMustBeNamed=Ingest profile must be named.", - "ProfilePanel.messages.profileNameContainsIllegalCharacter=Profile name contains an illegal character"}) + "ProfilePanel.messages.profileNameContainsIllegalCharacter=Profile name contains an illegal character. Only letters and digits are allowed."}) private final IngestJobSettingsPanel ingestSettingsPanel; private final IngestJobSettings settings; private IngestProfile profile; private final static String NEW_PROFILE_NAME = NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.newProfileText"); - private static final List ILLEGAL_NAME_CHARS = Collections.unmodifiableList(new ArrayList<>(Arrays.asList("\\", "/", ":", "*", "?", "\"", "<", ">"))); /** * Creates new form ProfilePanel @@ -232,6 +231,9 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { * Save a new or edited profile. */ void store() { + if (!isValidDefinition(false)) { + return; + } saveSettings(); } @@ -243,38 +245,28 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { * * @return true for valid, false for invalid. */ - boolean isValidDefinition() { - if (getProfileName().isEmpty()) { - NotifyDescriptor notifyDesc = new NotifyDescriptor.Message( - NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.messages.profilesMustBeNamed"), - NotifyDescriptor.WARNING_MESSAGE); - DialogDisplayer.getDefault().notify(notifyDesc); - return false; - } - if (!containsOnlyLegalChars(getProfileName(), ILLEGAL_NAME_CHARS)) { - NotifyDescriptor notifyDesc = new NotifyDescriptor.Message( - NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.messages.profileNameContainsIllegalCharacter"), - NotifyDescriptor.WARNING_MESSAGE); - DialogDisplayer.getDefault().notify(notifyDesc); - return false; - } - return true; - } - - /** - * Checks an input string for the use of illegal characters. - * - * @param toBeChecked The input string. - * @param illegalChars The characters deemed to be illegal. - * - * @return True if the string does not contain illegal characters, false - * otherwise. - */ - private static boolean containsOnlyLegalChars(String toBeChecked, List illegalChars) { - for (String illegalChar : illegalChars) { - if (toBeChecked.contains(illegalChar)) { - return false; + boolean isValidDefinition(boolean dispayWarnings) { + String profileName = getProfileName(); + if (profileName.isEmpty()) { + if (dispayWarnings) { + NotifyDescriptor notifyDesc = new NotifyDescriptor.Message( + NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.messages.profilesMustBeNamed"), + NotifyDescriptor.WARNING_MESSAGE); + DialogDisplayer.getDefault().notify(notifyDesc); } + return false; + } + + // check if the name contains illegal characters + String sanitizedName = profileName.replaceAll("[^A-Za-z0-9]", ""); + if (!(profileName.equals(sanitizedName))) { + if (dispayWarnings) { + NotifyDescriptor notifyDesc = new NotifyDescriptor.Message( + NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.messages.profileNameContainsIllegalCharacter"), + NotifyDescriptor.WARNING_MESSAGE); + DialogDisplayer.getDefault().notify(notifyDesc); + } + return false; } return true; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java index c841431171..300cc613d8 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfileSettingsPanel.java @@ -416,7 +416,7 @@ class ProfileSettingsPanel extends IngestModuleGlobalSettingsPanel implements Op do { option = JOptionPane.CANCEL_OPTION; dialog.display(panel); - } while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition()); + } while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition(true)); if (option == JOptionPane.OK_OPTION) { From ab30a1da8b56b600122cb830fb926c7f7ef6cccf Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 30 Aug 2021 15:05:42 -0400 Subject: [PATCH 65/76] Minor --- .../org/sleuthkit/autopsy/ingest/ProfilePanel.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index 86faece681..543faa1b01 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.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"); @@ -19,10 +19,6 @@ package org.sleuthkit.autopsy.ingest; import java.beans.PropertyChangeListener; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.util.NbBundle; @@ -230,11 +226,12 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { /** * Save a new or edited profile. */ - void store() { + boolean store() { if (!isValidDefinition(false)) { - return; + return false; } saveSettings(); + return true; } void load() { @@ -242,6 +239,8 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { /** * Checks that information entered constitutes a valid ingest profile. + * + * @param dispayWarnings boolean flag whether to display warnings if an error occurred. * * @return true for valid, false for invalid. */ From f332d3c91eb116f738e9c6fe1ea9a160f2dfe85e Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 30 Aug 2021 15:10:54 -0400 Subject: [PATCH 66/76] Fixed bug --- .../autopsy/communications/relationships/MediaViewer.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java index 4038455c11..67a9ee5482 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java @@ -111,7 +111,7 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM @Override public void setSelectionInfo(SelectionInfo info) { contentViewer.setNode(null); - thumbnailViewer.resetComponent(); + thumbnailViewer.setNode(null); if (worker != null) { worker.cancel(true); @@ -199,8 +199,9 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM if (nodes != null && nodes.length == 1) { AbstractContent thumbnail = nodes[0].getLookup().lookup(AbstractContent.class); if (thumbnail != null) { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); selectionWorker = new SelectionWorker(thumbnail); - worker.execute(); + selectionWorker.execute(); } } } @@ -246,6 +247,8 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM } } catch (InterruptedException | ExecutionException ex) { logger.log(Level.SEVERE, "Failed message viewer based on thumbnail selection. thumbnailID = " + thumbnail.getId(), ex); + } finally { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } } } From ed679aa28ccae5170aaf2b33efcf2440e46e768d Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 30 Aug 2021 15:28:55 -0400 Subject: [PATCH 67/76] Addressed review comments --- .../autopsy/guiutils/JFileChooserFactory.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/JFileChooserFactory.java b/Core/src/org/sleuthkit/autopsy/guiutils/JFileChooserFactory.java index 996608f452..85e7936882 100755 --- a/Core/src/org/sleuthkit/autopsy/guiutils/JFileChooserFactory.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/JFileChooserFactory.java @@ -44,7 +44,7 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; * enough time for the JFileChooser to be initialized in the background before * the UI user causes an event which will launch the JFileChooser. If the * JFileChooser is not initialized prior to the event occurring, the EDT will be - * blocked , but the wait cursor will appear. + * blocked, but the wait cursor will appear. * * https://stackoverflow.com/questions/49792375/jfilechooser-is-very-slow-when-using-windows-look-and-feel */ @@ -54,10 +54,11 @@ public final class JFileChooserFactory { private final FutureTask futureFileChooser; private JFileChooser chooser; + private final ExecutorService executor; /** - * Create a new instance of the factory. The constructor will kick of an - * executor to that will execute the task of initializing the JFileChooser. + * Create a new instance of the factory. The constructor will kick off an + * executor to execute the initializing the JFileChooser task. */ public JFileChooserFactory() { this(null); @@ -80,7 +81,7 @@ public final class JFileChooserFactory { futureFileChooser = new FutureTask<>(new ChooserCallable(cls)); } - ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("JFileChooser-background-thread").build()); + executor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("JFileChooser-background-thread").build()); executor.execute(futureFileChooser); } @@ -104,14 +105,14 @@ public final class JFileChooserFactory { chooser = futureFileChooser.get(); } catch (InterruptedException | ExecutionException ex) { // An exception is generally not expected. On the off chance - // one does occur save the sisutation by created a new + // one does occur save the situation by created a new // instance in the EDT. - // If an exception does occur logger.log(Level.WARNING, "Failed to initialize JFileChooser in background thread."); chooser = new JFileChooser(); } } finally { WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + executor.shutdown(); } } From 2153bd56e886bf1b8c8a93fc66240f4b0ee7a830 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Tue, 31 Aug 2021 11:42:17 -0400 Subject: [PATCH 68/76] Fix for table refresh issues --- .../autopsy/experimental/autoingest/AutoIngestDashboard.java | 1 + .../autopsy/experimental/autoingest/AutoIngestJobsNode.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index 075ba9395b..ae532a1db9 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -262,6 +262,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { * Shut down parts of the AutoIngestDashboard which were initialized */ void shutDown() { + scheduledRefreshThreadPoolExecutor.shutdownNow(); if (autoIngestMonitor != null) { autoIngestMonitor.shutDown(); } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java index 415b3237b9..24a1e57fb9 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java @@ -70,7 +70,7 @@ final class AutoIngestJobsNode extends AbstractNode { * refresh events */ AutoIngestJobsNode(AutoIngestMonitor monitor, AutoIngestJobStatus status, EventBus eventBus) { - super(Children.create(new AutoIngestNodeChildren(monitor, status, eventBus), true)); + super(Children.create(new AutoIngestNodeChildren(monitor, status, eventBus), false)); refreshChildrenEventBus = eventBus; } From 3b078c34cb8459a8abf98409a5c138c99223eda5 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Tue, 31 Aug 2021 14:07:13 -0400 Subject: [PATCH 69/76] Added more allowed characters to profile names --- .../autopsy/commandlineingest/Bundle.properties-MERGED | 2 +- .../commandlineingest/CommandLineIngestSettingsPanel.java | 4 ++-- .../src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED | 2 +- Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties-MERGED index c760c4b1c8..84598e3756 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties-MERGED @@ -3,7 +3,7 @@ CommandLineIngestSettingPanel_existing_report_name_mgs=Report profile name was a CommandLineIngestSettingPanel_invalid_report_name_mgs=Report profile name contained illegal characters, no profile created. CommandListIngestSettingsPanel_Default_Report_DisplayName=Default CommandListIngestSettingsPanel_Make_Config=Make new profile... -CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (letters and digits only): +CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (letters, digits, and underscore characters only): OpenIDE-Module-Name=CommandLineAutopsy OptionsCategory_Keywords_Command_Line_Ingest_Settings=Command Line Ingest Settings OptionsCategory_Keywords_General=Options diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java index d4c7bd601e..531f96a878 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java @@ -280,7 +280,7 @@ public class CommandLineIngestSettingsPanel extends javax.swing.JPanel { add(nodePanel, java.awt.BorderLayout.CENTER); }// //GEN-END:initComponents @Messages({ - "CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (letters and digits only):", + "CommandListIngestSettingsPanel_Report_Name_Msg=Please supply a report profile name (letters, digits, and underscore characters only):", "CommandLineIngestSettingPanel_empty_report_name_mgs=Report profile name was empty, no profile created.", "CommandLineIngestSettingPanel_existing_report_name_mgs=Report profile name was already exists, no profile created.", "CommandLineIngestSettingPanel_invalid_report_name_mgs=Report profile name contained illegal characters, no profile created." @@ -302,7 +302,7 @@ public class CommandLineIngestSettingsPanel extends javax.swing.JPanel { } else { // sanitize report name String originalReportName = reportName; - reportName = reportName.replaceAll("[^A-Za-z0-9]", ""); + reportName = reportName.replaceAll("[^A-Za-z0-9_]", ""); if (reportName.isEmpty() || (!(originalReportName.equals(reportName)))) { // report name contained only invalid characters, display error JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), Bundle.CommandLineIngestSettingPanel_invalid_report_name_mgs()); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED index 3165583373..11fbd0a9d8 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED @@ -115,7 +115,7 @@ IngestJobSettingsPanel.jButtonSelectAll.text=Select All IngestJobSettingsPanel.jButtonDeselectAll.text=Deselect All IngestManager.cancellingIngest.msgDlg.text=Cancelling all currently running ingest jobs IngestManager.serviceIsDown.msgDlg.text={0} is down -ProfilePanel.messages.profileNameContainsIllegalCharacter=Profile name contains an illegal character. Only letters and digits are allowed. +ProfilePanel.messages.profileNameContainsIllegalCharacter=Profile name contains an illegal character. Only \nletters, digits, and underscore characters are allowed. ProfilePanel.messages.profilesMustBeNamed=Ingest profile must be named. ProfilePanel.newProfileText=NewEmptyProfile ProfilePanel.profileDescLabel.text=Description: diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index 543faa1b01..5efbb1bd4e 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -35,7 +35,7 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { "ProfilePanel.profileNameLabel.text=Profile Name:", "ProfilePanel.newProfileText=NewEmptyProfile", "ProfilePanel.messages.profilesMustBeNamed=Ingest profile must be named.", - "ProfilePanel.messages.profileNameContainsIllegalCharacter=Profile name contains an illegal character. Only letters and digits are allowed."}) + "ProfilePanel.messages.profileNameContainsIllegalCharacter=Profile name contains an illegal character. Only \nletters, digits, and underscore characters are allowed."}) private final IngestJobSettingsPanel ingestSettingsPanel; private final IngestJobSettings settings; @@ -257,7 +257,7 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { } // check if the name contains illegal characters - String sanitizedName = profileName.replaceAll("[^A-Za-z0-9]", ""); + String sanitizedName = profileName.replaceAll("[^A-Za-z0-9_]", ""); if (!(profileName.equals(sanitizedName))) { if (dispayWarnings) { NotifyDescriptor notifyDesc = new NotifyDescriptor.Message( From 4de91c38fc12fa6fea3223a03b2b0f77769f4f22 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 31 Aug 2021 16:21:36 -0400 Subject: [PATCH 70/76] First draft --- .../AnalysisResultsContentViewer.java | 65 ++++++++-------- .../AnalysisResultsViewModel.java | 76 +++++-------------- 2 files changed, 47 insertions(+), 94 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java index ef623f44cf..afe9387dd2 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java @@ -19,33 +19,28 @@ package org.sleuthkit.autopsy.contentviewers.analysisresults; import java.awt.Component; +import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.SwingWorker; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; +import org.sleuthkit.autopsy.datamodel.TskContentItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; -import org.sleuthkit.datamodel.AnalysisResult; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.datamodel.AnalysisResultItem; /** - * Displays a list of analysis results as a content viewer. + * A content viewer that displays the analysis results for a Content object. */ @ServiceProvider(service = DataContentViewer.class, position = 7) public class AnalysisResultsContentViewer implements DataContentViewer { private static final Logger logger = Logger.getLogger(AnalysisResultsContentPanel.class.getName()); - - // isPreferred value private static final int PREFERRED_VALUE = 3; - private final AnalysisResultsViewModel viewModel = new AnalysisResultsViewModel(); private final AnalysisResultsContentPanel panel = new AnalysisResultsContentPanel(); @@ -87,27 +82,35 @@ public class AnalysisResultsContentViewer implements DataContentViewer { "AnalysisResultsContentViewer_setNode_loadingMessage=Loading...", "AnalysisResultsContentViewer_setNode_errorMessage=There was an error loading results.",}) public synchronized void setNode(Node node) { - // reset the panel panel.reset(); - // if there is a worker running, cancel it if (worker != null) { worker.cancel(true); worker = null; } - // if no node, nothing to do if (node == null) { return; } + TskContentItem contentItem; + AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class); + if (Objects.nonNull(analysisResultItem)) { + + } else { + TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); + + } + + + // show a loading message panel.showMessage(Bundle.AnalysisResultsContentViewer_setNode_loadingMessage()); + TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); - // create the worker + worker = new DataFetchWorker<>( - // load a view model from the node - (selectedNode) -> viewModel.getAnalysisResults(selectedNode), + (selectedNode) -> viewModel.getAnalysisResults(node.getLookup().lookup(TskContentItem.class), node.getLookup().lookup(AnalysisResultItem.class), (nodeAnalysisResults) -> { if (nodeAnalysisResults.getResultType() == DataFetchResult.ResultType.SUCCESS) { // if successful, display the results @@ -125,34 +128,26 @@ public class AnalysisResultsContentViewer implements DataContentViewer { @Override public boolean isSupported(Node node) { - if (node == null) { + if (Objects.isNull(node)) { return false; } - // There needs to either be a file with an AnalysisResult or an AnalysisResult in the lookup. - for (Content content : node.getLookup().lookupAll(Content.class)) { - if (content instanceof AnalysisResult) { - return true; - } + AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class); + if (Objects.nonNull(analysisResultItem)) { + return true; + } + + TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); + if (Objects.isNull(contentItem)) { + return false; + } - if (content == null || content instanceof BlackboardArtifact) { - continue; - } - - try { - if (Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().hasAnalysisResults(content.getId())) { - return true; - } - } catch (NoCurrentCaseException | TskCoreException ex) { - logger.log(Level.SEVERE, "Unable to get analysis results for file with obj id " + content.getId(), ex); - } - } - - return false; + return (contentItem.getAnalyisisResults().isEmpty() == false); } @Override public int isPreferred(Node node) { return PREFERRED_VALUE; } + } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java index 03720e0cbe..7114d1f77b 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java @@ -30,7 +30,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; import org.openide.nodes.Node; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.datamodel.AnalysisResultItem; +import org.sleuthkit.autopsy.datamodel.TskContentItem; import org.sleuthkit.datamodel.AnalysisResult; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; @@ -94,7 +97,7 @@ public class AnalysisResultsViewModel { private final List analysisResults; private final Optional selectedResult; private final Optional aggregateScore; - private final Optional content; + private final Content content; /** * Constructor. @@ -105,7 +108,7 @@ public class AnalysisResultsViewModel { * @param aggregateScore The aggregate score or empty if no score. * @param content The content associated with these results. */ - NodeResults(List analysisResults, Optional selectedResult, Optional aggregateScore, Optional content) { + NodeResults(List analysisResults, Optional selectedResult, Optional aggregateScore, Content content) { this.analysisResults = analysisResults; this.selectedResult = selectedResult; this.aggregateScore = aggregateScore; @@ -146,7 +149,7 @@ public class AnalysisResultsViewModel { * @return The content associated with these results or empty if not * present. */ - Optional getContent() { + Content getContent() { return content; } } @@ -226,6 +229,8 @@ public class AnalysisResultsViewModel { } /** + * RJCTODO + * * Returns the view model data representing the analysis results to be * displayed for the node. * @@ -233,63 +238,16 @@ public class AnalysisResultsViewModel { * * @return The analysis results view model data to display. */ - NodeResults getAnalysisResults(Node node) { - if (node == null) { - return new NodeResults(Collections.emptyList(), Optional.empty(), Optional.empty(), Optional.empty()); - } - + NodeResults getAnalysisResults(TskContentItem contentItem, Optional selectedResult) { + Content content = contentItem.getTskContent(); Optional aggregateScore = Optional.empty(); - Optional nodeContent = Optional.empty(); - // maps id of analysis result to analysis result to prevent duplication - Map allAnalysisResults = new HashMap<>(); - Optional selectedResult = Optional.empty(); - - // Find first content that is not an artifact within node - for (Content content : node.getLookup().lookupAll(Content.class)) { - if (content == null || content instanceof BlackboardArtifact) { - continue; - } - - try { - nodeContent = Optional.of(content); - - // get the aggregate score of that content - aggregateScore = Optional.ofNullable(content.getAggregateScore()); - - // and add all analysis results to mapping - content.getAllAnalysisResults().stream() - .forEach((ar) -> allAnalysisResults.put(ar.getArtifactID(), ar)); - - break; - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Unable to get analysis results for content with obj id " + content.getId(), ex); - } + try { + aggregateScore = Optional.ofNullable(content.getAggregateScore()); + + } catch (TskCoreException ex) { + // RJCTODO: log error } - - // Find any analysis results in the node - Collection analysisResults = node.getLookup().lookupAll(AnalysisResult.class); - if (analysisResults.size() > 0) { - - // get any items with a score - List filteredResults = analysisResults.stream() - .collect(Collectors.toList()); - - // add them to the map to display - filteredResults.forEach((ar) -> allAnalysisResults.put(ar.getArtifactID(), ar)); - - // the selected result will be the highest scored analysis result in the node. - selectedResult = filteredResults.stream() - .max((a, b) -> a.getScore().compareTo(b.getScore())); - - // if no aggregate score determined at this point, use the selected result score. - if (!aggregateScore.isPresent()) { - aggregateScore = selectedResult.flatMap(selectedRes -> Optional.ofNullable(selectedRes.getScore())); - } - } - - // get view model representation - List displayAttributes = getOrderedDisplayAttributes(allAnalysisResults.values()); - - return new NodeResults(displayAttributes, selectedResult, aggregateScore, nodeContent); + List displayAttributes = getOrderedDisplayAttributes(contentItem.getAnalyisisResults());; + return new NodeResults(displayAttributes, selectedResult, aggregateScore, content); } } From 93c87cf7ceabc20108ce04370b65a1343e56226d Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 1 Sep 2021 12:37:26 -0400 Subject: [PATCH 71/76] 7861 Make analysis results content viewer work for data artifacts --- .../autopsy/datamodel/AnalysisResultItem.java | 51 +++++++++++++++++ .../autopsy/datamodel/TskContentItem.java | 56 +++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100755 Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java create mode 100755 Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java new file mode 100755 index 0000000000..442d070f5c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java @@ -0,0 +1,51 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021-2021 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 com.google.common.annotations.Beta; +import org.sleuthkit.datamodel.AnalysisResult; + +/** + * An Autopsy Data Model item with an underlying analysis result Sleuth Kit Data + * Model object. + */ +public class AnalysisResultItem extends TskContentItem { + + /** + * Constructs an Autopsy Data Model item with an underlying AnalysisResult + * Sleuth Kit Data Model object. + * + * @param analysisResult The analysis result. + */ + @Beta + AnalysisResultItem(AnalysisResult analysisResult) { + super(analysisResult); + } + + /** + * Gets the underlying analysis result. + * + * @return The analysis result. + */ + @Beta + public AnalysisResult getAnalysisResult() { + return (AnalysisResult) (getTskContent()); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java b/Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java new file mode 100755 index 0000000000..999474cc1d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java @@ -0,0 +1,56 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021-2021 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 com.google.common.annotations.Beta; +import org.sleuthkit.datamodel.Content; + +/** + * An Autopsy Data Model item with an underlying Sleuth Kit Data Model object + * that implements the Sleuth Kit Data Model's Content interface. + */ +@Beta +public class TskContentItem { + + private final Content tskContent; + + /** + * Constructs an Autopsy Data Model item with an underlying Sleuth Kit Data + * Model object that implements the Sleuth Kit Data Model's Content + * interface. + * + * @param content The underlying Sleuth Kit Data Model object. + * + */ + @Beta + TskContentItem(Content sleuthKitContent) { + this.tskContent = sleuthKitContent; + } + + /** + * Gets the underlying Sleuth Kit Data Model object. + * + * @return The Sleuth Kit Data Model object. + */ + @Beta + public Content getTskContent() { + return tskContent; + } + +} From eabef9175d51462adf502991ab8888e7d178eab3 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 1 Sep 2021 16:28:11 -0400 Subject: [PATCH 72/76] 7861 Make analysis results content viewer work for data artifacts --- .../AnalysisResultsContentViewer.java | 44 +++--- .../AnalysisResultsViewModel.java | 71 +++++++--- .../datamodel/AbstractContentNode.java | 2 +- .../datamodel/BlackboardArtifactNode.java | 128 ++++++++++-------- 4 files changed, 141 insertions(+), 104 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java index afe9387dd2..b056eb11db 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java @@ -26,12 +26,15 @@ import javax.swing.SwingWorker; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.datamodel.TskContentItem; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; import org.sleuthkit.datamodel.Content; import org.sleuthkit.autopsy.datamodel.AnalysisResultItem; +import org.sleuthkit.datamodel.TskCoreException; /** * A content viewer that displays the analysis results for a Content object. @@ -82,35 +85,27 @@ public class AnalysisResultsContentViewer implements DataContentViewer { "AnalysisResultsContentViewer_setNode_loadingMessage=Loading...", "AnalysisResultsContentViewer_setNode_errorMessage=There was an error loading results.",}) public synchronized void setNode(Node node) { + // reset the panel panel.reset(); + // if there is a worker running, cancel it if (worker != null) { worker.cancel(true); worker = null; } + // if no node, nothing to do if (node == null) { return; } - TskContentItem contentItem; - AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class); - if (Objects.nonNull(analysisResultItem)) { - - } else { - TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); - - } - - - // show a loading message panel.showMessage(Bundle.AnalysisResultsContentViewer_setNode_loadingMessage()); - TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); - + // create the worker worker = new DataFetchWorker<>( - (selectedNode) -> viewModel.getAnalysisResults(node.getLookup().lookup(TskContentItem.class), node.getLookup().lookup(AnalysisResultItem.class), + // load a view model from the node + (selectedNode) -> viewModel.getAnalysisResults(selectedNode), (nodeAnalysisResults) -> { if (nodeAnalysisResults.getResultType() == DataFetchResult.ResultType.SUCCESS) { // if successful, display the results @@ -135,14 +130,21 @@ public class AnalysisResultsContentViewer implements DataContentViewer { AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class); if (Objects.nonNull(analysisResultItem)) { return true; - } - - TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); - if (Objects.isNull(contentItem)) { - return false; - } + } - return (contentItem.getAnalyisisResults().isEmpty() == false); + TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); + if (!Objects.isNull(contentItem)) { + Content content = contentItem.getTskContent(); + try { + if (Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().hasAnalysisResults(content.getId())) { + return true; + } + } catch (NoCurrentCaseException | TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error getting analysis results for Content (object ID = %d)", content.getId()), ex); + } + } + + return false; } @Override diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java index 7114d1f77b..508c9966fe 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java @@ -20,9 +20,8 @@ package org.sleuthkit.autopsy.contentviewers.analysisresults; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; @@ -30,18 +29,15 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; import org.openide.nodes.Node; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.datamodel.AnalysisResultItem; import org.sleuthkit.autopsy.datamodel.TskContentItem; import org.sleuthkit.datamodel.AnalysisResult; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Score; import org.sleuthkit.datamodel.TskCoreException; /** - * * Creates a representation of a list of analysis results gathered from a node. */ public class AnalysisResultsViewModel { @@ -75,7 +71,7 @@ public class AnalysisResultsViewModel { * @return The attributes to display. */ List> getAttributesToDisplay() { - return attributesToDisplay; + return Collections.unmodifiableList(attributesToDisplay); } /** @@ -97,7 +93,7 @@ public class AnalysisResultsViewModel { private final List analysisResults; private final Optional selectedResult; private final Optional aggregateScore; - private final Content content; + private final Optional content; /** * Constructor. @@ -108,7 +104,7 @@ public class AnalysisResultsViewModel { * @param aggregateScore The aggregate score or empty if no score. * @param content The content associated with these results. */ - NodeResults(List analysisResults, Optional selectedResult, Optional aggregateScore, Content content) { + NodeResults(List analysisResults, Optional selectedResult, Optional aggregateScore, Optional content) { this.analysisResults = analysisResults; this.selectedResult = selectedResult; this.aggregateScore = aggregateScore; @@ -121,7 +117,7 @@ public class AnalysisResultsViewModel { * @return The analysis results to be displayed. */ List getAnalysisResults() { - return analysisResults; + return Collections.unmodifiableList(analysisResults); } /** @@ -149,7 +145,7 @@ public class AnalysisResultsViewModel { * @return The content associated with these results or empty if not * present. */ - Content getContent() { + Optional getContent() { return content; } } @@ -229,8 +225,6 @@ public class AnalysisResultsViewModel { } /** - * RJCTODO - * * Returns the view model data representing the analysis results to be * displayed for the node. * @@ -238,16 +232,49 @@ public class AnalysisResultsViewModel { * * @return The analysis results view model data to display. */ - NodeResults getAnalysisResults(TskContentItem contentItem, Optional selectedResult) { - Content content = contentItem.getTskContent(); - Optional aggregateScore = Optional.empty(); - try { - aggregateScore = Optional.ofNullable(content.getAggregateScore()); - - } catch (TskCoreException ex) { - // RJCTODO: log error + NodeResults getAnalysisResults(Node node) { + if (node == null) { + return new NodeResults(Collections.emptyList(), Optional.empty(), Optional.empty(), Optional.empty()); } - List displayAttributes = getOrderedDisplayAttributes(contentItem.getAnalyisisResults());; - return new NodeResults(displayAttributes, selectedResult, aggregateScore, content); + + Content analyzedContent = null; + AnalysisResult selectedAnalysisResult = null; + Score aggregateScore = null; + List analysisResults = Collections.emptyList(); + long selectedObjectId = 0; + try { + AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class); + if (Objects.nonNull(analysisResultItem)) { + /* + * The content represented by the Node is an analysis result. + * Set this analysis result as the analysis result to be + * selected in the content viewer and get the analyzed content + * as the source of the analysis results to display. + */ + selectedAnalysisResult = analysisResultItem.getAnalysisResult(); + selectedObjectId = selectedAnalysisResult.getId(); + analyzedContent = selectedAnalysisResult.getParent(); + } else { + /* + * The content represented by the Node is something other than + * an analysis result. Use it as the source of the analysis + * results to display. + */ + TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); + analyzedContent = contentItem.getTskContent(); + selectedObjectId = analyzedContent.getId(); + } + aggregateScore = analyzedContent.getAggregateScore(); + analysisResults = analyzedContent.getAllAnalysisResults(); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error get analysis result data for selected Content (object ID=%d)", selectedObjectId), ex); + } + + /* + * Use the data collected above to construct the view model. + */ + List displayAttributes = getOrderedDisplayAttributes(analysisResults); + return new NodeResults(displayAttributes, Optional.ofNullable(selectedAnalysisResult), Optional.ofNullable(aggregateScore), Optional.ofNullable(analyzedContent)); } + } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java index 0a43d47102..daf8cd84da 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java @@ -102,7 +102,7 @@ public abstract class AbstractContentNode extends ContentNode * @param content Underlying Content instances */ AbstractContentNode(T content) { - this(content, Lookups.singleton(content)); + this(content, Lookups.fixed(content, new TskContentItem(content))); } /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index e3bad44705..bf57a00caa 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -84,8 +84,8 @@ import org.sleuthkit.datamodel.BlackboardArtifact.Category; import org.sleuthkit.datamodel.Score; /** - * A BlackboardArtifactNode is an AbstractNode implementation that can be used - * to represent an artifact of any type. + * An AbstractNode implementation that can be used to represent an data artifact + * or analysis result of any type. */ public class BlackboardArtifactNode extends AbstractContentNode { @@ -219,17 +219,20 @@ public class BlackboardArtifactNode extends AbstractContentNode artifact.getSleuthkitCase().getContentById(objectID)); - if (content == null) { - return Lookups.fixed(artifact); + if (useAssociatedFile) { + content = getPathIdFile(artifact); } else { - return Lookups.fixed(artifact, content); + long srcObjectID = artifact.getObjectID(); + content = contentCache.get(srcObjectID, () -> artifact.getSleuthkitCase().getContentById(srcObjectID)); } } catch (ExecutionException ex) { - logger.log(Level.SEVERE, MessageFormat.format("Error getting source content (artifact objID={0}", artifact.getId()), ex); //NON-NLS - return Lookups.fixed(artifact); + logger.log(Level.SEVERE, MessageFormat.format("Error getting source/associated content (artifact object ID={0})", artifact.getId()), ex); //NON-NLS } - } - /** - * Creates a Lookup object for this node and populates it with both the - * artifact this node represents and its source content. - * - * @param artifact The artifact this node represents. - * @param lookupIsAssociatedFile True if the Content lookup should be made - * for the associated file instead of the - * parent file. - * - * @return The Lookup. - */ - private static Lookup createLookup(BlackboardArtifact artifact, boolean lookupIsAssociatedFile) { - Content content = null; - if (lookupIsAssociatedFile) { - try { - content = getPathIdFile(artifact); - } catch (ExecutionException ex) { - logger.log(Level.SEVERE, MessageFormat.format("Error getting source content (artifact objID={0}", artifact.getId()), ex); //NON-NLS - content = null; - } - if (content == null) { - return Lookups.fixed(artifact); - } else { - return Lookups.fixed(artifact, content); - } + /* + * Make an Autopsy Data Model wrapper for the artifact. + * + * NOTE: The creation of an Autopsy Data Model independent of the + * NetBeans nodes is a work in progress. At the time this comment is + * being written, this object is only used by the analysis content + * viewer. + */ + TskContentItem artifactItem; + if (artifact instanceof AnalysisResult) { + artifactItem = new AnalysisResultItem((AnalysisResult) artifact); } else { - return createLookup(artifact); + artifactItem = new TskContentItem(artifact); } + /* + * Create the Lookup. + */ + if (content == null) { + return Lookups.fixed(artifact, artifactItem); + } else { + return Lookups.fixed(artifact, artifactItem, content); + } } /** @@ -447,10 +455,10 @@ public class BlackboardArtifactNode extends AbstractContentNode Date: Wed, 1 Sep 2021 16:44:55 -0400 Subject: [PATCH 73/76] 7932 fix method doc for DisplayableItemNode.java --- .../src/org/sleuthkit/autopsy/datamodel/DisplayableItemNode.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNode.java index c6bc88129a..6edba5db30 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNode.java @@ -99,6 +99,7 @@ public abstract class DisplayableItemNode extends AbstractNode { * operation on this artifact type and return some object as the result of * the operation. * + * @param The return type. * @param visitor The visitor, where the type parameter of the visitor is * the type of the object that will be returned as the result * of the visit operation. From 5c205e0e5e193d7714a0259e0ca10d76e2192386 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 1 Sep 2021 16:58:59 -0400 Subject: [PATCH 74/76] 7861 Make analysis results content viewer work for data artifacts --- .../analysisresults/AnalysisResultsViewModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java index 508c9966fe..37e4114168 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java @@ -267,7 +267,7 @@ public class AnalysisResultsViewModel { aggregateScore = analyzedContent.getAggregateScore(); analysisResults = analyzedContent.getAllAnalysisResults(); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, String.format("Error get analysis result data for selected Content (object ID=%d)", selectedObjectId), ex); + logger.log(Level.SEVERE, String.format("Error getting analysis result data for selected Content (object ID=%d)", selectedObjectId), ex); } /* From 417c432a216e8a9d7ab9044feda5eac05ddb90d7 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 3 Sep 2021 12:46:17 -0400 Subject: [PATCH 75/76] 7963 format IngestEventsListener.java --- .../eventlisteners/IngestEventsListener.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 7aa229949e..04275f0e98 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -70,6 +70,7 @@ import org.sleuthkit.datamodel.Score; */ @NbBundle.Messages({"IngestEventsListener.ingestmodule.name=Central Repository"}) public class IngestEventsListener { + private static final Logger LOGGER = Logger.getLogger(CorrelationAttributeInstance.class.getName()); private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED); private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(DATA_ADDED); @@ -246,15 +247,15 @@ public class IngestEventsListener { originalArtifact.getArtifactID())); makeAndPostInterestingArtifact(originalArtifact, attributesForNewArtifact, Bundle.IngestEventsListener_prevExists_text()); } - - + /** * Make an interesting item artifact to flag the passed in artifact. * * @param originalArtifact Artifact in current case we want to flag * @param attributesForNewArtifact Attributes to assign to the new * Interesting items artifact - * @param configuration The configuration to be specified for the new interesting artifact hit + * @param configuration The configuration to be specified for the + * new interesting artifact hit */ private static void makeAndPostInterestingArtifact(BlackboardArtifact originalArtifact, Collection attributesForNewArtifact, String configuration) { try { @@ -263,8 +264,8 @@ public class IngestEventsListener { Blackboard blackboard = tskCase.getBlackboard(); // Create artifact if it doesn't already exist. if (!blackboard.artifactExists(abstractFile, TSK_INTERESTING_ARTIFACT_HIT, attributesForNewArtifact)) { - BlackboardArtifact newInterestingArtifact = abstractFile.newAnalysisResult( - BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, Score.SCORE_LIKELY_NOTABLE, + BlackboardArtifact newInterestingArtifact = abstractFile.newAnalysisResult( + BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, Score.SCORE_LIKELY_NOTABLE, null, configuration, null, attributesForNewArtifact) .getAnalysisResult(); @@ -368,8 +369,8 @@ public class IngestEventsListener { try { dataSource = ((DataSourceAnalysisEvent) event).getDataSource(); /* - * We only care about Images for the purpose of - * updating hash values. + * We only care about Images for the purpose of updating hash + * values. */ if (!(dataSource instanceof Image)) { return; From da84ce0e94d1276f87a346c2806b01d3fa1d531d Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Tue, 7 Sep 2021 16:49:51 -0400 Subject: [PATCH 76/76] Minor --- .../autopsy/centralrepository/ingestmodule/Bundle_ja.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle_ja.properties index 47b5abd4ec..1899d309b9 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle_ja.properties @@ -13,4 +13,3 @@ IngestSettingsPanel.createCorrelationPropertiesCheckbox.text=\u30a2\u30a4\u30c6\ IngestSettingsPanel.flagPreviouslySeenDevicesCheckbox.text=\u4ee5\u524d\u306e\u30b1\u30fc\u30b9\u3067\u898b\u3089\u308c\u305f\u30c7\u30d0\u30a4\u30b9\u306b\u30d5\u30e9\u30b0\u3092\u4ed8\u3051\u308b IngestSettingsPanel.flagTaggedNotableItemsCheckbox.text=\u4ee5\u524d\u306b\u6ce8\u76ee\u3059\u3079\u304d\u30bf\u30b0\u4ed8\u3051\u305f\u30a2\u30a4\u30c6\u30e0\u306b\u30d5\u30e9\u30b0\u3092\u4ed8\u3051\u308b IngestSettingsPanel.ingestSettingsLabel.text=\u53d6\u8fbc\u307f\u8a2d\u5b9a -IngestSettingsPanel.flagUniqueAppsCheckbox.text=\u4ee5\u524d\u306e\u30b1\u30fc\u30b9\u3067\u898b\u3089\u308c\u305f\u30c7\u30d0\u30a4\u30b9\u306b\u30d5\u30e9\u30b0\u3092\u4ed8\u3051\u308b