From 88fd85cf0298fb21b7826f1041c4e9b96c113b1e Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 4 Sep 2020 13:18:03 -0400 Subject: [PATCH 01/26] started working on parsing case string --- .../datamodel/DataSourcePastCasesSummary.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java new file mode 100644 index 0000000000..7d9cd635c7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java @@ -0,0 +1,91 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.datasourcesummary.datamodel; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; +import org.sleuthkit.datamodel.DataSource; + +/** + * + * @author gregd + */ +public class DataSourcePastCasesSummary { + + 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 DataSourcePastCasesSummary() { + this(SleuthkitCaseProvider.DEFAULT, + org.sleuthkit.autopsy.coreutils.Logger.getLogger(DataSourceUserActivitySummary.class.getName())); + + + } + + private static final BlackboardAttribute.Type TYPE_COMMENT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_COMMENT); + + /** + * Gets a list of cases from the TSK_COMMENT of an artifact. The cases + * string is expected to be of a form of "Previous Case: + * case1,case2...caseN". + * + * @param artifact The artifact + * + * @return The list of cases if found or empty list if not. + */ + private static List getCases(BlackboardArtifact artifact) { + String casesString = DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_COMMENT); + if (StringUtils.isBlank(casesString)) { + return Collections.emptyList(); + } + + int prefixCharIdx = casesString.indexOf(PREFIX_END); + if (prefixCharIdx < 0 || prefixCharIdx >= casesString.length() - 1) { + return Collections.emptyList(); + } + + String justCasesStr = casesString.substring(prefixCharIdx + 1).trim(); + return Arrays.asList(justCasesStr.split(CASE_SEPARATOR)); + } + + + + /** + * 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 DataSourcePastCasesSummary( + SleuthkitCaseProvider provider, + java.util.logging.Logger logger) { + + this.caseProvider = provider; + this.logger = logger; + } + + public List> getPastCasesWithNotableFile(DataSource dataSource) { + + } + + public List> getPastCasesWithSameId(DataSource dataSource) { + + } +} From 4f9addc321fd74d8dd387dc8bfee84f166411489 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 4 Sep 2020 14:35:43 -0400 Subject: [PATCH 02/26] working through reader --- .../datamodel/DataSourcePastCasesSummary.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java index 7d9cd635c7..edd25d5833 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java @@ -10,6 +10,7 @@ import java.util.Collections; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; +import org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; @@ -20,13 +21,18 @@ import org.sleuthkit.datamodel.DataSource; * @author gregd */ public class DataSourcePastCasesSummary { - + private static final String CENTRAL_REPO_INGEST_NAME = CentralRepoIngestModuleFactory.getModuleName(); + 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. */ From 2fc032abd44012228a33ab4c1f7367dd998aebcd Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Sep 2020 10:12:08 -0400 Subject: [PATCH 03/26] working through panel --- .../datamodel/DataSourcePastCasesSummary.java | 108 ++++++++++++++---- .../datasourcesummary/ui/PastCasesPanel.form | 28 +++++ .../datasourcesummary/ui/PastCasesPanel.java | 54 +++++++++ 3 files changed, 165 insertions(+), 25 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java index edd25d5833..f95cf30206 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java @@ -5,47 +5,58 @@ */ package org.sleuthkit.autopsy.datasourcesummary.datamodel; -import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; -import org.apache.commons.lang3.StringUtils; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; import org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory; 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.TskCoreException; /** * * @author gregd */ public class DataSourcePastCasesSummary { - private static final String CENTRAL_REPO_INGEST_NAME = CentralRepoIngestModuleFactory.getModuleName(); - + + private static final String CENTRAL_REPO_INGEST_NAME = CentralRepoIngestModuleFactory.getModuleName().toUpperCase().trim(); + 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 DataSourcePastCasesSummary() { this(SleuthkitCaseProvider.DEFAULT, org.sleuthkit.autopsy.coreutils.Logger.getLogger(DataSourceUserActivitySummary.class.getName())); - - + } private static final BlackboardAttribute.Type TYPE_COMMENT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_COMMENT); - /** + + + private static boolean isCentralRepoGenerated(List sources) { + if (sources == null) { + return false; + } + + return sources.stream().anyMatch((str) -> (str == null) ? false : CENTRAL_REPO_INGEST_NAME.equals(str.toUpperCase().trim())); + } + + + + /** * Gets a list of cases from the TSK_COMMENT of an artifact. The cases * string is expected to be of a form of "Previous Case: * case1,case2...caseN". @@ -54,23 +65,45 @@ public class DataSourcePastCasesSummary { * * @return The list of cases if found or empty list if not. */ - private static List getCases(BlackboardArtifact artifact) { - String casesString = DataSourceInfoUtilities.getStringOrNull(artifact, TYPE_COMMENT); - if (StringUtils.isBlank(casesString)) { + + + + + + private static List getCasesFromArtifact(BlackboardArtifact artifact) { + if (artifact == null) { + return Collections.emptyList(); + } + + BlackboardAttribute commentAttr = null; + try { + commentAttr = artifact.getAttribute(TYPE_COMMENT); + } catch (TskCoreException ignored) { + // ignore if no attribute can be found + } + + if (commentAttr == null) { + return Collections.emptyList(); + } + + if (!isCentralRepoGenerated(commentAttr.getSources())) { + return Collections.emptyList(); + } + + String commentStr = commentAttr.getValueString(); + + int prefixCharIdx = commentStr.indexOf(PREFIX_END); + if (prefixCharIdx < 0 || prefixCharIdx >= commentStr.length() - 1) { return Collections.emptyList(); } - int prefixCharIdx = casesString.indexOf(PREFIX_END); - if (prefixCharIdx < 0 || prefixCharIdx >= casesString.length() - 1) { - return Collections.emptyList(); - } - - String justCasesStr = casesString.substring(prefixCharIdx + 1).trim(); - return Arrays.asList(justCasesStr.split(CASE_SEPARATOR)); + String justCasesStr = commentStr.substring(prefixCharIdx + 1).trim(); + return Stream.of(justCasesStr.split(CASE_SEPARATOR)) + .map(String::trim) + .collect(Collectors.toList()); + } - - /** * Main constructor with external dependencies specified. This constructor * is designed with unit testing in mind since mocked dependencies can be @@ -87,11 +120,36 @@ public class DataSourcePastCasesSummary { this.logger = logger; } - public List> getPastCasesWithNotableFile(DataSource dataSource) { + private List> getPastCases(DataSource dataSource, ARTIFACT_TYPE artifactType) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { + // get a list of case names grouped by case insensitive grouping of names + + Collection> cases = this.caseProvider.get().getBlackboard().getArtifacts(artifactType.getTypeID(), dataSource.getId()) + .stream() + // convert to list of cases where there is a TSK_COMMENT from the central repo + .flatMap((art) -> getCasesFromArtifact(art).stream()) + // group by case insensitive compare of cases + .collect(Collectors.groupingBy((caseStr) -> caseStr.toUpperCase().trim())) + .values(); + return cases + .stream() + // get any cases where an actual case is found + .filter((lst) -> lst != null && lst.size() > 0) + // get non-normalized (i.e. not all caps) case name and number of items found + .map((lst) -> Pair.of(lst.get(0), (long) lst.size())) + // sorted descending + .sorted((a,b) -> -Long.compare(a.getValue(), b.getValue())) + .collect(Collectors.toList()); } - public List> getPastCasesWithSameId(DataSource dataSource) { + public List> getPastCasesWithNotableFile(DataSource dataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { + return getPastCases(dataSource, ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); + } + public List> getPastCasesWithSameId(DataSource dataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { + return getPastCases(dataSource, ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form new file mode 100644 index 0000000000..4f9abb50dc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form @@ -0,0 +1,28 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java new file mode 100644 index 0000000000..75cd0b2d12 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -0,0 +1,54 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.datasourcesummary.ui; + +import org.sleuthkit.datamodel.DataSource; + +/** + * + * @author gregd + */ +public class PastCasesPanel extends BaseDataSourceSummaryPanel { + + /** + * Creates new form PastCasesPanel + */ + public PastCasesPanel() { + initComponents(); + } + + @Override + protected void onNewDataSource(DataSource dataSource) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + /** + * 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.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables +} From cc1d583f217e20657a63704dae0dd42c365d1ae1 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Sep 2020 10:55:01 -0400 Subject: [PATCH 04/26] working through past cases tab --- .../autopsy/corecomponents/Bundle.properties | 1 + .../datasourcesummary/ui/Bundle.properties | 2 + .../datasourcesummary/ui/PastCasesPanel.form | 167 +++++++++++++++++- .../datasourcesummary/ui/PastCasesPanel.java | 155 ++++++++++++++-- 4 files changed, 309 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index c109aad513..6e128ac7a1 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -223,3 +223,4 @@ AutopsyOptionsPanel.totalMemoryLabel.text=Total System Memory: AutopsyOptionsPanel.maxMemoryUnitsLabel.text=GB AutopsyOptionsPanel.maxMemoryLabel.text=Maximum JVM Memory: AutopsyOptionsPanel.runtimePanel.border.title=Runtime +PastCasesPanel.notableFileLabel.text=Past Cases With Notable File diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties index 3d4d3af78c..5fe24786f3 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties @@ -38,3 +38,5 @@ DataSourceSummaryUserActivityPanel.recentDomainsLabel.text=Recent Domains RecentFilesPanel.openDocsLabel.text=Recently Opened Documents RecentFilesPanel.downloadLabel.text=Recent Downloads RecentFilesPanel.attachmentLabel.text=Recent Attachements +PastCasesPanel.notableFileLabel.text=Past Cases With Notable File\t +PastCasesPanel.sameIdLabel.text=Past Cases With Same Ids diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form index 4f9abb50dc..b2b67acd4a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form @@ -1,6 +1,6 @@ -
+ @@ -16,13 +16,174 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index 75cd0b2d12..04de6df7de 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -1,28 +1,120 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * 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.DataSourcePastCasesSummary; +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.DataFetchWorker.DataFetchComponents; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; +import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.ColumnModel; import org.sleuthkit.datamodel.DataSource; /** - * - * @author gregd + * A tab shown in data source summary displaying information about a datasource + * and how it pertains to other cases. */ +@Messages({ + "PastCasesPanel_caseColumn_title=Case", + "PastCasesPanel_countColumn_title=Count" +}) public class PastCasesPanel extends BaseDataSourceSummaryPanel { + private static final long serialVersionUID = 1L; + + private static final ColumnModel> CASE_COL = new ColumnModel<>( + Bundle.PastCasesPanel_caseColumn_title(), + (pair) -> new DefaultCellModel(pair.getKey()), + 300 + ); + + private static final ColumnModel> COUNT_COL = new ColumnModel<>( + Bundle.PastCasesPanel_countColumn_title(), + (pair) -> new DefaultCellModel(String.valueOf(pair.getValue())), + 100 + ); + + private static final List>> DEFAULT_COLUMNS = Arrays.asList(CASE_COL, COUNT_COL); + + private final JTablePanel> notableFileTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS); + + private final JTablePanel> sameIdTable = JTablePanel.getJTablePanel(DEFAULT_COLUMNS); + + private final List> tables = Arrays.asList( + notableFileTable, + sameIdTable + ); + + private final List> dataFetchComponents; + + public PastCasesPanel() { + this(new DataSourcePastCasesSummary()); + } + + /** * Creates new form PastCasesPanel */ - public PastCasesPanel() { + public PastCasesPanel(DataSourcePastCasesSummary pastCaseData) { + // set up data acquisition methods + dataFetchComponents = Arrays.asList( + // hashset hits loading components + new DataFetchWorker.DataFetchComponents<>( + (dataSource) -> pastCaseData.getPastCasesWithNotableFile(dataSource), + (result) -> notableFileTable.showDataFetchResult(result)), + // keyword hits loading components + new DataFetchWorker.DataFetchComponents<>( + (dataSource) -> pastCaseData.getPastCasesWithSameId(dataSource), + (result) -> sameIdTable.showDataFetchResult(result)) + ); + initComponents(); } - - @Override + + @Override protected void onNewDataSource(DataSource dataSource) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + // 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); + } } /** @@ -34,21 +126,58 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { // //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 notableFileLabel = 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 notableFilePanel = notableFileTable; + 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 sameIdLabel = new javax.swing.JLabel(); + javax.swing.Box.Filler filler3 = 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 sameIdPanel = sameIdTable; + 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.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS)); + + org.openide.awt.Mnemonics.setLocalizedText(notableFileLabel, org.openide.util.NbBundle.getMessage(PastCasesPanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N + mainContentPanel.add(notableFileLabel); + notableFileLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(PastCasesPanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N + + mainContentPanel.add(filler1); + + notableFilePanel.setMaximumSize(new java.awt.Dimension(32767, 106)); + notableFilePanel.setMinimumSize(new java.awt.Dimension(100, 106)); + notableFilePanel.setPreferredSize(new java.awt.Dimension(32767, 106)); + notableFilePanel.setLayout(null); + mainContentPanel.add(notableFilePanel); + mainContentPanel.add(filler2); + + org.openide.awt.Mnemonics.setLocalizedText(sameIdLabel, org.openide.util.NbBundle.getMessage(PastCasesPanel.class, "PastCasesPanel.sameIdLabel.text")); // NOI18N + mainContentPanel.add(sameIdLabel); + mainContentPanel.add(filler3); + + sameIdPanel.setMaximumSize(new java.awt.Dimension(32767, 106)); + sameIdPanel.setMinimumSize(new java.awt.Dimension(100, 106)); + sameIdPanel.setPreferredSize(new java.awt.Dimension(32767, 106)); + sameIdPanel.setLayout(null); + mainContentPanel.add(sameIdPanel); + 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) - .addGap(0, 400, Short.MAX_VALUE) + .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 300, Short.MAX_VALUE) + .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 bcf6ef9ca9c78417a3d1f53efb7dcbee6eb96fba Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 8 Sep 2020 11:00:27 -0400 Subject: [PATCH 05/26] fix layout issue --- .../autopsy/datasourcesummary/ui/PastCasesPanel.form | 8 ++------ .../autopsy/datasourcesummary/ui/PastCasesPanel.java | 2 -- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form index b2b67acd4a..5138a0905c 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form @@ -96,9 +96,7 @@
- - - + @@ -165,9 +163,7 @@ - - - + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index 04de6df7de..576cdc6ea9 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -148,7 +148,6 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { notableFilePanel.setMaximumSize(new java.awt.Dimension(32767, 106)); notableFilePanel.setMinimumSize(new java.awt.Dimension(100, 106)); notableFilePanel.setPreferredSize(new java.awt.Dimension(32767, 106)); - notableFilePanel.setLayout(null); mainContentPanel.add(notableFilePanel); mainContentPanel.add(filler2); @@ -159,7 +158,6 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { sameIdPanel.setMaximumSize(new java.awt.Dimension(32767, 106)); sameIdPanel.setMinimumSize(new java.awt.Dimension(100, 106)); sameIdPanel.setPreferredSize(new java.awt.Dimension(32767, 106)); - sameIdPanel.setLayout(null); mainContentPanel.add(sameIdPanel); mainContentPanel.add(filler5); From cf4f7144e227b81d8c1cbc3e62291f7de879f200 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 9 Sep 2020 09:32:32 -0400 Subject: [PATCH 06/26] message when ingest module has not been run on dataSource --- .../datamodel/DataSourcePastCasesSummary.java | 214 ++++++++++++++---- .../ui/Bundle.properties-MERGED | 5 + .../ui/DataSourceSummaryTabbedPane.java | 6 +- .../datasourcesummary/ui/PastCasesPanel.form | 13 +- .../datasourcesummary/ui/PastCasesPanel.java | 67 ++++-- 5 files changed, 234 insertions(+), 71 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java index f95cf30206..020d3eb120 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * 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; @@ -10,6 +23,7 @@ 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.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -17,46 +31,83 @@ 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.IngestJobInfo; +import org.sleuthkit.datamodel.IngestModuleInfo; import org.sleuthkit.datamodel.TskCoreException; /** + * Provides information about how a datasource relates to a previous case. NOTE: + * This code is fragile and has certain expectations about how the central + * repository handles creating artifacts. So, if the central repository changes + * ingest process, this code could break. This code expects that the central + * repository ingest module: * - * @author gregd + * a) Creates a TSK_INTERESTING_FILE_HIT artifact for a file whose hash is in + * the central repository as a notable file. + * + * b) Creates a TSK_INTERESTING_ARTIFACT_HIT artifact for a matching id in the + * central repository. + * + * c) The created artifact will have a TSK_COMMENT attribute attached where one + * of the sources for the attribute matches + * CentralRepoIngestModuleFactory.getModuleName(). The module display name at + * time of ingest will match CentralRepoIngestModuleFactory.getModuleName() as + * well. + * + * d) The content of that TSK_COMMENT attribute will be of the form "Previous + * Case: case1,case2...caseN" */ public class DataSourcePastCasesSummary { 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 String CASE_SEPARATOR = ","; private static final String PREFIX_END = ":"; private final SleuthkitCaseProvider caseProvider; - private final java.util.logging.Logger logger; /** * Main constructor. */ public DataSourcePastCasesSummary() { - this(SleuthkitCaseProvider.DEFAULT, - org.sleuthkit.autopsy.coreutils.Logger.getLogger(DataSourceUserActivitySummary.class.getName())); + this(SleuthkitCaseProvider.DEFAULT); } - private static final BlackboardAttribute.Type TYPE_COMMENT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_COMMENT); - - + /** + * 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. + */ + public DataSourcePastCasesSummary(SleuthkitCaseProvider provider) { + this.caseProvider = provider; + } + /** + * Given the provided sources for an attribute, aims to determine if one of + * those sources is the + * + * @param sources The list of sources found on an attribute. + * + * @return Whether or not this attribute (and subsequently the parent + * artifact) is created by the Central Repository Ingest Module. + */ private static boolean isCentralRepoGenerated(List sources) { if (sources == null) { return false; } - - return sources.stream().anyMatch((str) -> (str == null) ? false : CENTRAL_REPO_INGEST_NAME.equals(str.toUpperCase().trim())); + + return sources.stream().anyMatch((str) -> { + return (str == null) + ? false + : CENTRAL_REPO_INGEST_NAME.equals(str.toUpperCase().trim()); + }); } - - - /** + /** * Gets a list of cases from the TSK_COMMENT of an artifact. The cases * string is expected to be of a form of "Previous Case: * case1,case2...caseN". @@ -65,33 +116,28 @@ public class DataSourcePastCasesSummary { * * @return The list of cases if found or empty list if not. */ - - - - - private static List getCasesFromArtifact(BlackboardArtifact artifact) { if (artifact == null) { return Collections.emptyList(); } - + BlackboardAttribute commentAttr = null; try { - commentAttr = artifact.getAttribute(TYPE_COMMENT); + commentAttr = artifact.getAttribute(TYPE_COMMENT); } catch (TskCoreException ignored) { // ignore if no attribute can be found } - + if (commentAttr == null) { return Collections.emptyList(); } - + if (!isCentralRepoGenerated(commentAttr.getSources())) { return Collections.emptyList(); } - + String commentStr = commentAttr.getValueString(); - + int prefixCharIdx = commentStr.indexOf(PREFIX_END); if (prefixCharIdx < 0 || prefixCharIdx >= commentStr.length() - 1) { return Collections.emptyList(); @@ -101,29 +147,26 @@ public class DataSourcePastCasesSummary { return Stream.of(justCasesStr.split(CASE_SEPARATOR)) .map(String::trim) .collect(Collectors.toList()); - + } - + /** - * Main constructor with external dependencies specified. This constructor - * is designed with unit testing in mind since mocked dependencies can be - * utilized. + * Retrieves past cases associated with a specific artifact type. * - * @param provider The object providing the current SleuthkitCase. - * @param logger The logger to use. + * @param dataSource The datasource. + * @param artifactType The artifact type. + * + * @return A list of key value pairs mapping the case to the count of + * instances that case appeared for the given artifact type. The + * case is sorted from max to min descending. + * + * @throws + * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws TskCoreException */ - public DataSourcePastCasesSummary( - SleuthkitCaseProvider provider, - java.util.logging.Logger logger) { - - this.caseProvider = provider; - this.logger = logger; - } - - private List> getPastCases(DataSource dataSource, ARTIFACT_TYPE artifactType) + private List> getPastCases(DataSource dataSource, ARTIFACT_TYPE artifactType) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { - // get a list of case names grouped by case insensitive grouping of names - + Collection> cases = this.caseProvider.get().getBlackboard().getArtifacts(artifactType.getTypeID(), dataSource.getId()) .stream() // convert to list of cases where there is a TSK_COMMENT from the central repo @@ -139,16 +182,93 @@ public class DataSourcePastCasesSummary { // get non-normalized (i.e. not all caps) case name and number of items found .map((lst) -> Pair.of(lst.get(0), (long) lst.size())) // sorted descending - .sorted((a,b) -> -Long.compare(a.getValue(), b.getValue())) + .sorted((a, b) -> -Long.compare(a.getValue(), b.getValue())) .collect(Collectors.toList()); } - public List> getPastCasesWithNotableFile(DataSource dataSource) + /** + * Returns true if the ingest job info contains an ingest module that + * matches the Central Repo Module ingest display name. + * + * @param info The info. + * + * @return True if there is a central repo ingest match. + */ + private boolean hasCentralRepoIngest(IngestJobInfo info) { + if (info == null || info.getIngestModuleInfo() == null) { + return false; + } + + return info.getIngestModuleInfo().stream() + .anyMatch((moduleInfo) -> { + return StringUtils.isNotBlank(moduleInfo.getDisplayName()) + && moduleInfo.getDisplayName().toUpperCase().trim().equals(CENTRAL_REPO_INGEST_NAME); + }); + } + + /** + * Returns true if there is an ingest module + * + * @param dataSource The data source. + * + * @return True if there is an ingest job pertaining to the data source + * where an ingest module matches the central repo ingest module + * display name. + * + * @throws + * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws TskCoreException + */ + public boolean isCentralRepoIngested(DataSource dataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { + if (dataSource == null) { + return false; + } + + long dataSourceId = dataSource.getId(); + + return this.caseProvider.get().getIngestJobs().stream() + .anyMatch((ingestJob) -> { + return ingestJob != null + && ingestJob.getObjectId() == dataSourceId + && hasCentralRepoIngest(ingestJob); + }); + + } + + /** + * Get all cases that share notable files with the given data source. + * + * @param dataSource The data source. + * + * @return A list of key value pairs mapping the case to the count of + * instances that case appeared. The case is sorted from max to min + * descending. + * + * @throws + * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws TskCoreException + */ + public List> getPastCasesWithNotableFile(DataSource dataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { return getPastCases(dataSource, ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); } - public List> getPastCasesWithSameId(DataSource dataSource) + /** + * Get all cases that share a common central repository id with the given + * data source. + * + * @param dataSource The data source. + * + * @return A list of key value pairs mapping the case to the count of + * instances that case appeared. The case is sorted from max to min + * descending. + * + * @throws + * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws TskCoreException + */ + public List> getPastCasesWithSameId(DataSource dataSource) throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { return getPastCases(dataSource, ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); } 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..166f55d664 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -67,6 +67,7 @@ DataSourceSummaryNode.viewDataSourceAction.text=Go to Data Source DataSourceSummaryTabbedPane_countsTab_title=Counts DataSourceSummaryTabbedPane_detailsTab_title=Container DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History +DataSourceSummaryTabbedPane_pastCasesTab_title=Past Cases DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files DataSourceSummaryTabbedPane_userActivityTab_title=User Activity DataSourceSummaryUserActivityPanel.programsRunLabel.text=Recent Programs @@ -91,6 +92,8 @@ DataSourceSummaryUserActivityPanel_TopProgramsTableModel_name_header=Program DataSourceSummaryUserActivityPanel_TopWebSearchTableModel_dateAccessed_header=Date Accessed DataSourceSummaryUserActivityPanel_TopWebSearchTableModel_searchString_header=Search String DataSourceSummaryUserActivityPanel_TopWebSearchTableModel_translatedResult_header=Translated +PastCasesPanel_caseColumn_title=Case +PastCasesPanel_countColumn_title=Count RecentFilePanel_col_header_domain=Domain RecentFilePanel_col_header_path=Path RecentFilePanel_col_header_sender=Sender @@ -98,5 +101,7 @@ RecentFilePanel_no_open_documents=No recently open documents found. RecentFilesPanel.openDocsLabel.text=Recently Opened Documents RecentFilesPanel.downloadLabel.text=Recent Downloads RecentFilesPanel.attachmentLabel.text=Recent Attachements +PastCasesPanel.notableFileLabel.text=Past Cases With Notable File\t +PastCasesPanel.sameIdLabel.text=Past Cases With Same Ids RecentFilesPanel_col_head_date=Date ViewSummaryInformationAction.name.text=View Summary Information diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryTabbedPane.java index 047af1cdd9..7371697cae 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_pastCasesTab_title=Past Cases", }) 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_pastCasesTab_title(), new PastCasesPanel()) )); private final IngestJobInfoPanel ingestHistoryPanel = new IngestJobInfoPanel(); diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form index 5138a0905c..13ddb081bd 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form @@ -35,6 +35,13 @@ + + + + + + + @@ -80,6 +87,7 @@ + @@ -87,7 +95,7 @@ - + @@ -147,6 +155,7 @@ + @@ -154,7 +163,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index 576cdc6ea9..9aedcd1f3e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -20,11 +20,14 @@ package org.sleuthkit.autopsy.datasourcesummary.ui; import java.util.Arrays; import java.util.List; +import java.util.logging.Level; 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.coreutils.Logger; import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourcePastCasesSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker; @@ -32,6 +35,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetch import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.ColumnModel; import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.TskCoreException; /** * A tab shown in data source summary displaying information about a datasource @@ -39,11 +43,14 @@ import org.sleuthkit.datamodel.DataSource; */ @Messages({ "PastCasesPanel_caseColumn_title=Case", - "PastCasesPanel_countColumn_title=Count" + "PastCasesPanel_countColumn_title=Count", + "PastCasesPanel_onNoCrIngest_message=No results will be shown because the Central Repository module was not run." + }) public class PastCasesPanel extends BaseDataSourceSummaryPanel { private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(PastCasesPanel.class.getName()); private static final ColumnModel> CASE_COL = new ColumnModel<>( Bundle.PastCasesPanel_caseColumn_title(), @@ -74,12 +81,15 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { this(new DataSourcePastCasesSummary()); } - + private final DataSourcePastCasesSummary pastCaseData; + /** * Creates new form PastCasesPanel */ public PastCasesPanel(DataSourcePastCasesSummary pastCaseData) { - // set up data acquisition methods + this.pastCaseData = pastCaseData; + + // set up data acquisition methods dataFetchComponents = Arrays.asList( // hashset hits loading components new DataFetchWorker.DataFetchComponents<>( @@ -90,10 +100,10 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { (dataSource) -> pastCaseData.getPastCasesWithSameId(dataSource), (result) -> sameIdTable.showDataFetchResult(result)) ); - + initComponents(); } - + @Override protected void onNewDataSource(DataSource dataSource) { // if no data source is present or the case is not open, @@ -101,20 +111,34 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { 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); + return; } + + boolean centralRepoIngested = false; + try { + centralRepoIngested = this.pastCaseData.isCentralRepoIngested(dataSource); + } catch (SleuthkitCaseProvider.SleuthkitCaseProviderException | TskCoreException ex) { + logger.log(Level.WARNING, "There was an error while determining if dataSource has been central repo ingested.", ex); + } + + if (!centralRepoIngested) { + // set tables to display loading screen + this.tables.forEach((table) -> table.showMessage(Bundle.PastCasesPanel_onNoCrIngest_message())); + return; + } + + // 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); + } /** @@ -137,6 +161,7 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { javax.swing.JPanel sameIdPanel = sameIdTable; 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)); org.openide.awt.Mnemonics.setLocalizedText(notableFileLabel, org.openide.util.NbBundle.getMessage(PastCasesPanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N @@ -145,9 +170,10 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { mainContentPanel.add(filler1); + notableFilePanel.setAlignmentX(0.0F); notableFilePanel.setMaximumSize(new java.awt.Dimension(32767, 106)); notableFilePanel.setMinimumSize(new java.awt.Dimension(100, 106)); - notableFilePanel.setPreferredSize(new java.awt.Dimension(32767, 106)); + notableFilePanel.setPreferredSize(new java.awt.Dimension(100, 106)); mainContentPanel.add(notableFilePanel); mainContentPanel.add(filler2); @@ -155,9 +181,10 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { mainContentPanel.add(sameIdLabel); mainContentPanel.add(filler3); + sameIdPanel.setAlignmentX(0.0F); sameIdPanel.setMaximumSize(new java.awt.Dimension(32767, 106)); sameIdPanel.setMinimumSize(new java.awt.Dimension(100, 106)); - sameIdPanel.setPreferredSize(new java.awt.Dimension(32767, 106)); + sameIdPanel.setPreferredSize(new java.awt.Dimension(100, 106)); mainContentPanel.add(sameIdPanel); mainContentPanel.add(filler5); From 7128093e3e8050ba4a1faaf8d3a4c8a2e7a5fc72 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 9 Sep 2020 13:35:39 -0400 Subject: [PATCH 07/26] updated past cases bundle --- .../autopsy/datasourcesummary/ui/Bundle.properties-MERGED | 1 + 1 file changed, 1 insertion(+) 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 166f55d664..0c51ecea62 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -94,6 +94,7 @@ DataSourceSummaryUserActivityPanel_TopWebSearchTableModel_searchString_header=Se DataSourceSummaryUserActivityPanel_TopWebSearchTableModel_translatedResult_header=Translated PastCasesPanel_caseColumn_title=Case PastCasesPanel_countColumn_title=Count +PastCasesPanel_onNoCrIngest_message=No results will be shown because the Central Repository module was not run. RecentFilePanel_col_header_domain=Domain RecentFilePanel_col_header_path=Path RecentFilePanel_col_header_sender=Sender From 7f718148e33896ea626dc43c966f00c6643bb736 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 9 Sep 2020 14:27:25 -0400 Subject: [PATCH 08/26] code cleanup --- .../datamodel/DataSourcePastCasesSummary.java | 14 +++++--------- .../datasourcesummary/ui/PastCasesPanel.java | 12 ++++++------ 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java index 020d3eb120..b219049a6e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java @@ -26,13 +26,13 @@ import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; 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.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.IngestJobInfo; -import org.sleuthkit.datamodel.IngestModuleInfo; import org.sleuthkit.datamodel.TskCoreException; /** @@ -160,8 +160,7 @@ public class DataSourcePastCasesSummary { * instances that case appeared for the given artifact type. The * case is sorted from max to min descending. * - * @throws - * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws SleuthkitCaseProviderException * @throws TskCoreException */ private List> getPastCases(DataSource dataSource, ARTIFACT_TYPE artifactType) @@ -215,8 +214,7 @@ public class DataSourcePastCasesSummary { * where an ingest module matches the central repo ingest module * display name. * - * @throws - * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws SleuthkitCaseProviderException * @throws TskCoreException */ public boolean isCentralRepoIngested(DataSource dataSource) @@ -245,8 +243,7 @@ public class DataSourcePastCasesSummary { * instances that case appeared. The case is sorted from max to min * descending. * - * @throws - * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws SleuthkitCaseProviderException * @throws TskCoreException */ public List> getPastCasesWithNotableFile(DataSource dataSource) @@ -264,8 +261,7 @@ public class DataSourcePastCasesSummary { * instances that case appeared. The case is sorted from max to min * descending. * - * @throws - * org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException + * @throws SleuthkitCaseProviderException * @throws TskCoreException */ public List> getPastCasesWithSameId(DataSource dataSource) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index 9aedcd1f3e..c61ade219d 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -45,7 +45,7 @@ import org.sleuthkit.datamodel.TskCoreException; "PastCasesPanel_caseColumn_title=Case", "PastCasesPanel_countColumn_title=Count", "PastCasesPanel_onNoCrIngest_message=No results will be shown because the Central Repository module was not run." - + }) public class PastCasesPanel extends BaseDataSourceSummaryPanel { @@ -80,7 +80,7 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { public PastCasesPanel() { this(new DataSourcePastCasesSummary()); } - + private final DataSourcePastCasesSummary pastCaseData; /** @@ -88,7 +88,7 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { */ public PastCasesPanel(DataSourcePastCasesSummary pastCaseData) { this.pastCaseData = pastCaseData; - + // set up data acquisition methods dataFetchComponents = Arrays.asList( // hashset hits loading components @@ -103,7 +103,7 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { initComponents(); } - + @Override protected void onNewDataSource(DataSource dataSource) { // if no data source is present or the case is not open, @@ -120,13 +120,13 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { } catch (SleuthkitCaseProvider.SleuthkitCaseProviderException | TskCoreException ex) { logger.log(Level.WARNING, "There was an error while determining if dataSource has been central repo ingested.", ex); } - + if (!centralRepoIngested) { // set tables to display loading screen this.tables.forEach((table) -> table.showMessage(Bundle.PastCasesPanel_onNoCrIngest_message())); return; } - + // set tables to display loading screen this.tables.forEach((table) -> table.showDefaultLoadingMessage()); From 3569d5f66c2c6ba6c8e21c9d56aea93f77ea1632 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 9 Sep 2020 14:29:19 -0400 Subject: [PATCH 09/26] code cleanup --- Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 6e128ac7a1..c109aad513 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -223,4 +223,3 @@ AutopsyOptionsPanel.totalMemoryLabel.text=Total System Memory: AutopsyOptionsPanel.maxMemoryUnitsLabel.text=GB AutopsyOptionsPanel.maxMemoryLabel.text=Maximum JVM Memory: AutopsyOptionsPanel.runtimePanel.border.title=Runtime -PastCasesPanel.notableFileLabel.text=Past Cases With Notable File From c4518c3c178aa26e5e2be89dfcc2d8de37e4e5ba Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 10 Sep 2020 10:17:56 -0400 Subject: [PATCH 10/26] revisions --- .../datamodel/DataSourcePastCasesSummary.java | 47 ++++++++++++- .../datasourcesummary/ui/PastCasesPanel.java | 66 +++++++++---------- 2 files changed, 76 insertions(+), 37 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java index b219049a6e..8d077f1fbf 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java @@ -59,6 +59,21 @@ import org.sleuthkit.datamodel.TskCoreException; */ public class DataSourcePastCasesSummary { + /** + * Exception that is thrown in the event that a data source has not been + * ingested with the Central Repository Ingest Module. + */ + public static class NotCentralRepoIngestedException extends Exception { + + /** + * Main constructor. + * @param string Error message. + */ + public NotCentralRepoIngestedException(String string) { + super(string); + } + } + 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); @@ -162,9 +177,12 @@ public class DataSourcePastCasesSummary { * * @throws SleuthkitCaseProviderException * @throws TskCoreException + * @throws NotCentralRepoIngestedException */ private List> getPastCases(DataSource dataSource, ARTIFACT_TYPE artifactType) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, NotCentralRepoIngestedException { + + throwOnNotCentralRepoIngested(dataSource); Collection> cases = this.caseProvider.get().getBlackboard().getArtifacts(artifactType.getTypeID(), dataSource.getId()) .stream() @@ -234,6 +252,27 @@ public class DataSourcePastCasesSummary { } + /** + * Throws an exception if the current data source has not been ingested with + * the Central Repository Ingest Module. + * + * @param dataSource The data source to check if it has been ingested with + * the Central Repository Ingest Module. + * + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + * @throws NotCentralRepoIngestedException + */ + private void throwOnNotCentralRepoIngested(DataSource dataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, NotCentralRepoIngestedException { + + if (!isCentralRepoIngested(dataSource)) { + String objectId = (dataSource == null) ? "" : String.valueOf(dataSource.getId()); + String message = String.format("Data source: %s has not been ingested with the Central Repository Ingest Module.", objectId); + throw new NotCentralRepoIngestedException(message); + } + } + /** * Get all cases that share notable files with the given data source. * @@ -245,9 +284,10 @@ public class DataSourcePastCasesSummary { * * @throws SleuthkitCaseProviderException * @throws TskCoreException + * @throws NotCentralRepoIngestedException */ public List> getPastCasesWithNotableFile(DataSource dataSource) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, NotCentralRepoIngestedException { return getPastCases(dataSource, ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); } @@ -263,9 +303,10 @@ public class DataSourcePastCasesSummary { * * @throws SleuthkitCaseProviderException * @throws TskCoreException + * @throws NotCentralRepoIngestedException */ public List> getPastCasesWithSameId(DataSource dataSource) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException { + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, NotCentralRepoIngestedException { return getPastCases(dataSource, ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index c61ade219d..6e578cd492 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -20,22 +20,21 @@ package org.sleuthkit.autopsy.datasourcesummary.ui; import java.util.Arrays; import java.util.List; -import java.util.logging.Level; 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.coreutils.Logger; import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourcePastCasesSummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourcePastCasesSummary.NotCentralRepoIngestedException; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel; 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.JTablePanel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.ColumnModel; import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.TskCoreException; /** * A tab shown in data source summary displaying information about a datasource @@ -81,29 +80,42 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { this(new DataSourcePastCasesSummary()); } - private final DataSourcePastCasesSummary pastCaseData; - /** * Creates new form PastCasesPanel */ public PastCasesPanel(DataSourcePastCasesSummary pastCaseData) { - this.pastCaseData = pastCaseData; - // set up data acquisition methods dataFetchComponents = Arrays.asList( // hashset hits loading components new DataFetchWorker.DataFetchComponents<>( (dataSource) -> pastCaseData.getPastCasesWithNotableFile(dataSource), - (result) -> notableFileTable.showDataFetchResult(result)), + (result) -> handleResult(notableFileTable, result)), // keyword hits loading components new DataFetchWorker.DataFetchComponents<>( (dataSource) -> pastCaseData.getPastCasesWithSameId(dataSource), - (result) -> sameIdTable.showDataFetchResult(result)) + (result) -> handleResult(sameIdTable, result)) ); initComponents(); } + /** + * handles displaying the result for the table. If a + * NotCentralRepoIngestedException is thrown, then an appropriate message is + * shown. Otherwise, this method uses the tables default showDataFetchResult + * method. + * + * @param table The table. + * @param result The result. + */ + private void handleResult(JTablePanel table, DataFetchResult> result) { + if (result.getResultType() == ResultType.ERROR && result.getException() instanceof NotCentralRepoIngestedException) { + table.showMessage(Bundle.PastCasesPanel_onNoCrIngest_message()); + } else { + table.showDataFetchResult(result); + } + } + @Override protected void onNewDataSource(DataSource dataSource) { // if no data source is present or the case is not open, @@ -111,34 +123,20 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { if (dataSource == null || !Case.isCaseOpen()) { this.dataFetchComponents.forEach((item) -> item.getResultHandler() .accept(DataFetchResult.getSuccessResult(null))); - return; - } - boolean centralRepoIngested = false; - try { - centralRepoIngested = this.pastCaseData.isCentralRepoIngested(dataSource); - } catch (SleuthkitCaseProvider.SleuthkitCaseProviderException | TskCoreException ex) { - logger.log(Level.WARNING, "There was an error while determining if dataSource has been central repo ingested.", ex); - } - - if (!centralRepoIngested) { + } else { // set tables to display loading screen - this.tables.forEach((table) -> table.showMessage(Bundle.PastCasesPanel_onNoCrIngest_message())); - return; + 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); } - - // 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); - } /** From 461c6258dbacaab86beab9742b7ae07e4af034e7 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 11 Sep 2020 08:19:47 -0400 Subject: [PATCH 11/26] header updates --- .../sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties | 4 ++-- .../autopsy/datasourcesummary/ui/Bundle.properties-MERGED | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties index 5fe24786f3..8a83a74e0e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties @@ -38,5 +38,5 @@ DataSourceSummaryUserActivityPanel.recentDomainsLabel.text=Recent Domains RecentFilesPanel.openDocsLabel.text=Recently Opened Documents RecentFilesPanel.downloadLabel.text=Recent Downloads RecentFilesPanel.attachmentLabel.text=Recent Attachements -PastCasesPanel.notableFileLabel.text=Past Cases With Notable File\t -PastCasesPanel.sameIdLabel.text=Past Cases With Same Ids +PastCasesPanel.notableFileLabel.text=Past Cases with Notable Tags +PastCasesPanel.sameIdLabel.text=Past Cases with the Same Device IDs 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 0c51ecea62..487b2f6868 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -102,7 +102,7 @@ RecentFilePanel_no_open_documents=No recently open documents found. RecentFilesPanel.openDocsLabel.text=Recently Opened Documents RecentFilesPanel.downloadLabel.text=Recent Downloads RecentFilesPanel.attachmentLabel.text=Recent Attachements -PastCasesPanel.notableFileLabel.text=Past Cases With Notable File\t -PastCasesPanel.sameIdLabel.text=Past Cases With Same Ids +PastCasesPanel.notableFileLabel.text=Past Cases with Notable Tags +PastCasesPanel.sameIdLabel.text=Past Cases with the Same Device IDs RecentFilesPanel_col_head_date=Date ViewSummaryInformationAction.name.text=View Summary Information From 72a03930562643e36c820a9f671cc5a754f8c6f3 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 11 Sep 2020 11:38:38 -0400 Subject: [PATCH 12/26] added recent domains query --- .../DataSourceUserActivitySummary.java | 181 ++++++++++++++---- .../datamodel/TopDomainsResult.java | 11 +- .../ui/Bundle.properties-MERGED | 2 +- .../DataSourceSummaryUserActivityPanel.java | 17 +- 4 files changed, 158 insertions(+), 53 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceUserActivitySummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceUserActivitySummary.java index 1ae108c496..b6cc94d4ee 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceUserActivitySummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceUserActivitySummary.java @@ -18,15 +18,19 @@ */ package org.sleuthkit.autopsy.datasourcesummary.datamodel; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.logging.Level; import java.util.stream.Collectors; -import java.util.stream.IntStream; 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.datamodel.BlackboardArtifact; @@ -47,6 +51,7 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; public class DataSourceUserActivitySummary { private static final BlackboardArtifact.Type TYPE_DEVICE_ATTACHED = new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED); + private static final BlackboardArtifact.Type TYPE_WEB_HISTORY = new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_WEB_HISTORY); private static final BlackboardAttribute.Type TYPE_DATETIME = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME); private static final BlackboardAttribute.Type TYPE_DATETIME_ACCESSED = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED); @@ -55,49 +60,19 @@ public class DataSourceUserActivitySummary { private static final BlackboardAttribute.Type TYPE_DEVICE_MODEL = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL); private static final BlackboardAttribute.Type TYPE_MESSAGE_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE); private static final BlackboardAttribute.Type TYPE_TEXT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_TEXT); - private static final BlackboardAttribute.Type TYPE_DATETIME_RCVD = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_RCVD); private static final BlackboardAttribute.Type TYPE_DATETIME_SENT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_SENT); private static final BlackboardAttribute.Type TYPE_DATETIME_START = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_START); private static final BlackboardAttribute.Type TYPE_DATETIME_END = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_END); + private static final BlackboardAttribute.Type TYPE_DOMAIN = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN); private static final Comparator TOP_ACCOUNT_RESULT_DATE_COMPARE = (a, b) -> a.getLastAccess().compareTo(b.getLastAccess()); private static final Comparator TOP_WEBSEARCH_RESULT_DATE_COMPARE = (a, b) -> a.getDateAccessed().compareTo(b.getDateAccessed()); private static final String ROOT_HUB_IDENTIFIER = "ROOT_HUB"; - private static final long SLEEP_TIME = 5000; - - /** - * A function to calculate a result from 2 parameters. - */ - interface Function2 { - - O apply(A1 a1, A2 a2); - } - - /** - * 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 InterruptedException { - Thread.sleep(SLEEP_TIME); - final String dId = Long.toString(dataSource.getId()); - final Function2 getId = (s, idx) -> String.format("d:%s, f:%s, i:%d", dId, s, idx); - return IntStream.range(0, count) - .mapToObj(num -> new TopDomainsResult( - getId.apply("domain", num), - getId.apply("url", num), - (long) num, - new Date(((long) num) * 1000 * 60 * 60 * 24) - )) - .collect(Collectors.toList()); - } + private static final long MS_PER_DAY = 1000 * 60 * 60 * 24; + 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; @@ -141,6 +116,142 @@ public class DataSourceUserActivitySummary { } } + /** + * 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); + + Pair>> mostRecentAndGroups = getDomainGroupsAndMostRecent(dataSource); + // if no recent domains, return accordingly + if (mostRecentAndGroups.getKey() == null || mostRecentAndGroups.getValue().size() == 0) { + return Collections.emptyList(); + } + + final long mostRecentMs = mostRecentAndGroups.getLeft(); + Map> groups = mostRecentAndGroups.getRight(); + + return groups.entrySet().stream() + .map(entry -> getDomainsResult(entry.getKey(), entry.getValue(), mostRecentMs)) + .filter(result -> result != null) + // sort by number of visit times in those 30 days (max to min) + .sorted((a, b) -> -Long.compare(a.getVisitTimes(), b.getVisitTimes())) + // limit the result number to the parameter provided + .limit(count) + .collect(Collectors.toList()); + } + + /** + * 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 number of visits. + * @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. + */ + private TopDomainsResult getDomainsResult(String domain, List visits, long mostRecentMs) { + long visitCount = 0; + Long thisMostRecentMs = null; + + for (Long visitMs : visits) { + // make sure that visit is within window of mostRecentMS; otherwise skip it. + if (visitMs + DOMAIN_WINDOW_MS < mostRecentMs) { + continue; + } + + // if visit is within window, increment the count and get most recent + visitCount++; + thisMostRecentMs = getMax(thisMostRecentMs, visitMs); + } + + // if there are no visits within the window, return null + if (visitCount <= 0 || thisMostRecentMs == null) { + return null; + } else { + // create a top domain result with the domain, count, and most recent visit date + return new TopDomainsResult(domain, visitCount, new Date(thisMostRecentMs)); + } + } + + /** + * Queries TSK_WEB_HISTORY artifacts and returning the latest web history + * date accessed and a mapping of domains to all of their visits. + * + * @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. + * + * @throws TskCoreException + * @throws SleuthkitCaseProviderException + */ + 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; + Map> domainVisits = new HashMap<>(); + + for (BlackboardArtifact art : artifacts) { + Long artifactDateSecs = DataSourceInfoUtilities.getLongOrNull(art, TYPE_DATETIME_ACCESSED); + String domain = DataSourceInfoUtilities.getStringOrNull(art, TYPE_DOMAIN); + + // if there isn't a last access date or domain for this artifact, it can be ignored. + if (artifactDateSecs == null || StringUtils.isBlank(domain)) { + continue; + } + + Long artifactDateMs = artifactDateSecs * 1000; + + // update the most recent visit date overall + mostRecentMs = getMax(mostRecentMs, artifactDateMs); + + //Normalize the domain to lower case. + domain = domain.toLowerCase().trim(); + + // add this visit date to the list of dates for the domain + List domainVisitList = domainVisits.get(domain); + if (domainVisitList == null) { + domainVisitList = new ArrayList<>(); + domainVisits.put(domain, domainVisitList); + } + + domainVisitList.add(artifactDateMs); + } + + return Pair.of(mostRecentMs, domainVisits); + } + + /** + * Returns the maximum value given two longs handling possible null values. + * + * @param num1 The first number. + * @param num2 The second number. + * + * @return The maximum non-null number or null if both numbers are null. + */ + private static Long getMax(Long num1, Long num2) { + if (num1 == null) { + return num2; + } else if (num2 == null) { + return num1; + } else { + return num2 > num1 ? num2 : num1; + } + } + /** * Attempts to obtain a web search result record from a blackboard artifact. * diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TopDomainsResult.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TopDomainsResult.java index e843e51c4c..2e6a36af4e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TopDomainsResult.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/TopDomainsResult.java @@ -26,7 +26,6 @@ import java.util.Date; public class TopDomainsResult { private final String domain; - private final String url; private final Long visitTimes; private final Date lastVisit; @@ -38,9 +37,8 @@ public class TopDomainsResult { * @param visitTimes The number of times it was visited. * @param lastVisit The date of the last visit. */ - public TopDomainsResult(String domain, String url, Long visitTimes, Date lastVisit) { + public TopDomainsResult(String domain, Long visitTimes, Date lastVisit) { this.domain = domain; - this.url = url; this.visitTimes = visitTimes; this.lastVisit = lastVisit; } @@ -52,13 +50,6 @@ public class TopDomainsResult { return domain; } - /** - * @return The url for the result. - */ - public String getUrl() { - return url; - } - /** * @return The number of times this site is visited. */ 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 f3325f2e46..7cdf0dd4df 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -87,9 +87,9 @@ DataSourceSummaryUserActivityPanel_TopAccountTableModel_lastAccess_header=Last A DataSourceSummaryUserActivityPanel_TopDeviceAttachedTableModel_dateAccessed_header=Last Accessed DataSourceSummaryUserActivityPanel_TopDeviceAttachedTableModel_deviceId_header=Device Id DataSourceSummaryUserActivityPanel_TopDeviceAttachedTableModel_makeModel_header=Make and Model +DataSourceSummaryUserActivityPanel_TopDomainsTableModel_count_header=Count DataSourceSummaryUserActivityPanel_TopDomainsTableModel_domain_header=Domain DataSourceSummaryUserActivityPanel_TopDomainsTableModel_lastAccess_header=Last Access -DataSourceSummaryUserActivityPanel_TopDomainsTableModel_url_header=URL DataSourceSummaryUserActivityPanel_TopProgramsTableModel_count_header=Run Times DataSourceSummaryUserActivityPanel_TopProgramsTableModel_folder_header=Folder DataSourceSummaryUserActivityPanel_TopProgramsTableModel_lastrun_header=Last Run diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryUserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryUserActivityPanel.java index b4011fe4d6..da6e86b488 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryUserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryUserActivityPanel.java @@ -54,7 +54,7 @@ import org.sleuthkit.datamodel.DataSource; "DataSourceSummaryUserActivityPanel_TopProgramsTableModel_count_header=Run Times", "DataSourceSummaryUserActivityPanel_TopProgramsTableModel_lastrun_header=Last Run", "DataSourceSummaryUserActivityPanel_TopDomainsTableModel_domain_header=Domain", - "DataSourceSummaryUserActivityPanel_TopDomainsTableModel_url_header=URL", + "DataSourceSummaryUserActivityPanel_TopDomainsTableModel_count_header=Count", "DataSourceSummaryUserActivityPanel_TopDomainsTableModel_lastAccess_header=Last Access", "DataSourceSummaryUserActivityPanel_noDataExists=No communication data exists", "DataSourceSummaryUserActivityPanel_TopWebSearchTableModel_searchString_header=Search String", @@ -129,16 +129,19 @@ public class DataSourceSummaryUserActivityPanel extends BaseDataSourceSummaryPan Bundle.DataSourceSummaryUserActivityPanel_TopDomainsTableModel_domain_header(), (recentDomain) -> new DefaultCellModel(recentDomain.getDomain()), 250), - // url column - new ColumnModel<>( - Bundle.DataSourceSummaryUserActivityPanel_TopDomainsTableModel_url_header(), - (recentDomain) -> new DefaultCellModel(recentDomain.getUrl()), - 250), // last accessed column new ColumnModel<>( Bundle.DataSourceSummaryUserActivityPanel_TopDomainsTableModel_lastAccess_header(), (recentDomain) -> new DefaultCellModel(getFormatted(recentDomain.getLastVisit())), - 150) + 150), + // count column + new ColumnModel<>( + Bundle.DataSourceSummaryUserActivityPanel_TopDomainsTableModel_count_header(), + (recentDomain) -> { + String visitTimes = recentDomain.getVisitTimes() == null ? "" : Long.toString(recentDomain.getVisitTimes()); + return new DefaultCellModel(visitTimes); + }, + 100) )); // top web searches table From 2c00c1f5100360b9eb76d844ad69e6f0838b7203 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 11 Sep 2020 11:44:28 -0400 Subject: [PATCH 13/26] comment updates --- .../datamodel/DataSourcePastCasesSummary.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java index 8d077f1fbf..36795acbc3 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java @@ -103,7 +103,7 @@ public class DataSourcePastCasesSummary { /** * Given the provided sources for an attribute, aims to determine if one of - * those sources is the + * those sources is the Central Repository Ingest Module. * * @param sources The list of sources found on an attribute. * @@ -127,7 +127,7 @@ public class DataSourcePastCasesSummary { * string is expected to be of a form of "Previous Case: * case1,case2...caseN". * - * @param artifact The artifact + * @param artifact The artifact. * * @return The list of cases if found or empty list if not. */ @@ -224,7 +224,7 @@ public class DataSourcePastCasesSummary { } /** - * Returns true if there is an ingest module + * Returns true if the central repository ingest module has been run on the datasource. * * @param dataSource The data source. * From d3097bbdbde32f6ec45c5fb3ba0d382f3c9e2984 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 11 Sep 2020 11:47:08 -0400 Subject: [PATCH 14/26] formatting --- .../datamodel/DataSourcePastCasesSummary.java | 4 +++- .../autopsy/datasourcesummary/ui/PastCasesPanel.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java index 36795acbc3..e2063b0cc6 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java @@ -67,6 +67,7 @@ public class DataSourcePastCasesSummary { /** * Main constructor. + * * @param string Error message. */ public NotCentralRepoIngestedException(String string) { @@ -224,7 +225,8 @@ public class DataSourcePastCasesSummary { } /** - * Returns true if the central repository ingest module has been run on the datasource. + * Returns true if the central repository ingest module has been run on the + * datasource. * * @param dataSource The data source. * diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index 6e578cd492..81c0d12e0e 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -105,7 +105,7 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { * shown. Otherwise, this method uses the tables default showDataFetchResult * method. * - * @param table The table. + * @param table The table. * @param result The result. */ private void handleResult(JTablePanel table, DataFetchResult> result) { From 4c3f5c9bedfbd35ea766801eed7c07ddfeaae332 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 11 Sep 2020 13:27:43 -0400 Subject: [PATCH 15/26] updates for consistency --- .../DataSourceUserActivitySummary.java | 12 ++++++++--- .../ui/Bundle.properties-MERGED | 4 ++-- .../DataSourceSummaryUserActivityPanel.java | 20 +++++++++---------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceUserActivitySummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceUserActivitySummary.java index b6cc94d4ee..d2cf3a11c4 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceUserActivitySummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceUserActivitySummary.java @@ -19,13 +19,16 @@ package org.sleuthkit.autopsy.datasourcesummary.datamodel; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -68,7 +71,9 @@ public class DataSourceUserActivitySummary { private static final Comparator TOP_ACCOUNT_RESULT_DATE_COMPARE = (a, b) -> a.getLastAccess().compareTo(b.getLastAccess()); private static final Comparator TOP_WEBSEARCH_RESULT_DATE_COMPARE = (a, b) -> a.getDateAccessed().compareTo(b.getDateAccessed()); - private static final String ROOT_HUB_IDENTIFIER = "ROOT_HUB"; + private static final Set DEVICE_EXCLUDE_LIST = new HashSet<>(Arrays.asList("ROOT_HUB", "ROOT_HUB20")); + + private static final String LOOPBACK_ADDRESS = "127.0.0.1"; private static final long MS_PER_DAY = 1000 * 60 * 60 * 24; private static final long DOMAIN_WINDOW_DAYS = 30; @@ -209,7 +214,8 @@ public class DataSourceUserActivitySummary { String domain = DataSourceInfoUtilities.getStringOrNull(art, TYPE_DOMAIN); // if there isn't a last access date or domain for this artifact, it can be ignored. - if (artifactDateSecs == null || StringUtils.isBlank(domain)) { + // Also, ignore the loopback address. + if (artifactDateSecs == null || StringUtils.isBlank(domain) || LOOPBACK_ADDRESS.equals(domain.toUpperCase().trim())) { continue; } @@ -384,7 +390,7 @@ public class DataSourceUserActivitySummary { // remove Root Hub identifier .filter(result -> { return result.getDeviceModel() == null - || !result.getDeviceModel().trim().toUpperCase().equals(ROOT_HUB_IDENTIFIER); + || !DEVICE_EXCLUDE_LIST.contains(result.getDeviceModel().trim().toUpperCase()); }) .limit(count) .collect(Collectors.toList()); 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 7cdf0dd4df..b707cf5ac0 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -87,9 +87,9 @@ DataSourceSummaryUserActivityPanel_TopAccountTableModel_lastAccess_header=Last A DataSourceSummaryUserActivityPanel_TopDeviceAttachedTableModel_dateAccessed_header=Last Accessed DataSourceSummaryUserActivityPanel_TopDeviceAttachedTableModel_deviceId_header=Device Id DataSourceSummaryUserActivityPanel_TopDeviceAttachedTableModel_makeModel_header=Make and Model -DataSourceSummaryUserActivityPanel_TopDomainsTableModel_count_header=Count +DataSourceSummaryUserActivityPanel_TopDomainsTableModel_count_header=Visits DataSourceSummaryUserActivityPanel_TopDomainsTableModel_domain_header=Domain -DataSourceSummaryUserActivityPanel_TopDomainsTableModel_lastAccess_header=Last Access +DataSourceSummaryUserActivityPanel_TopDomainsTableModel_lastAccess_header=Last Accessed DataSourceSummaryUserActivityPanel_TopProgramsTableModel_count_header=Run Times DataSourceSummaryUserActivityPanel_TopProgramsTableModel_folder_header=Folder DataSourceSummaryUserActivityPanel_TopProgramsTableModel_lastrun_header=Last Run diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryUserActivityPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryUserActivityPanel.java index da6e86b488..7a23b8be87 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryUserActivityPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryUserActivityPanel.java @@ -54,9 +54,8 @@ import org.sleuthkit.datamodel.DataSource; "DataSourceSummaryUserActivityPanel_TopProgramsTableModel_count_header=Run Times", "DataSourceSummaryUserActivityPanel_TopProgramsTableModel_lastrun_header=Last Run", "DataSourceSummaryUserActivityPanel_TopDomainsTableModel_domain_header=Domain", - "DataSourceSummaryUserActivityPanel_TopDomainsTableModel_count_header=Count", - "DataSourceSummaryUserActivityPanel_TopDomainsTableModel_lastAccess_header=Last Access", - "DataSourceSummaryUserActivityPanel_noDataExists=No communication data exists", + "DataSourceSummaryUserActivityPanel_TopDomainsTableModel_count_header=Visits", + "DataSourceSummaryUserActivityPanel_TopDomainsTableModel_lastAccess_header=Last Accessed", "DataSourceSummaryUserActivityPanel_TopWebSearchTableModel_searchString_header=Search String", "DataSourceSummaryUserActivityPanel_TopWebSearchTableModel_dateAccessed_header=Date Accessed", "DataSourceSummaryUserActivityPanel_TopWebSearchTableModel_translatedResult_header=Translated", @@ -64,7 +63,8 @@ import org.sleuthkit.datamodel.DataSource; "DataSourceSummaryUserActivityPanel_TopDeviceAttachedTableModel_makeModel_header=Make and Model", "DataSourceSummaryUserActivityPanel_TopDeviceAttachedTableModel_dateAccessed_header=Last Accessed", "DataSourceSummaryUserActivityPanel_TopAccountTableModel_accountType_header=Account Type", - "DataSourceSummaryUserActivityPanel_TopAccountTableModel_lastAccess_header=Last Accessed",}) + "DataSourceSummaryUserActivityPanel_TopAccountTableModel_lastAccess_header=Last Accessed", + "DataSourceSummaryUserActivityPanel_noDataExists=No communication data exists"}) public class DataSourceSummaryUserActivityPanel extends BaseDataSourceSummaryPanel { private static final long serialVersionUID = 1L; @@ -129,11 +129,6 @@ public class DataSourceSummaryUserActivityPanel extends BaseDataSourceSummaryPan Bundle.DataSourceSummaryUserActivityPanel_TopDomainsTableModel_domain_header(), (recentDomain) -> new DefaultCellModel(recentDomain.getDomain()), 250), - // last accessed column - new ColumnModel<>( - Bundle.DataSourceSummaryUserActivityPanel_TopDomainsTableModel_lastAccess_header(), - (recentDomain) -> new DefaultCellModel(getFormatted(recentDomain.getLastVisit())), - 150), // count column new ColumnModel<>( Bundle.DataSourceSummaryUserActivityPanel_TopDomainsTableModel_count_header(), @@ -141,7 +136,12 @@ public class DataSourceSummaryUserActivityPanel extends BaseDataSourceSummaryPan String visitTimes = recentDomain.getVisitTimes() == null ? "" : Long.toString(recentDomain.getVisitTimes()); return new DefaultCellModel(visitTimes); }, - 100) + 100), + // last accessed column + new ColumnModel<>( + Bundle.DataSourceSummaryUserActivityPanel_TopDomainsTableModel_lastAccess_header(), + (recentDomain) -> new DefaultCellModel(getFormatted(recentDomain.getLastVisit())), + 150) )); // top web searches table From d19aabc065c18834064fa8c3020665e7654daf15 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 11 Sep 2020 13:41:43 -0400 Subject: [PATCH 16/26] updated title for recent accounts --- .../sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties | 2 +- .../autopsy/datasourcesummary/ui/Bundle.properties-MERGED | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties index b88a008e10..2d6fdf9051 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties @@ -31,7 +31,7 @@ DataSourceSummaryDetailsPanel.unallocatedSizeValue.text= DataSourceSummaryCountsPanel.byCategoryLabel.text=Files by Category DataSourceSummaryCountsPanel.resultsByTypeLabel.text=Results by Type DataSourceSummaryUserActivityPanel.programsRunLabel.text=Recent Programs -DataSourceSummaryUserActivityPanel.recentAccountsLabel.text=Recent Accounts +DataSourceSummaryUserActivityPanel.recentAccountsLabel.text=Recent Account Types Used DataSourceSummaryUserActivityPanel.topWebSearchLabel.text=Recent Web Searches DataSourceSummaryUserActivityPanel.topDevicesAttachedLabel.text=Recent Devices Attached DataSourceSummaryUserActivityPanel.recentDomainsLabel.text=Recent Domains 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 b707cf5ac0..95a7f7b463 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -73,7 +73,7 @@ DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files DataSourceSummaryTabbedPane_userActivityTab_title=User Activity DataSourceSummaryUserActivityPanel.programsRunLabel.text=Recent Programs -DataSourceSummaryUserActivityPanel.recentAccountsLabel.text=Recent Accounts +DataSourceSummaryUserActivityPanel.recentAccountsLabel.text=Recent Account Types Used DataSourceSummaryUserActivityPanel.topWebSearchLabel.text=Recent Web Searches DataSourceSummaryUserActivityPanel.topDevicesAttachedLabel.text=Recent Devices Attached DataSourceSummaryUserActivityPanel.recentDomainsLabel.text=Recent Domains From d6a86b0e1647b456b7e3a638bc977b4503841fad Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 14 Sep 2020 10:13:14 -0400 Subject: [PATCH 17/26] draft with correlation attribute instances --- ...asesSummary.java => PastCasesSummary.java} | 271 +++++++++++++----- .../datasourcesummary/ui/Bundle.properties | 2 +- .../datasourcesummary/ui/PastCasesPanel.java | 50 ++-- 3 files changed, 236 insertions(+), 87 deletions(-) rename Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/{DataSourcePastCasesSummary.java => PastCasesSummary.java} (53%) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java similarity index 53% rename from Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java rename to Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java index e2063b0cc6..b7cf996fc5 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourcePastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java @@ -18,13 +18,24 @@ */ package org.sleuthkit.autopsy.datasourcesummary.datamodel; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.function.Function; +import java.util.function.Supplier; +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.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil; import org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -33,6 +44,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; /** @@ -57,37 +69,109 @@ 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 DataSourcePastCasesSummary { +public class PastCasesSummary { /** * Exception that is thrown in the event that a data source has not been - * ingested with the Central Repository Ingest Module. + * ingested with a particular ingest module. */ - public static class NotCentralRepoIngestedException extends Exception { + public static class NotIngestedWithModuleException extends Exception { + + private final String moduleDisplayName; + + /** + * Constructor. + * + * @param moduleName The module name. + * @param message The message for the exception. + */ + public NotIngestedWithModuleException(String moduleName, String message) { + super(message); + this.moduleDisplayName = moduleName; + } + + /** + * Constructor. + * + * @param moduleName The module name. + * @param message The message for the exception. + * @param thrwbl Inner exception if applicable. + */ + public NotIngestedWithModuleException(String moduleName, String message, Throwable thrwbl) { + super(message, thrwbl); + this.moduleDisplayName = moduleName; + } + + /** + * @return The module display name. + */ + public String getModuleDisplayName() { + return moduleDisplayName; + } + } + + /** + * Return type for results items in the past cases tab. + */ + public static class PastCasesResult { + + private final List> sameIdsResults; + private final List> taggedNotable; /** * Main constructor. * - * @param string Error message. + * @param sameIdsResults Data for the cases with same id table. + * @param taggedNotable Data for the tagged notable table. */ - public NotCentralRepoIngestedException(String string) { - super(string); + public PastCasesResult(List> sameIdsResults, List> taggedNotable) { + this.sameIdsResults = sameIdsResults; + this.taggedNotable = taggedNotable; + } + + /** + * @return Data for the cases with same id table. + */ + public List> getSameIdsResults() { + return sameIdsResults; + } + + /** + * @return Data for the tagged notable table. + */ + public List> getTaggedNotable() { + return taggedNotable; } } 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); + + private static final Set CR_DEVICE_TYPE_IDS = new HashSet<>(Arrays.asList( + CorrelationAttributeInstance.USBID_TYPE_ID, + CorrelationAttributeInstance.ICCID_TYPE_ID, + CorrelationAttributeInstance.IMEI_TYPE_ID, + CorrelationAttributeInstance.IMSI_TYPE_ID, + CorrelationAttributeInstance.MAC_TYPE_ID + )); private static final String CASE_SEPARATOR = ","; private static final String PREFIX_END = ":"; private final SleuthkitCaseProvider caseProvider; + private final java.util.logging.Logger logger; + private final Function> corrAttrRetriever; /** * Main constructor. */ - public DataSourcePastCasesSummary() { - this(SleuthkitCaseProvider.DEFAULT); + public PastCasesSummary() { + this( + SleuthkitCaseProvider.DEFAULT, + (artifact) -> CorrelationAttributeUtil.makeCorrAttrsForCorrelation(artifact), + org.sleuthkit.autopsy.coreutils.Logger.getLogger(DataSourceUserActivitySummary.class.getName()) + ); } @@ -96,10 +180,19 @@ public class DataSourcePastCasesSummary { * is designed with unit testing in mind since mocked dependencies can be * utilized. * - * @param provider The object providing the current SleuthkitCase. + * @param provider The object providing the current SleuthkitCase. + * @param corrAttrRetriever Obtains a list of CorrelationAttributeInstance + * objects for the given artifact. + * @param logger The logger to use. */ - public DataSourcePastCasesSummary(SleuthkitCaseProvider provider) { + public PastCasesSummary( + SleuthkitCaseProvider provider, + Function> corrAttrRetriever, + java.util.logging.Logger logger) { + this.caseProvider = provider; + this.corrAttrRetriever = corrAttrRetriever; + this.logger = logger; } /** @@ -167,33 +260,21 @@ public class DataSourcePastCasesSummary { } /** - * Retrieves past cases associated with a specific artifact type. + * Given a stream of case ids, groups the strings in a case-insensitive + * manner, and then provides a list of cases and the occurrence count sorted + * from max to min. * - * @param dataSource The datasource. - * @param artifactType The artifact type. + * @param cases A stream of cases. * - * @return A list of key value pairs mapping the case to the count of - * instances that case appeared for the given artifact type. The - * case is sorted from max to min descending. - * - * @throws SleuthkitCaseProviderException - * @throws TskCoreException - * @throws NotCentralRepoIngestedException + * @return The list of unique cases and their occurrences sorted from max to min. */ - private List> getPastCases(DataSource dataSource, ARTIFACT_TYPE artifactType) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, NotCentralRepoIngestedException { - - throwOnNotCentralRepoIngested(dataSource); - - Collection> cases = this.caseProvider.get().getBlackboard().getArtifacts(artifactType.getTypeID(), dataSource.getId()) - .stream() - // convert to list of cases where there is a TSK_COMMENT from the central repo - .flatMap((art) -> getCasesFromArtifact(art).stream()) + private List> getCaseCounts(Stream cases) { + Collection> groupedCases = cases // group by case insensitive compare of cases .collect(Collectors.groupingBy((caseStr) -> caseStr.toUpperCase().trim())) .values(); - return cases + return groupedCases .stream() // get any cases where an actual case is found .filter((lst) -> lst != null && lst.size() > 0) @@ -204,6 +285,93 @@ public class DataSourcePastCasesSummary { .collect(Collectors.toList()); } + /** + * Given an artifact with a TYPE_ASSOCIATED_ARTIFACT attribute, retrieves the related artifact. + * @param skCase The sleuthkit case. + * @param artifact The artifact with the TYPE_ASSOCIATED_ARTIFACT attribute. + * @return The artifact if found or null if not. + * @throws SleuthkitCaseProviderException + */ + 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 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; + } + } + + /** + * Returns true if the artifact has an associated artifact of a device type. + * @param artifact The artifact. + * @return True if there is a device associated artifact. + * @throws SleuthkitCaseProviderException + */ + private boolean hasDeviceAssociatedArtifact(BlackboardArtifact artifact) throws SleuthkitCaseProviderException { + BlackboardArtifact parent = getParentArtifact(artifact); + if (parent == null) { + return false; + } + + List correlationAttributes = corrAttrRetriever.apply(parent); + if (correlationAttributes == null) { + return false; + } + + return correlationAttributes.stream() + .anyMatch((attrInstance) -> CR_DEVICE_TYPE_IDS.contains(attrInstance.getCorrelationType())); + } + + + /** + * Returns the past cases data to be shown in the past cases tab. + * @param dataSource The data source. + * @return The retrieved data. + * @throws SleuthkitCaseProviderException + * @throws TskCoreException + * @throws NotIngestedWithModuleException + */ + public PastCasesResult getPastCasesData(DataSource dataSource) + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, NotIngestedWithModuleException { + + throwOnNotCentralRepoIngested(dataSource); + + SleuthkitCase skCase = caseProvider.get(); + + List deviceArtifactCases = new ArrayList<>(); + List nonDeviceArtifactCases = new ArrayList<>(); + + for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT, dataSource.getId())) { + List cases = getCasesFromArtifact(artifact); + if (cases == null || cases.isEmpty()) { + continue; + } + + if (hasDeviceAssociatedArtifact(artifact)) { + deviceArtifactCases.addAll(cases); + } else { + nonDeviceArtifactCases.addAll(cases); + } + } + + Stream filesCases = skCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, dataSource.getId()).stream() + .flatMap((art) -> getCasesFromArtifact(art).stream()); + + return new PastCasesResult( + getCaseCounts(deviceArtifactCases.stream()), + getCaseCounts(Stream.concat(filesCases, nonDeviceArtifactCases.stream())) + ); + } + + /** * Returns true if the ingest job info contains an ingest module that * matches the Central Repo Module ingest display name. @@ -263,52 +431,15 @@ public class DataSourcePastCasesSummary { * * @throws SleuthkitCaseProviderException * @throws TskCoreException - * @throws NotCentralRepoIngestedException + * @throws NotIngestedWithModuleException */ private void throwOnNotCentralRepoIngested(DataSource dataSource) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, NotCentralRepoIngestedException { + throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, NotIngestedWithModuleException { if (!isCentralRepoIngested(dataSource)) { String objectId = (dataSource == null) ? "" : String.valueOf(dataSource.getId()); String message = String.format("Data source: %s has not been ingested with the Central Repository Ingest Module.", objectId); - throw new NotCentralRepoIngestedException(message); + throw new NotIngestedWithModuleException(CENTRAL_REPO_INGEST_NAME, message); } } - - /** - * Get all cases that share notable files with the given data source. - * - * @param dataSource The data source. - * - * @return A list of key value pairs mapping the case to the count of - * instances that case appeared. The case is sorted from max to min - * descending. - * - * @throws SleuthkitCaseProviderException - * @throws TskCoreException - * @throws NotCentralRepoIngestedException - */ - public List> getPastCasesWithNotableFile(DataSource dataSource) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, NotCentralRepoIngestedException { - return getPastCases(dataSource, ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); - } - - /** - * Get all cases that share a common central repository id with the given - * data source. - * - * @param dataSource The data source. - * - * @return A list of key value pairs mapping the case to the count of - * instances that case appeared. The case is sorted from max to min - * descending. - * - * @throws SleuthkitCaseProviderException - * @throws TskCoreException - * @throws NotCentralRepoIngestedException - */ - public List> getPastCasesWithSameId(DataSource dataSource) - throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, NotCentralRepoIngestedException { - return getPastCases(dataSource, ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); - } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties index 74b89436b0..4886f25f68 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties @@ -39,5 +39,5 @@ AnalysisPanel.interestingItemLabel.text=Interesting Item Hits RecentFilesPanel.openDocsLabel.text=Recently Opened Documents RecentFilesPanel.downloadLabel.text=Recent Downloads RecentFilesPanel.attachmentLabel.text=Recent Attachements -PastCasesPanel.notableFileLabel.text=Past Cases with Notable Tags +PastCasesPanel.notableFileLabel.text=Cases with Common Items That Were Tagged as Notable PastCasesPanel.sameIdLabel.text=Past Cases with the Same Device IDs diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index 81c0d12e0e..c1d5d5605d 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -20,13 +20,15 @@ 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 org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourcePastCasesSummary; -import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataSourcePastCasesSummary.NotCentralRepoIngestedException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.NotIngestedWithModuleException; +import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.PastCasesResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType; @@ -77,23 +79,18 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { private final List> dataFetchComponents; public PastCasesPanel() { - this(new DataSourcePastCasesSummary()); + this(new PastCasesSummary()); } /** * Creates new form PastCasesPanel */ - public PastCasesPanel(DataSourcePastCasesSummary pastCaseData) { + public PastCasesPanel(PastCasesSummary pastCaseData) { // set up data acquisition methods dataFetchComponents = Arrays.asList( - // hashset hits loading components new DataFetchWorker.DataFetchComponents<>( - (dataSource) -> pastCaseData.getPastCasesWithNotableFile(dataSource), - (result) -> handleResult(notableFileTable, result)), - // keyword hits loading components - new DataFetchWorker.DataFetchComponents<>( - (dataSource) -> pastCaseData.getPastCasesWithSameId(dataSource), - (result) -> handleResult(sameIdTable, result)) + (dataSource) -> pastCaseData.getPastCasesData(dataSource), + (result) -> handleResult(result)) ); initComponents(); @@ -105,14 +102,35 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { * shown. Otherwise, this method uses the tables default showDataFetchResult * method. * - * @param table The table. * @param result The result. */ - private void handleResult(JTablePanel table, DataFetchResult> result) { - if (result.getResultType() == ResultType.ERROR && result.getException() instanceof NotCentralRepoIngestedException) { - table.showMessage(Bundle.PastCasesPanel_onNoCrIngest_message()); + private void handleResult(DataFetchResult result) { + if (result.getResultType() == ResultType.ERROR && result.getException() instanceof NotIngestedWithModuleException) { + notableFileTable.showMessage(Bundle.PastCasesPanel_onNoCrIngest_message()); + sameIdTable.showMessage(Bundle.PastCasesPanel_onNoCrIngest_message()); } else { - table.showDataFetchResult(result); + notableFileTable.showDataFetchResult(getSubResult(result, (res) -> res.getTaggedNotable())); + sameIdTable.showDataFetchResult(getSubResult(result, (res) -> res.getSameIdsResults())); + } + } + + /** + * Given an input data fetch result, creates an error result if the original + * is an error. Otherwise, uses the getSubResult function on the underlying + * data to create a new DataFetchResult. + * + * @param inputResult The input result. + * @param getSubComponent The means of getting the data given the original + * data. + * + * @return The new result with the error of the original or the processed + * data. + */ + private DataFetchResult getSubResult(DataFetchResult inputResult, Function getSubResult) { + if (inputResult.getResultType() == ResultType.SUCCESS) { + return DataFetchResult.getSuccessResult(getSubResult.apply(inputResult.getData())); + } else { + return DataFetchResult.getErrorResult(inputResult.getException()); } } From 2a9e6355e80ef213e96c0753bb9fc53c472ac724 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 14 Sep 2020 10:19:53 -0400 Subject: [PATCH 18/26] devices and changed table name --- .../datamodel/PastCasesSummary.java | 24 ++++--------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java index b7cf996fc5..bf9dbe3b12 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java @@ -25,15 +25,12 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.concurrent.Callable; import java.util.function.Function; -import java.util.function.Supplier; 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.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil; import org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory; @@ -149,11 +146,10 @@ public class PastCasesSummary { private static final BlackboardAttribute.Type TYPE_ASSOCIATED_ARTIFACT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT); private static final Set CR_DEVICE_TYPE_IDS = new HashSet<>(Arrays.asList( - CorrelationAttributeInstance.USBID_TYPE_ID, - CorrelationAttributeInstance.ICCID_TYPE_ID, - CorrelationAttributeInstance.IMEI_TYPE_ID, - CorrelationAttributeInstance.IMSI_TYPE_ID, - CorrelationAttributeInstance.MAC_TYPE_ID + ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID(), + ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID(), + ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID(), + ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID() )); private static final String CASE_SEPARATOR = ","; @@ -161,7 +157,6 @@ public class PastCasesSummary { private final SleuthkitCaseProvider caseProvider; private final java.util.logging.Logger logger; - private final Function> corrAttrRetriever; /** * Main constructor. @@ -181,8 +176,6 @@ public class PastCasesSummary { * utilized. * * @param provider The object providing the current SleuthkitCase. - * @param corrAttrRetriever Obtains a list of CorrelationAttributeInstance - * objects for the given artifact. * @param logger The logger to use. */ public PastCasesSummary( @@ -191,7 +184,6 @@ public class PastCasesSummary { java.util.logging.Logger logger) { this.caseProvider = provider; - this.corrAttrRetriever = corrAttrRetriever; this.logger = logger; } @@ -321,13 +313,7 @@ public class PastCasesSummary { return false; } - List correlationAttributes = corrAttrRetriever.apply(parent); - if (correlationAttributes == null) { - return false; - } - - return correlationAttributes.stream() - .anyMatch((attrInstance) -> CR_DEVICE_TYPE_IDS.contains(attrInstance.getCorrelationType())); + return CR_DEVICE_TYPE_IDS.contains(parent.getArtifactTypeID()); } From 4816c01c3b23419fcbad100da1c133cef5ebb482 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 14 Sep 2020 10:25:18 -0400 Subject: [PATCH 19/26] updated bundle --- .../autopsy/datasourcesummary/ui/Bundle.properties-MERGED | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 31238a3c2c..96515e7e1a 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -83,7 +83,7 @@ RecentFilePanel_no_open_documents=No recently open documents found. RecentFilesPanel.openDocsLabel.text=Recently Opened Documents RecentFilesPanel.downloadLabel.text=Recent Downloads RecentFilesPanel.attachmentLabel.text=Recent Attachements -PastCasesPanel.notableFileLabel.text=Past Cases with Notable Tags +PastCasesPanel.notableFileLabel.text=Cases with Common Items That Were Tagged as Notable PastCasesPanel.sameIdLabel.text=Past Cases with the Same Device IDs RecentFilesPanel_col_head_date=Date SizeRepresentationUtil_units_bytes=\ bytes From d51c16c0000253484ca8138621aceb63ae7bd8a6 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 14 Sep 2020 12:37:09 -0400 Subject: [PATCH 20/26] codacy remarks and bug fixes --- .../datamodel/PastCasesSummary.java | 13 ++++++------- .../datasourcesummary/ui/PastCasesPanel.java | 1 - 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java index bf9dbe3b12..b3a8f0eee3 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java @@ -73,7 +73,8 @@ public class PastCasesSummary { * ingested with a particular ingest module. */ public static class NotIngestedWithModuleException extends Exception { - + private static final long serialVersionUID = 1L; + private final String moduleDisplayName; /** @@ -202,9 +203,7 @@ public class PastCasesSummary { } return sources.stream().anyMatch((str) -> { - return (str == null) - ? false - : CENTRAL_REPO_INGEST_NAME.equals(str.toUpperCase().trim()); + return str != null && CENTRAL_REPO_INGEST_NAME.equalsIgnoreCase(str.trim()); }); } @@ -335,7 +334,7 @@ public class PastCasesSummary { List deviceArtifactCases = new ArrayList<>(); List nonDeviceArtifactCases = new ArrayList<>(); - for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT, dataSource.getId())) { + for (BlackboardArtifact artifact : skCase.getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID(), dataSource.getId())) { List cases = getCasesFromArtifact(artifact); if (cases == null || cases.isEmpty()) { continue; @@ -348,7 +347,7 @@ public class PastCasesSummary { } } - Stream filesCases = skCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, dataSource.getId()).stream() + Stream filesCases = skCase.getBlackboard().getArtifacts(ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(), dataSource.getId()).stream() .flatMap((art) -> getCasesFromArtifact(art).stream()); return new PastCasesResult( @@ -374,7 +373,7 @@ public class PastCasesSummary { return info.getIngestModuleInfo().stream() .anyMatch((moduleInfo) -> { return StringUtils.isNotBlank(moduleInfo.getDisplayName()) - && moduleInfo.getDisplayName().toUpperCase().trim().equals(CENTRAL_REPO_INGEST_NAME); + && moduleInfo.getDisplayName().trim().equalsIgnoreCase(CENTRAL_REPO_INGEST_NAME); }); } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index c1d5d5605d..b21d373e04 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -51,7 +51,6 @@ import org.sleuthkit.datamodel.DataSource; public class PastCasesPanel extends BaseDataSourceSummaryPanel { private static final long serialVersionUID = 1L; - private static final Logger logger = Logger.getLogger(PastCasesPanel.class.getName()); private static final ColumnModel> CASE_COL = new ColumnModel<>( Bundle.PastCasesPanel_caseColumn_title(), From f315d33f5f41081eb8fe618bc8143c251fa14f57 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 14 Sep 2020 15:14:11 -0400 Subject: [PATCH 21/26] remove unused import --- .../sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index b21d373e04..295cd035dd 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -25,7 +25,6 @@ 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.coreutils.Logger; import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary; import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.NotIngestedWithModuleException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.PastCasesSummary.PastCasesResult; From 89faf2c089b53322452fec89174955ebc02fd2d5 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 14 Sep 2020 20:27:55 -0400 Subject: [PATCH 22/26] add in localhost --- .../datamodel/DataSourceUserActivitySummary.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceUserActivitySummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceUserActivitySummary.java index d2cf3a11c4..34509e3691 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceUserActivitySummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/DataSourceUserActivitySummary.java @@ -71,9 +71,9 @@ public class DataSourceUserActivitySummary { private static final Comparator TOP_ACCOUNT_RESULT_DATE_COMPARE = (a, b) -> a.getLastAccess().compareTo(b.getLastAccess()); private static final Comparator TOP_WEBSEARCH_RESULT_DATE_COMPARE = (a, b) -> a.getDateAccessed().compareTo(b.getDateAccessed()); + private static final Set DEVICE_EXCLUDE_LIST = new HashSet<>(Arrays.asList("ROOT_HUB", "ROOT_HUB20")); - - private static final String LOOPBACK_ADDRESS = "127.0.0.1"; + private static final Set DOMAIN_EXCLUDE_LIST = new HashSet<>(Arrays.asList("127.0.0.1", "LOCALHOST")); private static final long MS_PER_DAY = 1000 * 60 * 60 * 24; private static final long DOMAIN_WINDOW_DAYS = 30; @@ -215,7 +215,7 @@ public class DataSourceUserActivitySummary { // if there isn't a last access date or domain for this artifact, it can be ignored. // Also, ignore the loopback address. - if (artifactDateSecs == null || StringUtils.isBlank(domain) || LOOPBACK_ADDRESS.equals(domain.toUpperCase().trim())) { + if (artifactDateSecs == null || StringUtils.isBlank(domain) || DOMAIN_EXCLUDE_LIST.contains(domain.toUpperCase().trim())) { continue; } From 11ce06c039449e31d0f4b6781bfc4c2cc1ca31c5 Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Mon, 14 Sep 2020 22:25:44 -0400 Subject: [PATCH 23/26] Update ILeappAnalyzerModuleFactory.java Rename module name and description --- .../modules/ileappanalyzer/ILeappAnalyzerModuleFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/ileappanalyzer/ILeappAnalyzerModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/ileappanalyzer/ILeappAnalyzerModuleFactory.java index 5da165392f..166c455d55 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/ileappanalyzer/ILeappAnalyzerModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/ileappanalyzer/ILeappAnalyzerModuleFactory.java @@ -33,7 +33,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; @ServiceProvider(service = IngestModuleFactory.class) public class ILeappAnalyzerModuleFactory extends IngestModuleFactoryAdapter { - @NbBundle.Messages({"ILeappAnalyzerModuleFactory_moduleName=ILeapp Analyzer"}) + @NbBundle.Messages({"ILeappAnalyzerModuleFactory_moduleName=iOS Analyzer (iLEAPP)"}) static String getModuleName() { return Bundle.ILeappAnalyzerModuleFactory_moduleName(); } @@ -43,7 +43,7 @@ public class ILeappAnalyzerModuleFactory extends IngestModuleFactoryAdapter { return getModuleName(); } - @NbBundle.Messages({"ILeappAnalyzerModuleFactory_moduleDesc=Runs iLeapp against files."}) + @NbBundle.Messages({"ILeappAnalyzerModuleFactory_moduleDesc=Uses iLEAPP to analyze logical acquisitions of iOS devices."}) @Override public String getModuleDescription() { return Bundle.ILeappAnalyzerModuleFactory_moduleDesc(); From 181cf860d141819658c205d64476c6f3c81b8b6a Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Mon, 14 Sep 2020 22:46:07 -0400 Subject: [PATCH 24/26] Update Bundle.properties-MERGED Missed file --- .../autopsy/modules/ileappanalyzer/Bundle.properties-MERGED | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/ileappanalyzer/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/ileappanalyzer/Bundle.properties-MERGED index 8638a2c121..b4f350f478 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/ileappanalyzer/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/ileappanalyzer/Bundle.properties-MERGED @@ -12,8 +12,8 @@ ILeappAnalyzerIngestModule.report.name=iLeapp Html Report ILeappAnalyzerIngestModule.requires.windows=iLeapp module requires windows. ILeappAnalyzerIngestModule.running.iLeapp=Running iLeapp ILeappAnalyzerIngestModule.starting.iLeapp=Starting iLeapp -ILeappAnalyzerModuleFactory_moduleDesc=Runs iLeapp against files. -ILeappAnalyzerModuleFactory_moduleName=ILeapp Analyzer +ILeappAnalyzerModuleFactory_moduleDesc=Uses iLEAPP to analyze logical acquisitions of iOS devices. +ILeappAnalyzerModuleFactory_moduleName=iOS Analyzer (iLEAPP) ILeappFileProcessor.cannot.load.artifact.xml=Cannor load xml artifact file. ILeappFileProcessor.cannotBuildXmlParser=Cannot buld an XML parser. ILeappFileProcessor.completed=iLeapp Processing Completed From cc4962783a100a6263fb037575c998bedab3ab49 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 15 Sep 2020 13:48:36 -0400 Subject: [PATCH 25/26] Fixed deprecation warnings --- Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index 5f1653bf7a..872acfb8b3 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -38,6 +38,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.Iterator; import java.util.List; +import java.util.Objects; import static java.util.Objects.nonNull; import java.util.SortedSet; import java.util.TreeSet; @@ -962,7 +963,7 @@ public class ImageUtils { LOGGER.log(Level.WARNING, IMAGEIO_COULD_NOT_READ_UNSUPPORTED_OR_CORRUPT, ImageUtils.getContentPathSafe(file)); } else if (fxImage.isError()) { //if there was somekind of error, log it - LOGGER.log(Level.WARNING, IMAGEIO_COULD_NOT_READ_UNSUPPORTED_OR_CORRUPT + ": " + ObjectUtils.toString(fxImage.getException()), ImageUtils.getContentPathSafe(file)); + LOGGER.log(Level.WARNING, IMAGEIO_COULD_NOT_READ_UNSUPPORTED_OR_CORRUPT + ": " + Objects.toString(fxImage.getException()), ImageUtils.getContentPathSafe(file)); } } catch (InterruptedException | ExecutionException ex) { failed(); @@ -972,7 +973,7 @@ public class ImageUtils { @Override protected void failed() { super.failed(); - LOGGER.log(Level.WARNING, IMAGEIO_COULD_NOT_READ_UNSUPPORTED_OR_CORRUPT + ": " + ObjectUtils.toString(getException()), ImageUtils.getContentPathSafe(file)); + LOGGER.log(Level.WARNING, IMAGEIO_COULD_NOT_READ_UNSUPPORTED_OR_CORRUPT + ": " + Objects.toString(getException()), ImageUtils.getContentPathSafe(file)); } @Override From 0fd27226c840aab7601a73f4df117b9c0b99ff78 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 15 Sep 2020 13:49:28 -0400 Subject: [PATCH 26/26] Removed unused import --- Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index 872acfb8b3..6ae521de1e 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -59,7 +59,6 @@ import javax.imageio.ImageReadParam; import javax.imageio.ImageReader; import javax.imageio.event.IIOReadProgressListener; import javax.imageio.stream.ImageInputStream; -import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.openide.util.NbBundle;