From af304223db4f536af74494ac72ed9e513068ec81 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 4 Sep 2020 10:17:59 -0400 Subject: [PATCH 1/8] datamodel service --- .../datamodel/DataSourceInfoUtilities.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java index 9a60bd17e7..da02cb087b 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceInfoUtilities.java @@ -35,6 +35,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.datamodel.BlackboardAttribute.Type; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskData.TSK_FS_META_FLAG_ENUM; @@ -357,4 +358,36 @@ final class DataSourceInfoUtilities { } } } + + + /** + * Retrieves attribute from artifact if exists. Returns null if attribute is + * null or underlying call throws exception. + * + * @param artifact The artifact. + * @param attributeType The attribute type to retrieve from the artifact. + * + * @return The attribute or null if could not be received. + */ + private static BlackboardAttribute getAttributeOrNull(BlackboardArtifact artifact, Type attributeType) { + try { + return artifact.getAttribute(attributeType); + } catch (TskCoreException ex) { + return null; + } + } + + /** + * Retrieves the string value of a certain attribute type from an artifact. + * + * @param artifact The artifact. + * @param attributeType The attribute type. + * + * @return The 'getValueString()' value or null if the attribute or String + * could not be retrieved. + */ + static String getStringOrNull(BlackboardArtifact artifact, Type attributeType) { + BlackboardAttribute attr = getAttributeOrNull(artifact, attributeType); + return (attr == null) ? null : attr.getValueString(); + } } From 837f4a47ec5ab7b51973af865230e8b053d38382 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 4 Sep 2020 10:18:10 -0400 Subject: [PATCH 2/8] datamodel service --- .../datamodel/DataSourceAnalysisSummary.java | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java new file mode 100644 index 0000000000..a42a46b56e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.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.ArrayList; +import java.util.List; +import java.util.Map; +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.coreutils.Logger; +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; +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. + */ +public class DataSourceAnalysisSummary { + private static final BlackboardAttribute.Type TYPE_SET_NAME = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME); + + private final java.util.logging.Logger logger; + private final SleuthkitCaseProvider provider; + + public DataSourceAnalysisSummary() { + this(Logger.getLogger(DataSourceAnalysisSummary.class.getName()), SleuthkitCaseProvider.DEFAULT); + } + + public DataSourceAnalysisSummary(java.util.logging.Logger logger, SleuthkitCaseProvider provider) { + this.logger = logger; + this.provider = provider; + } + + public List> getHashsetCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { + return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_HASHSET_HIT); + } + + public List> getKeywordCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { + return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT); + } + + 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); + } + + private List> getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes) throws SleuthkitCaseProviderException, TskCoreException { + List artifacts = new ArrayList<>(); + SleuthkitCase skCase = provider.get(); + + for (ARTIFACT_TYPE type : artifactTypes) { + artifacts.addAll(skCase.getBlackboard().getArtifacts(type.getTypeID(), dataSource.getId())); + } + + Map countedKeys = artifacts.stream() + .map((art) -> { + String key = DataSourceInfoUtilities.getStringOrNull(art, keyType); + return (StringUtils.isBlank(key)) ? null : key; + }) + .filter((key) -> key != null) + .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); + + return countedKeys.entrySet().stream() + .map((e) -> Pair.of(e.getKey(), e.getValue())) + .sorted((a,b) -> -a.getValue().compareTo(b.getValue())) + .collect(Collectors.toList()); + } +} From 5c31586f461b80ae7c81c9c2faf2e6db2a7b1954 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Sep 2020 08:35:29 -0400 Subject: [PATCH 3/8] created analysis summary tab --- .../sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties index 350daeb57e..26c7055a75 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties @@ -32,3 +32,6 @@ DataSourceSummaryCountsPanel.byCategoryLabel.text=Files by Category DataSourceSummaryCountsPanel.resultsByTypeLabel.text=Results by Type DataSourceSummaryUserActivityPanel.programsRunLabel.text=Recent Programs DataSourceSummaryUserActivityPanel.recentDomainsLabel.text=Recent Domains +AnalysisPanel.hashsetHitsLabel.text=Hashset Hits +AnalysisPanel.keywordHitsLabel.text=Keyword Hits +AnalysisPanel.interestingItemLabel.text=Interesting Item Hits From 122b51f9f1a824a392130128068ee84809a93d35 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Sep 2020 08:35:36 -0400 Subject: [PATCH 4/8] created analysis summary tab --- .../datasourcesummary/ui/AnalysisPanel.form | 260 ++++++++++++++++++ .../datasourcesummary/ui/AnalysisPanel.java | 200 ++++++++++++++ 2 files changed, 460 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form new file mode 100644 index 0000000000..dd8ae51623 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form @@ -0,0 +1,260 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java new file mode 100644 index 0000000000..f1b1483deb --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -0,0 +1,200 @@ +/* + * 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.ui; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.apache.commons.lang3.tuple.Pair; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourceAnalysisSummary; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.ColumnModel; +import org.sleuthkit.datamodel.DataSource; + +/** + * A tab shown in data source summary displaying hash set hits, keyword hits, + * and interesting item hits within a datasource. + */ +@Messages({ + "AnalysisPanel_keyColumn_title=Name", + "AnalysisPanel_countColumn_title=Count" +}) +public class AnalysisPanel extends BaseDataSourceSummaryPanel { + + private static final long serialVersionUID = 1L; + + private static final ColumnModel> KEY_COL = new ColumnModel<>( + Bundle.AnalysisPanel_keyColumn_title(), + (pair) -> new DefaultCellModel(pair.getKey()), + 300 + ); + + private static final ColumnModel> COUNT_COL = new ColumnModel<>( + Bundle.AnalysisPanel_countColumn_title(), + (pair) -> new DefaultCellModel(String.valueOf(pair.getValue())), + 100 + ); + + private static final List>> DEFAULT_COLUMNS = Arrays.asList(KEY_COL, COUNT_COL); + + private final JTablePanel> hashsetHitsTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS); + + private final JTablePanel> keywordHitsTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS); + + private final JTablePanel> interestingItemsTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS); + + private final List> tables = Arrays.asList( + hashsetHitsTable, + keywordHitsTable, + interestingItemsTable + ); + + private final List> dataFetchComponents; + + /** + * Creates a new DataSourceUserActivityPanel. + */ + public AnalysisPanel() { + this(new DataSourceAnalysisSummary()); + } + + public AnalysisPanel(DataSourceAnalysisSummary analysisData) { + // set up data acquisition methods + dataFetchComponents = Arrays.asList( + // hashset hits loading components + new DataFetchWorker.DataFetchComponents<>( + (dataSource) -> analysisData.getHashsetCounts(dataSource), + (result) -> hashsetHitsTable.showDataFetchResult(result)), + // keyword hits loading components + new DataFetchWorker.DataFetchComponents<>( + (dataSource) -> analysisData.getKeywordCounts(dataSource), + (result) -> keywordHitsTable.showDataFetchResult(result)), + // interesting item hits loading components + new DataFetchWorker.DataFetchComponents<>( + (dataSource) -> analysisData.getInterestingItemCounts(dataSource), + (result) -> interestingItemsTable.showDataFetchResult(result)) + ); + + initComponents(); + } + + @Override + protected void onNewDataSource(DataSource dataSource) { + // if no data source is present or the case is not open, + // set results for tables to null. + if (dataSource == null || !Case.isCaseOpen()) { + this.dataFetchComponents.forEach((item) -> item.getResultHandler() + .accept(DataFetchResult.getSuccessResult(null))); + + } else { + // set tables to display loading screen + this.tables.forEach((table) -> table.showDefaultLoadingMessage()); + + // create swing workers to run for each table + List> workers = dataFetchComponents + .stream() + .map((components) -> new DataFetchWorker<>(components, dataSource)) + .collect(Collectors.toList()); + + // submit swing workers to run + submit(workers); + } + } + + /** + * 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.JLabel hashsetHitsLabel = 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(32767, 2)); + javax.swing.JPanel hashSetHitsPanel = hashsetHitsTable; + 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(32767, 20)); + javax.swing.JLabel keywordHitsLabel = new javax.swing.JLabel(); + javax.swing.Box.Filler filler4 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(32767, 2)); + javax.swing.JPanel keywordHitsPanel = keywordHitsTable; + javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(32767, 20)); + javax.swing.JLabel interestingItemLabel = new javax.swing.JLabel(); + javax.swing.Box.Filler filler6 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(32767, 2)); + javax.swing.JPanel interestingItemPanel = interestingItemsTable; + javax.swing.Box.Filler filler3 = 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.setMaximumSize(new java.awt.Dimension(32767, 452)); + mainContentPanel.setMinimumSize(new java.awt.Dimension(200, 452)); + mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS)); + + org.openide.awt.Mnemonics.setLocalizedText(hashsetHitsLabel, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.hashsetHitsLabel.text")); // NOI18N + mainContentPanel.add(hashsetHitsLabel); + mainContentPanel.add(filler1); + + hashSetHitsPanel.setMaximumSize(new java.awt.Dimension(32767, 106)); + hashSetHitsPanel.setMinimumSize(new java.awt.Dimension(10, 106)); + hashSetHitsPanel.setPreferredSize(new java.awt.Dimension(32767, 106)); + mainContentPanel.add(hashSetHitsPanel); + mainContentPanel.add(filler2); + + org.openide.awt.Mnemonics.setLocalizedText(keywordHitsLabel, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.keywordHitsLabel.text")); // NOI18N + mainContentPanel.add(keywordHitsLabel); + mainContentPanel.add(filler4); + + keywordHitsPanel.setMaximumSize(new java.awt.Dimension(32767, 106)); + keywordHitsPanel.setMinimumSize(new java.awt.Dimension(10, 106)); + keywordHitsPanel.setPreferredSize(new java.awt.Dimension(32767, 106)); + mainContentPanel.add(keywordHitsPanel); + mainContentPanel.add(filler5); + + org.openide.awt.Mnemonics.setLocalizedText(interestingItemLabel, org.openide.util.NbBundle.getMessage(AnalysisPanel.class, "AnalysisPanel.interestingItemLabel.text")); // NOI18N + mainContentPanel.add(interestingItemLabel); + mainContentPanel.add(filler6); + + interestingItemPanel.setMaximumSize(new java.awt.Dimension(32767, 106)); + interestingItemPanel.setMinimumSize(new java.awt.Dimension(10, 106)); + interestingItemPanel.setPreferredSize(new java.awt.Dimension(32767, 106)); + mainContentPanel.add(interestingItemPanel); + mainContentPanel.add(filler3); + + 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, 756, 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 + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables +} From d7f7e1f986b5749fd1d7d4c53316671d01c0214b Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Sep 2020 13:11:05 -0400 Subject: [PATCH 5/8] bug fixes --- .../autopsy/datasourcesummary/ui/AnalysisPanel.form | 9 ++++++--- .../autopsy/datasourcesummary/ui/AnalysisPanel.java | 9 ++++++--- .../datasourcesummary/ui/Bundle.properties-MERGED | 6 ++++++ .../ui/DataSourceSummaryTabbedPane.java | 6 ++++-- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form index dd8ae51623..4016b539a7 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.form @@ -88,6 +88,7 @@ + @@ -95,7 +96,7 @@ - + @@ -155,6 +156,7 @@ + @@ -162,7 +164,7 @@ - + @@ -222,6 +224,7 @@ + @@ -229,7 +232,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index f1b1483deb..8f8698316a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -155,9 +155,10 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { mainContentPanel.add(hashsetHitsLabel); mainContentPanel.add(filler1); + hashSetHitsPanel.setAlignmentX(0.0F); hashSetHitsPanel.setMaximumSize(new java.awt.Dimension(32767, 106)); hashSetHitsPanel.setMinimumSize(new java.awt.Dimension(10, 106)); - hashSetHitsPanel.setPreferredSize(new java.awt.Dimension(32767, 106)); + hashSetHitsPanel.setPreferredSize(new java.awt.Dimension(10, 106)); mainContentPanel.add(hashSetHitsPanel); mainContentPanel.add(filler2); @@ -165,9 +166,10 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { mainContentPanel.add(keywordHitsLabel); mainContentPanel.add(filler4); + keywordHitsPanel.setAlignmentX(0.0F); keywordHitsPanel.setMaximumSize(new java.awt.Dimension(32767, 106)); keywordHitsPanel.setMinimumSize(new java.awt.Dimension(10, 106)); - keywordHitsPanel.setPreferredSize(new java.awt.Dimension(32767, 106)); + keywordHitsPanel.setPreferredSize(new java.awt.Dimension(10, 106)); mainContentPanel.add(keywordHitsPanel); mainContentPanel.add(filler5); @@ -175,9 +177,10 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { mainContentPanel.add(interestingItemLabel); mainContentPanel.add(filler6); + interestingItemPanel.setAlignmentX(0.0F); interestingItemPanel.setMaximumSize(new java.awt.Dimension(32767, 106)); interestingItemPanel.setMinimumSize(new java.awt.Dimension(10, 106)); - interestingItemPanel.setPreferredSize(new java.awt.Dimension(32767, 106)); + interestingItemPanel.setPreferredSize(new java.awt.Dimension(10, 106)); mainContentPanel.add(interestingItemPanel); mainContentPanel.add(filler3); 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 bd71f58f9c..f3325f2e46 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -1,3 +1,5 @@ +AnalysisPanel_countColumn_title=Count +AnalysisPanel_keyColumn_title=Name CTL_DataSourceSummaryAction=Data Source Summary DataSourceSummaryCountsPanel.ArtifactCountsTableModel.count.header=Count DataSourceSummaryCountsPanel.ArtifactCountsTableModel.type.header=Result Type @@ -64,6 +66,7 @@ DataSourceSummaryNode.column.status.header=Ingest Status DataSourceSummaryNode.column.tags.header=Tags DataSourceSummaryNode.column.type.header=Type DataSourceSummaryNode.viewDataSourceAction.text=Go to Data Source +DataSourceSummaryTabbedPane_analysisTab_title=Analysis DataSourceSummaryTabbedPane_countsTab_title=Counts DataSourceSummaryTabbedPane_detailsTab_title=Container DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History @@ -74,6 +77,9 @@ DataSourceSummaryUserActivityPanel.recentAccountsLabel.text=Recent Accounts DataSourceSummaryUserActivityPanel.topWebSearchLabel.text=Recent Web Searches DataSourceSummaryUserActivityPanel.topDevicesAttachedLabel.text=Recent Devices Attached DataSourceSummaryUserActivityPanel.recentDomainsLabel.text=Recent Domains +AnalysisPanel.hashsetHitsLabel.text=Hashset Hits +AnalysisPanel.keywordHitsLabel.text=Keyword Hits +AnalysisPanel.interestingItemLabel.text=Interesting Item Hits DataSourceSummaryUserActivityPanel_noDataExists=No communication data exists DataSourceSummaryUserActivityPanel_tab_title=User Activity DataSourceSummaryUserActivityPanel_TopAccountTableModel_accountType_header=Account Type diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java index 047af1cdd9..9696f4d4c4 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java @@ -37,7 +37,8 @@ import org.sleuthkit.datamodel.DataSource; "DataSourceSummaryTabbedPane_detailsTab_title=Container", "DataSourceSummaryTabbedPane_userActivityTab_title=User Activity", "DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History", - "DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files" + "DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files", + "DataSourceSummaryTabbedPane_analysisTab_title=Analysis" }) public class DataSourceSummaryTabbedPane extends JTabbedPane { @@ -47,7 +48,8 @@ public class DataSourceSummaryTabbedPane extends JTabbedPane { private final List> tabs = new ArrayList<>(Arrays.asList( Pair.of(Bundle.DataSourceSummaryTabbedPane_countsTab_title(), new DataSourceSummaryCountsPanel()), Pair.of(Bundle.DataSourceSummaryTabbedPane_userActivityTab_title(), new DataSourceSummaryUserActivityPanel()), - Pair.of(Bundle.DataSourceSummaryTabbedPane_recentFileTab_title(), new RecentFilesPanel()) + Pair.of(Bundle.DataSourceSummaryTabbedPane_recentFileTab_title(), new RecentFilesPanel()), + Pair.of(Bundle.DataSourceSummaryTabbedPane_analysisTab_title(), new AnalysisPanel()) )); private final IngestJobInfoPanel ingestHistoryPanel = new IngestJobInfoPanel(); From 0726c1d55c2a1a5ec065067faabf1819247e9991 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Sep 2020 15:05:01 -0400 Subject: [PATCH 6/8] commenting and formatting --- .../datamodel/DataSourceAnalysisSummary.java | 103 +++++++++++++++--- .../datasourcesummary/ui/AnalysisPanel.java | 30 +++-- 2 files changed, 105 insertions(+), 28 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java index a42a46b56e..e15c1f98f7 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java @@ -19,13 +19,15 @@ package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; 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.coreutils.Logger; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; @@ -39,40 +41,109 @@ import org.sleuthkit.datamodel.TskCoreException; * Providing data for the data source analysis tab. */ public class DataSourceAnalysisSummary { + private static final BlackboardAttribute.Type TYPE_SET_NAME = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME); - - private final java.util.logging.Logger logger; + + private static final Set EXCLUDED_KEYWORD_SEARCH_ITEMS = new HashSet<>(Arrays.asList( + "PHONE NUMBERS", + "IP ADDRESSES", + "EMAIL ADDRESSES", + "URLS", + "CREDIT CARD NUMBERS" + )); + private final SleuthkitCaseProvider provider; + /** + * Main constructor. + */ public DataSourceAnalysisSummary() { - this(Logger.getLogger(DataSourceAnalysisSummary.class.getName()), SleuthkitCaseProvider.DEFAULT); + this(SleuthkitCaseProvider.DEFAULT); } - - public DataSourceAnalysisSummary(java.util.logging.Logger logger, SleuthkitCaseProvider provider) { - this.logger = logger; + + /** + * Main constructor. + * + * @param provider The means of obtaining a sleuthkit case. + */ + public DataSourceAnalysisSummary(SleuthkitCaseProvider provider) { this.provider = provider; } - + + /** + * 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 + * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws TskCoreException + */ public List> getHashsetCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_HASHSET_HIT); } + /** + * 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 + * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws TskCoreException + */ public List> getKeywordCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { - return getCountsData(dataSource, TYPE_SET_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT); + 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())) + .collect(Collectors.toList()); } - + + /** + * 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 + * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws 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); } - - private List> getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes) throws SleuthkitCaseProviderException, TskCoreException { + + /** + * Get counts for the artifact of the specified type. + * + * @param dataSource The datasource. + * @param keyType The attribute to use as the key type. + * @param artifactTypes The types of artifacts for which to query. + * + * @return A list of key value pairs where the key is the attribute type + * value and the value is the count of items found. This list is + * sorted by the count descending max to min. + * + * @throws + * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws TskCoreException + */ + private List> getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes) + throws SleuthkitCaseProviderException, TskCoreException { List artifacts = new ArrayList<>(); SleuthkitCase skCase = provider.get(); - + for (ARTIFACT_TYPE type : artifactTypes) { artifacts.addAll(skCase.getBlackboard().getArtifacts(type.getTypeID(), dataSource.getId())); } - + Map countedKeys = artifacts.stream() .map((art) -> { String key = DataSourceInfoUtilities.getStringOrNull(art, keyType); @@ -80,10 +151,10 @@ public class DataSourceAnalysisSummary { }) .filter((key) -> key != null) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); - + return countedKeys.entrySet().stream() .map((e) -> Pair.of(e.getKey(), e.getValue())) - .sorted((a,b) -> -a.getValue().compareTo(b.getValue())) + .sorted((a, b) -> -a.getValue().compareTo(b.getValue())) .collect(Collectors.toList()); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java index 8f8698316a..16de061385 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/AnalysisPanel.java @@ -44,20 +44,22 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { private static final long serialVersionUID = 1L; - private static final ColumnModel> KEY_COL = new ColumnModel<>( - Bundle.AnalysisPanel_keyColumn_title(), - (pair) -> new DefaultCellModel(pair.getKey()), - 300 + /** + * Default Column definitions for each table + */ + private static final List>> DEFAULT_COLUMNS = Arrays.asList( + new ColumnModel<>( + Bundle.AnalysisPanel_keyColumn_title(), + (pair) -> new DefaultCellModel(pair.getKey()), + 300 + ), + new ColumnModel<>( + Bundle.AnalysisPanel_countColumn_title(), + (pair) -> new DefaultCellModel(String.valueOf(pair.getValue())), + 100 + ) ); - private static final ColumnModel> COUNT_COL = new ColumnModel<>( - Bundle.AnalysisPanel_countColumn_title(), - (pair) -> new DefaultCellModel(String.valueOf(pair.getValue())), - 100 - ); - - private static final List>> DEFAULT_COLUMNS = Arrays.asList(KEY_COL, COUNT_COL); - private final JTablePanel> hashsetHitsTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS); private final JTablePanel> keywordHitsTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS); @@ -70,6 +72,10 @@ public class AnalysisPanel extends BaseDataSourceSummaryPanel { interestingItemsTable ); + /** + * All of the components necessary for data fetch swing workers to load data + * for each table. + */ private final List> dataFetchComponents; /** From 91613720c360b83e07ae939b839b06584c4911c1 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Sep 2020 18:48:04 -0400 Subject: [PATCH 7/8] commenting --- .../datasourcesummary/datamodel/DataSourceAnalysisSummary.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java index e15c1f98f7..9c0c791673 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java @@ -140,10 +140,12 @@ public class DataSourceAnalysisSummary { 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())); } + // group those based on the value of the attribute type that should serve as a key Map countedKeys = artifacts.stream() .map((art) -> { String key = DataSourceInfoUtilities.getStringOrNull(art, keyType); @@ -152,6 +154,7 @@ public class DataSourceAnalysisSummary { .filter((key) -> key != null) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); + // sort from max to min counts return countedKeys.entrySet().stream() .map((e) -> Pair.of(e.getKey(), e.getValue())) .sorted((a, b) -> -a.getValue().compareTo(b.getValue())) From 8a831b33454305500d4e1011671a7904a7e50c75 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 9 Sep 2020 14:13:29 -0400 Subject: [PATCH 8/8] exception to just class name --- .../datamodel/DataSourceAnalysisSummary.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java index 9c0c791673..86aa21c7a1 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceAnalysisSummary.java @@ -77,8 +77,7 @@ public class DataSourceAnalysisSummary { * * @return The hashset set name with the number of hits in descending order. * - * @throws - * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws SleuthkitCaseProviderException * @throws TskCoreException */ public List> getHashsetCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { @@ -92,8 +91,7 @@ public class DataSourceAnalysisSummary { * * @return The keyword set name with the number of hits in descending order. * - * @throws - * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws SleuthkitCaseProviderException * @throws TskCoreException */ public List> getKeywordCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { @@ -112,8 +110,7 @@ public class DataSourceAnalysisSummary { * @return The interesting item set name with the number of hits in * descending order. * - * @throws - * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws SleuthkitCaseProviderException * @throws TskCoreException */ public List> getInterestingItemCounts(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { @@ -131,8 +128,7 @@ public class DataSourceAnalysisSummary { * value and the value is the count of items found. This list is * sorted by the count descending max to min. * - * @throws - * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws SleuthkitCaseProviderException * @throws TskCoreException */ private List> getCountsData(DataSource dataSource, BlackboardAttribute.Type keyType, ARTIFACT_TYPE... artifactTypes)