diff --git a/Core/build.xml b/Core/build.xml index 898b17eff5..609fb1367b 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -91,6 +91,10 @@ + + + + diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/ArtifactKey.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/ArtifactKey.java deleted file mode 100644 index 1594456a97..0000000000 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/ArtifactKey.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Central Repository - * - * Copyright 2015-2017 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.centralrepository.contentviewer; - -import java.util.Objects; - -/** - * Used as a key to ensure we eliminate duplicates from the result set by not overwriting CR correlation instances. - */ -final class ArtifactKey { - - private final String dataSourceID; - private final String filePath; - - ArtifactKey(String theDataSource, String theFilePath) { - dataSourceID = theDataSource; - filePath = theFilePath.toLowerCase(); - } - - - /** - * - * @return the dataSourceID device ID - */ - String getDataSourceID() { - return dataSourceID; - } - - /** - * - * @return the filPath including the filename and extension. - */ - String getFilePath() { - return filePath; - } - - @Override - public boolean equals(Object other) { - if (other instanceof ArtifactKey) { - return ((ArtifactKey) other).getDataSourceID().equals(dataSourceID) && ((ArtifactKey) other).getFilePath().equals(filePath); - } - return false; - - } - - @Override - public int hashCode() { - //int hash = 7; - //hash = 67 * hash + this.dataSourceID.hashCode(); - //hash = 67 * hash + this.filePath.hashCode(); - - return Objects.hash(dataSourceID, filePath); - } -} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index b1ec30b4d7..2a9fd30a49 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -18,7 +18,9 @@ */ package org.sleuthkit.autopsy.centralrepository.contentviewer; +import java.awt.Color; import java.awt.Component; +import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedWriter; @@ -31,19 +33,30 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import java.util.stream.Collectors; +import javax.swing.GroupLayout; import javax.swing.JFileChooser; +import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import static javax.swing.JOptionPane.DEFAULT_OPTION; import static javax.swing.JOptionPane.PLAIN_MESSAGE; import static javax.swing.JOptionPane.ERROR_MESSAGE; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.LayoutStyle; +import javax.swing.ListSelectionModel; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; +import org.openide.awt.Mnemonics; import org.openide.nodes.Node; +import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.Case; @@ -65,14 +78,16 @@ import org.sleuthkit.datamodel.TskException; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.datamodel.TskDataException; /** * View correlation results from other cases */ +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives @ServiceProvider(service = DataContentViewer.class, position = 8) @Messages({"DataContentViewerOtherCases.title=Other Occurrences", "DataContentViewerOtherCases.toolTip=Displays instances of the selected file/artifact from other occurrences.",}) -public class DataContentViewerOtherCases extends javax.swing.JPanel implements DataContentViewer { +public class DataContentViewerOtherCases extends JPanel implements DataContentViewer { private final static Logger LOGGER = Logger.getLogger(DataContentViewerOtherCases.class.getName()); @@ -451,12 +466,12 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D * * @return A collection of correlated artifact instances from other cases */ - private Map getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) { + private Map getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) { // @@@ Check exception try { final Case openCase = Case.getCurrentCase(); String caseUUID = openCase.getName(); - HashMap artifactInstances = new HashMap<>(); + HashMap artifactInstances = new HashMap<>(); if (EamDb.isEnabled()) { EamDb dbManager = EamDb.getInstance(); @@ -464,8 +479,7 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D .filter(artifactInstance -> !artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID) || !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName) || !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)) - .collect(Collectors.toMap( - correlationAttr -> new ArtifactKey(correlationAttr.getCorrelationDataSource().getDeviceID(), correlationAttr.getFilePath()), + .collect(Collectors.toMap(correlationAttr -> new UniquePathKey(correlationAttr.getCorrelationDataSource().getDeviceID(), correlationAttr.getFilePath()), correlationAttr -> correlationAttr))); } @@ -507,29 +521,59 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D } - private void addOrUpdateAttributeInstance(final Case openCase, Map artifactInstances, AbstractFile caseDbFile) throws TskCoreException, EamDbException { - CorrelationCase caze = new CorrelationCase(openCase.getNumber(), openCase.getDisplayName()); - CorrelationDataSource dataSource = CorrelationDataSource.fromTSKDataSource(caze, caseDbFile.getDataSource()); - String filePath = caseDbFile.getParentPath() + caseDbFile.getName(); - ArtifactKey instKey = new ArtifactKey(dataSource.getDeviceID(), filePath); - CorrelationAttributeInstance caseDbInstance = new CorrelationAttributeInstance(caze, dataSource, filePath, "", caseDbFile.getKnown()); - TskData.FileKnown knownStatus = caseDbInstance.getKnownStatus(); - // If not known, check Tags for known and set - TskData.FileKnown knownBad = TskData.FileKnown.BAD; - if (!knownStatus.equals(knownBad)) { - List fileMatchTags = openCase.getServices().getTagsManager().getContentTagsByContent(caseDbFile); + /** + * Adds the file to the artifactInstances map if it does not already exist + * + * @param autopsyCase + * @param artifactInstances + * @param newFile + * @throws TskCoreException + * @throws EamDbException + */ + private void addOrUpdateAttributeInstance(final Case autopsyCase, Map artifactInstances, AbstractFile newFile) throws TskCoreException, EamDbException { + + // figure out if the casedb file is known via either hash or tags + TskData.FileKnown localKnown = newFile.getKnown(); + + if (localKnown != TskData.FileKnown.BAD) { + List fileMatchTags = autopsyCase.getServices().getTagsManager().getContentTagsByContent(newFile); for (ContentTag tag : fileMatchTags) { TskData.FileKnown tagKnownStatus = tag.getName().getKnownStatus(); - if (tagKnownStatus.equals(knownBad)) { - caseDbInstance.setKnownStatus(knownBad); + if (tagKnownStatus.equals(TskData.FileKnown.BAD)) { + localKnown = TskData.FileKnown.BAD; break; } } } - // If known, or not in CR, add - if (caseDbInstance.getKnownStatus().equals(knownBad) || !artifactInstances.containsKey(instKey)) { - artifactInstances.put(instKey, caseDbInstance); + // make a key to see if the file is already in the map + String filePath = newFile.getParentPath() + newFile.getName(); + String deviceId; + try { + deviceId = autopsyCase.getSleuthkitCase().getDataSource(newFile.getDataSource().getId()).getDeviceId(); + } catch (TskDataException | TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error getting data source info: " + ex); + return; + } + UniquePathKey uniquePathKey = new UniquePathKey(deviceId, filePath); + + // double check that the CR version is BAD if the caseDB version is BAD. + if (artifactInstances.containsKey(uniquePathKey)) { + if (localKnown == TskData.FileKnown.BAD) { + CorrelationAttributeInstance prevInstance = artifactInstances.get(uniquePathKey); + prevInstance.setKnownStatus(localKnown); + } + } + // add the data from the case DB by pushing data into CorrelationAttributeInstance class + else { + // NOTE: If we are in here, it is likely because CR is not enabled. So, we cannot rely + // on any of the methods that query the DB. + CorrelationCase correlationCase = new CorrelationCase(autopsyCase.getName(), autopsyCase.getDisplayName()); + + CorrelationDataSource correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, newFile.getDataSource()); + + CorrelationAttributeInstance caseDbInstance = new CorrelationAttributeInstance(correlationCase, correlationDataSource, filePath, "", localKnown); + artifactInstances.put(uniquePathKey, caseDbInstance); } } @@ -588,7 +632,7 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D // get the attributes we can correlate on correlationAttributes.addAll(getCorrelationAttributesFromNode(node)); for (CorrelationAttribute corAttr : correlationAttributes) { - Map corAttrInstances = new HashMap<>(0); + Map corAttrInstances = new HashMap<>(0); // get correlation and reference set instances from DB corAttrInstances.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId)); @@ -608,6 +652,7 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D } if (correlationAttributes.isEmpty()) { + // @@@ BC: We should have a more descriptive message than this. Mention that the file didn't have a MD5, etc. displayMessageOnTableStatusPanel(Bundle.DataContentViewerOtherCases_table_noArtifacts()); } else if (0 == tableModel.getRowCount()) { displayMessageOnTableStatusPanel(Bundle.DataContentViewerOtherCases_table_isempty()); @@ -645,131 +690,170 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D // //GEN-BEGIN:initComponents private void initComponents() { - rightClickPopupMenu = new javax.swing.JPopupMenu(); - selectAllMenuItem = new javax.swing.JMenuItem(); - exportToCSVMenuItem = new javax.swing.JMenuItem(); - showCaseDetailsMenuItem = new javax.swing.JMenuItem(); - showCommonalityMenuItem = new javax.swing.JMenuItem(); - CSVFileChooser = new javax.swing.JFileChooser(); - otherCasesPanel = new javax.swing.JPanel(); - tableContainerPanel = new javax.swing.JPanel(); - tableScrollPane = new javax.swing.JScrollPane(); - otherCasesTable = new javax.swing.JTable(); - tableStatusPanel = new javax.swing.JPanel(); - tableStatusPanelLabel = new javax.swing.JLabel(); + rightClickPopupMenu = new JPopupMenu(); + selectAllMenuItem = new JMenuItem(); + exportToCSVMenuItem = new JMenuItem(); + showCaseDetailsMenuItem = new JMenuItem(); + showCommonalityMenuItem = new JMenuItem(); + CSVFileChooser = new JFileChooser(); + otherCasesPanel = new JPanel(); + tableContainerPanel = new JPanel(); + tableScrollPane = new JScrollPane(); + otherCasesTable = new JTable(); + tableStatusPanel = new JPanel(); + tableStatusPanelLabel = new JLabel(); - org.openide.awt.Mnemonics.setLocalizedText(selectAllMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.selectAllMenuItem.text")); // NOI18N + Mnemonics.setLocalizedText(selectAllMenuItem, NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.selectAllMenuItem.text")); // NOI18N rightClickPopupMenu.add(selectAllMenuItem); - org.openide.awt.Mnemonics.setLocalizedText(exportToCSVMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.exportToCSVMenuItem.text")); // NOI18N + Mnemonics.setLocalizedText(exportToCSVMenuItem, NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.exportToCSVMenuItem.text")); // NOI18N rightClickPopupMenu.add(exportToCSVMenuItem); - org.openide.awt.Mnemonics.setLocalizedText(showCaseDetailsMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCaseDetailsMenuItem.text")); // NOI18N + Mnemonics.setLocalizedText(showCaseDetailsMenuItem, NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCaseDetailsMenuItem.text")); // NOI18N rightClickPopupMenu.add(showCaseDetailsMenuItem); - org.openide.awt.Mnemonics.setLocalizedText(showCommonalityMenuItem, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCommonalityMenuItem.text")); // NOI18N + Mnemonics.setLocalizedText(showCommonalityMenuItem, NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.showCommonalityMenuItem.text")); // NOI18N rightClickPopupMenu.add(showCommonalityMenuItem); - setMinimumSize(new java.awt.Dimension(1500, 10)); + setMinimumSize(new Dimension(1500, 10)); setOpaque(false); - setPreferredSize(new java.awt.Dimension(1500, 44)); + setPreferredSize(new Dimension(1500, 44)); - otherCasesPanel.setPreferredSize(new java.awt.Dimension(1500, 144)); + otherCasesPanel.setPreferredSize(new Dimension(1500, 144)); - tableContainerPanel.setPreferredSize(new java.awt.Dimension(1500, 63)); + tableContainerPanel.setPreferredSize(new Dimension(1500, 63)); - tableScrollPane.setPreferredSize(new java.awt.Dimension(1500, 30)); + tableScrollPane.setPreferredSize(new Dimension(1500, 30)); otherCasesTable.setAutoCreateRowSorter(true); otherCasesTable.setModel(tableModel); - otherCasesTable.setToolTipText(org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.table.toolTip.text")); // NOI18N + otherCasesTable.setToolTipText(NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.table.toolTip.text")); // NOI18N otherCasesTable.setComponentPopupMenu(rightClickPopupMenu); - otherCasesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION); + otherCasesTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); tableScrollPane.setViewportView(otherCasesTable); - tableStatusPanel.setPreferredSize(new java.awt.Dimension(1500, 16)); + tableStatusPanel.setPreferredSize(new Dimension(1500, 16)); - tableStatusPanelLabel.setForeground(new java.awt.Color(255, 0, 51)); + tableStatusPanelLabel.setForeground(new Color(255, 0, 51)); - javax.swing.GroupLayout tableStatusPanelLayout = new javax.swing.GroupLayout(tableStatusPanel); + GroupLayout tableStatusPanelLayout = new GroupLayout(tableStatusPanel); tableStatusPanel.setLayout(tableStatusPanelLayout); - tableStatusPanelLayout.setHorizontalGroup( - tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + tableStatusPanelLayout.setHorizontalGroup(tableStatusPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGap(0, 0, Short.MAX_VALUE) - .addGroup(tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(tableStatusPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(tableStatusPanelLayout.createSequentialGroup() .addContainerGap() - .addComponent(tableStatusPanelLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE) + .addComponent(tableStatusPanelLabel, GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE) .addContainerGap())) ); - tableStatusPanelLayout.setVerticalGroup( - tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + tableStatusPanelLayout.setVerticalGroup(tableStatusPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGap(0, 16, Short.MAX_VALUE) - .addGroup(tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(tableStatusPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(tableStatusPanelLayout.createSequentialGroup() - .addComponent(tableStatusPanelLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(tableStatusPanelLabel, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE) .addGap(0, 0, Short.MAX_VALUE))) ); - javax.swing.GroupLayout tableContainerPanelLayout = new javax.swing.GroupLayout(tableContainerPanel); + GroupLayout tableContainerPanelLayout = new GroupLayout(tableContainerPanel); tableContainerPanel.setLayout(tableContainerPanelLayout); - tableContainerPanelLayout.setHorizontalGroup( - tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(tableScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(tableStatusPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + tableContainerPanelLayout.setHorizontalGroup(tableContainerPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(tableScrollPane, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(tableStatusPanel, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); - tableContainerPanelLayout.setVerticalGroup( - tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + tableContainerPanelLayout.setVerticalGroup(tableContainerPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(tableContainerPanelLayout.createSequentialGroup() - .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(tableStatusPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(tableScrollPane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(tableStatusPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addContainerGap()) ); - javax.swing.GroupLayout otherCasesPanelLayout = new javax.swing.GroupLayout(otherCasesPanel); + GroupLayout otherCasesPanelLayout = new GroupLayout(otherCasesPanel); otherCasesPanel.setLayout(otherCasesPanelLayout); - otherCasesPanelLayout.setHorizontalGroup( - otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + otherCasesPanelLayout.setHorizontalGroup(otherCasesPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGap(0, 1500, Short.MAX_VALUE) - .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(tableContainerPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(otherCasesPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(tableContainerPanel, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); - otherCasesPanelLayout.setVerticalGroup( - otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + otherCasesPanelLayout.setVerticalGroup(otherCasesPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGap(0, 60, Short.MAX_VALUE) - .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(otherCasesPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(otherCasesPanelLayout.createSequentialGroup() - .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 60, Short.MAX_VALUE) + .addComponent(tableContainerPanel, GroupLayout.DEFAULT_SIZE, 60, Short.MAX_VALUE) .addGap(0, 0, 0))) ); - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + GroupLayout layout = new GroupLayout(this); this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(otherCasesPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 60, Short.MAX_VALUE) + layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(otherCasesPanel, GroupLayout.DEFAULT_SIZE, 60, Short.MAX_VALUE) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JFileChooser CSVFileChooser; - private javax.swing.JMenuItem exportToCSVMenuItem; - private javax.swing.JPanel otherCasesPanel; - private javax.swing.JTable otherCasesTable; - private javax.swing.JPopupMenu rightClickPopupMenu; - private javax.swing.JMenuItem selectAllMenuItem; - private javax.swing.JMenuItem showCaseDetailsMenuItem; - private javax.swing.JMenuItem showCommonalityMenuItem; - private javax.swing.JPanel tableContainerPanel; - private javax.swing.JScrollPane tableScrollPane; - private javax.swing.JPanel tableStatusPanel; - private javax.swing.JLabel tableStatusPanelLabel; + private JFileChooser CSVFileChooser; + private JMenuItem exportToCSVMenuItem; + private JPanel otherCasesPanel; + private JTable otherCasesTable; + private JPopupMenu rightClickPopupMenu; + private JMenuItem selectAllMenuItem; + private JMenuItem showCaseDetailsMenuItem; + private JMenuItem showCommonalityMenuItem; + private JPanel tableContainerPanel; + private JScrollPane tableScrollPane; + private JPanel tableStatusPanel; + private JLabel tableStatusPanelLabel; // End of variables declaration//GEN-END:variables + /** + * Used as a key to ensure we eliminate duplicates from the result set by not overwriting CR correlation instances. + */ + static final class UniquePathKey { + + private final String dataSourceID; + private final String filePath; + + UniquePathKey(String theDataSource, String theFilePath) { + super(); + dataSourceID = theDataSource; + filePath = theFilePath.toLowerCase(); + } + + /** + * + * @return the dataSourceID device ID + */ + String getDataSourceID() { + return dataSourceID; + } + + /** + * + * @return the filPath including the filename and extension. + */ + String getFilePath() { + return filePath; + } + + @Override + public boolean equals(Object other) { + if (other instanceof UniquePathKey) { + return ((UniquePathKey) other).getDataSourceID().equals(dataSourceID) && ((UniquePathKey) other).getFilePath().equals(filePath); + } + return false; + } + + @Override + public int hashCode() { + //int hash = 7; + //hash = 67 * hash + this.dataSourceID.hashCode(); + //hash = 67 * hash + this.filePath.hashCode(); + return Objects.hash(dataSourceID, filePath); + } + } + } diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/AllDataSourcesCommonFilesAlgorithm.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/AllDataSourcesCommonFilesAlgorithm.java index f752fbabad..044241ccf5 100644 --- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/AllDataSourcesCommonFilesAlgorithm.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/AllDataSourcesCommonFilesAlgorithm.java @@ -24,7 +24,7 @@ import java.util.Map; /** * Provides logic for selecting common files from all data sources. */ -final class AllDataSourcesCommonFilesAlgorithm extends CommonFilesMetadataBuilder { +final public class AllDataSourcesCommonFilesAlgorithm extends CommonFilesMetadataBuilder { private static final String WHERE_CLAUSE = "%s md5 in (select md5 from tsk_files where (known != 1 OR known IS NULL)%s GROUP BY md5 HAVING COUNT(*) > 1) order by md5"; //NON-NLS @@ -36,7 +36,7 @@ final class AllDataSourcesCommonFilesAlgorithm extends CommonFilesMetadataBuilde * @param filterByMediaMimeType match only on files whose mime types can be broadly categorized as media types * @param filterByDocMimeType match only on files whose mime types can be broadly categorized as document types */ - AllDataSourcesCommonFilesAlgorithm(Map dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) { + public AllDataSourcesCommonFilesAlgorithm(Map dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) { super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType); } diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonFilesMetadata.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonFilesMetadata.java index 7b7b10b828..de06db45a4 100644 --- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonFilesMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonFilesMetadata.java @@ -26,7 +26,7 @@ import java.util.Map; * Utility and wrapper model around data required for Common Files Search results. * Subclass this to implement different selections of files from the case. */ -final class CommonFilesMetadata { +final public class CommonFilesMetadata { private final Map metadata; @@ -52,7 +52,7 @@ final class CommonFilesMetadata { return this.metadata.get(md5); } - Map getMetadata() { + public Map getMetadata() { return Collections.unmodifiableMap(this.metadata); } @@ -60,7 +60,7 @@ final class CommonFilesMetadata { * How many distinct file instances exist for this metadata? * @return number of file instances */ - int size() { + public int size() { int count = 0; for (Md5Metadata data : this.metadata.values()) { count += data.size(); diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonFilesMetadataBuilder.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonFilesMetadataBuilder.java index d137368cfe..6fee774102 100644 --- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonFilesMetadataBuilder.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonFilesMetadataBuilder.java @@ -46,7 +46,7 @@ import org.sleuthkit.datamodel.TskCoreException; * This entire thing runs on a background thread where exceptions are handled. */ @SuppressWarnings("PMD.AbstractNaming") -abstract class CommonFilesMetadataBuilder { +public abstract class CommonFilesMetadataBuilder { private final Map dataSourceIdToNameMap; private final boolean filterByMedia; diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonFilesPanel.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonFilesPanel.java index 630efaead3..3ce2c34e26 100644 --- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonFilesPanel.java @@ -18,12 +18,9 @@ */ package org.sleuthkit.autopsy.commonfilesearch; -import java.io.File; -import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ExecutionException; @@ -33,7 +30,6 @@ import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.openide.explorer.ExplorerManager; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; @@ -42,8 +38,6 @@ import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; -import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; /** @@ -76,7 +70,7 @@ public final class CommonFilesPanel extends javax.swing.JPanel { initComponents(); this.setupDataSources(); - + this.errorText.setVisible(false); } @@ -97,10 +91,6 @@ public final class CommonFilesPanel extends javax.swing.JPanel { new SwingWorker, Void>() { - private static final String SELECT_DATA_SOURCES_LOGICAL = "select obj_id, name from tsk_files where obj_id in (SELECT obj_id FROM tsk_objects WHERE obj_id in (select obj_id from data_source_info))"; - - private static final String SELECT_DATA_SOURCES_IMAGE = "select obj_id, name from tsk_image_names where obj_id in (SELECT obj_id FROM tsk_objects WHERE obj_id in (select obj_id from data_source_info))"; - private void updateUi() { String[] dataSourcesNames = new String[CommonFilesPanel.this.dataSourceMap.size()]; @@ -131,48 +121,10 @@ public final class CommonFilesPanel extends javax.swing.JPanel { return CommonFilesPanel.this.dataSourceMap.size() >= 2; } - private void loadLogicalSources(SleuthkitCase tskDb, Map dataSouceMap) throws TskCoreException, SQLException { - //try block releases resources - exceptions are handled in done() - try ( - CaseDbQuery query = tskDb.executeQuery(SELECT_DATA_SOURCES_LOGICAL); - ResultSet resultSet = query.getResultSet()) { - while (resultSet.next()) { - Long objectId = resultSet.getLong(1); - String dataSourceName = resultSet.getString(2); - dataSouceMap.put(objectId, dataSourceName); - } - } - } - - private void loadImageSources(SleuthkitCase tskDb, Map dataSouceMap) throws SQLException, TskCoreException { - //try block releases resources - exceptions are handled in done() - try ( - CaseDbQuery query = tskDb.executeQuery(SELECT_DATA_SOURCES_IMAGE); - ResultSet resultSet = query.getResultSet()) { - - while (resultSet.next()) { - Long objectId = resultSet.getLong(1); - String dataSourceName = resultSet.getString(2); - File image = new File(dataSourceName); - String dataSourceNameTrimmed = image.getName(); - dataSouceMap.put(objectId, dataSourceNameTrimmed); - } - } - } - @Override protected Map doInBackground() throws NoCurrentCaseException, TskCoreException, SQLException { - - Map dataSouceMap = new HashMap<>(); - - Case currentCase = Case.getCurrentCaseThrows(); - SleuthkitCase tskDb = currentCase.getSleuthkitCase(); - - loadLogicalSources(tskDb, dataSouceMap); - - loadImageSources(tskDb, dataSouceMap); - - return dataSouceMap; + DataSourceLoader loader = new DataSourceLoader(); + return loader.getDataSourceMap(); } @Override @@ -295,10 +247,10 @@ public final class CommonFilesPanel extends javax.swing.JPanel { TableFilterNode tableFilterWithDescendantsNode = new TableFilterNode(dataResultFilterNode); DataResultViewerTable table = new DataResultViewerTable(); - + Collection viewers = new ArrayList<>(1); viewers.add(table); - + DataResultTopComponent.createInstance(tabTitle, pathText, tableFilterWithDescendantsNode, metadata.size(), viewers); } catch (InterruptedException ex) { @@ -590,7 +542,7 @@ public final class CommonFilesPanel extends javax.swing.JPanel { this.pictureVideoCheckbox.setEnabled(true); this.documentsCheckbox.setEnabled(true); - + this.toggleErrorTextAndSearchBox(); } } diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/DataSourceLoader.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/DataSourceLoader.java new file mode 100644 index 0000000000..69af771dad --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/DataSourceLoader.java @@ -0,0 +1,95 @@ +/* + * + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.commonfilesearch; + +import java.io.File; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Encapsulates logic required to create a mapping of data sources in the + * current case to their data source IDs. + * + * Intended to be used within the context of a SwingWorker or other background + * thread. + */ +public class DataSourceLoader { + + private static final String SELECT_DATA_SOURCES_LOGICAL = "select obj_id, name from tsk_files where obj_id in (SELECT obj_id FROM tsk_objects WHERE obj_id in (select obj_id from data_source_info))"; + + private static final String SELECT_DATA_SOURCES_IMAGE = "select obj_id, name from tsk_image_names where obj_id in (SELECT obj_id FROM tsk_objects WHERE obj_id in (select obj_id from data_source_info))"; + + private void loadLogicalSources(SleuthkitCase tskDb, Map dataSouceMap) throws TskCoreException, SQLException { + //try block releases resources - exceptions are handled in done() + try ( + SleuthkitCase.CaseDbQuery query = tskDb.executeQuery(SELECT_DATA_SOURCES_LOGICAL); + ResultSet resultSet = query.getResultSet() + ) { + while (resultSet.next()) { + Long objectId = resultSet.getLong(1); + String dataSourceName = resultSet.getString(2); + dataSouceMap.put(objectId, dataSourceName); + } + } + } + + private void loadImageSources(SleuthkitCase tskDb, Map dataSouceMap) throws SQLException, TskCoreException { + //try block releases resources - exceptions are handled in done() + try ( + SleuthkitCase.CaseDbQuery query = tskDb.executeQuery(SELECT_DATA_SOURCES_IMAGE); + ResultSet resultSet = query.getResultSet()) { + + while (resultSet.next()) { + Long objectId = resultSet.getLong(1); + String dataSourceName = resultSet.getString(2); + File image = new File(dataSourceName); + String dataSourceNameTrimmed = image.getName(); + dataSouceMap.put(objectId, dataSourceNameTrimmed); + } + } + } + + /** + * Get a map of data source Ids to their string names for the current case. + * + * @return Map of Long (id) to String (name) + * @throws NoCurrentCaseException + * @throws TskCoreException + * @throws SQLException + */ + public Map getDataSourceMap() throws NoCurrentCaseException, TskCoreException, SQLException { + Map dataSouceMap = new HashMap<>(); + + Case currentCase = Case.getCurrentCaseThrows(); + SleuthkitCase tskDb = currentCase.getSleuthkitCase(); + + loadLogicalSources(tskDb, dataSouceMap); + + loadImageSources(tskDb, dataSouceMap); + + return dataSouceMap; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/SingleDataSource.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/SingleDataSource.java index bc506f5988..f3f8ef689d 100644 --- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/SingleDataSource.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/SingleDataSource.java @@ -24,7 +24,7 @@ import java.util.Map; /** * Provides logic for selecting common files from a single data source. */ -final class SingleDataSource extends CommonFilesMetadataBuilder { +final public class SingleDataSource extends CommonFilesMetadataBuilder { private static final String WHERE_CLAUSE = "%s md5 in (select md5 from tsk_files where md5 in (select md5 from tsk_files where (known != 1 OR known IS NULL) and data_source_obj_id=%s%s) GROUP BY md5 HAVING COUNT(*) > 1) order by md5"; //NON-NLS private final Long selectedDataSourceId; @@ -35,10 +35,12 @@ final class SingleDataSource extends CommonFilesMetadataBuilder { * once in the given data source * @param dataSourceId data source id for which common files must appear at least once * @param dataSourceIdMap a map of obj_id to datasource name - * @param filterByMediaMimeType match only on files whose mime types can be broadly categorized as media types - * @param filterByDocMimeType match only on files whose mime types can be broadly categorized as document types + * @param filterByMediaMimeType match only on files whose mime types can be + * broadly categorized as media types + * @param filterByDocMimeType match only on files whose mime types can be + * broadly categorized as document types */ - SingleDataSource(Long dataSourceId, Map dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) { + public SingleDataSource(Long dataSourceId, Map dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) { super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType); this.selectedDataSourceId = dataSourceId; this.dataSourceName = dataSourceIdMap.get(this.selectedDataSourceId); diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/TimingMetricGraphPanel.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/TimingMetricGraphPanel.java index 6d995ed9ac..8d4a57b4f6 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/TimingMetricGraphPanel.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/TimingMetricGraphPanel.java @@ -373,7 +373,7 @@ class TimingMetricGraphPanel extends JPanel { } } else if (y0value > maxValueOnYAxis) { try { - y0value = minValueOnYAxis; + y0value = maxValueOnYAxis; x0value = trendLine.getXGivenY(y0value); } catch (HealthMonitorException ex) { // The exception is caused by a slope of zero on the trend line, which diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties index c80ccaa863..dfda2e6061 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties @@ -9,8 +9,8 @@ OpenIDE-Module-Name=Embedded File Extraction OpenIDE-Module-Short-Description=Embedded File Extraction Ingest Module EmbeddedFileExtractorIngestModule.SevenZipContentReadStream.seek.exception.invalidOrigin=Invalid seek origin\: {0} EmbeddedFileExtractorIngestModule.SevenZipContentReadStream.read.exception.errReadStream=Error reading content stream. -EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFileLevel=File-level Encryption -EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFull=Full Encryption +EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFileLevel=Content-only Encryption (Archive File) +EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFull=Full Encryption (Archive File) EmbeddedFileExtractorIngestModule.ArchiveExtractor.init.errInitModule.details=Error initializing output dir\: {0}\: {1} EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg=Possible ZIP bomb detected in archive\: {0}, item\: {1} EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnDetails=Compression ratio is {0}, skipping item in {1}. diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java index 257f90ad2f..068c52cf5e 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java @@ -18,8 +18,6 @@ */ package org.sleuthkit.autopsy.modules.hashdatabase; -import java.util.ArrayList; -import java.util.List; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/IngestedWithHashAndFileType.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/IngestedWithHashAndFileType.java new file mode 100644 index 0000000000..a599763346 --- /dev/null +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/IngestedWithHashAndFileType.java @@ -0,0 +1,465 @@ +/* + * + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.commonfilessearch; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import junit.framework.Test; +import org.netbeans.junit.NbModuleSuite; +import org.netbeans.junit.NbTestCase; +import org.openide.util.Exceptions; +import org.python.icu.impl.Assert; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.commonfilesearch.AllDataSourcesCommonFilesAlgorithm; +import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadata; +import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadataBuilder; +import org.sleuthkit.autopsy.commonfilesearch.SingleDataSource; +import static org.sleuthkit.autopsy.commonfilessearch.IntraCaseUtils.*; +import org.sleuthkit.autopsy.ingest.IngestJobSettings; +import org.sleuthkit.autopsy.ingest.IngestJobSettings.IngestType; +import org.sleuthkit.autopsy.ingest.IngestModuleTemplate; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeIdModuleFactory; +import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupModuleFactory; +import org.sleuthkit.autopsy.testutils.IngestUtils; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Add set 1, set 2, set 3, and set 4 to case and ingest with hash algorithm. + */ +public class IngestedWithHashAndFileType extends NbTestCase { + + public static Test suite() { + NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(IngestedWithHashAndFileType.class). + clusters(".*"). + enableModules(".*"); + return conf.suite(); + } + + private final IntraCaseUtils utils; + + public IngestedWithHashAndFileType(String name) { + super(name); + + this.utils = new IntraCaseUtils(this, "IngestedWithHashAndFileTypeTests"); + } + + @Override + public void setUp() { + this.utils.setUp(); + + IngestModuleTemplate hashLookupTemplate = IngestUtils.getIngestModuleTemplate(new HashLookupModuleFactory()); + IngestModuleTemplate mimeTypeLookupTemplate = IngestUtils.getIngestModuleTemplate(new FileTypeIdModuleFactory()); + + ArrayList templates = new ArrayList<>(); + templates.add(hashLookupTemplate); + templates.add(mimeTypeLookupTemplate); + + IngestJobSettings ingestJobSettings = new IngestJobSettings(IngestedWithHashAndFileType.class.getCanonicalName(), IngestType.FILES_ONLY, templates); + + try { + IngestUtils.runIngestJob(Case.getCurrentCaseThrows().getDataSources(), ingestJobSettings); + } catch (NoCurrentCaseException | TskCoreException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } + + @Override + public void tearDown() { + this.utils.tearDown(); + } + + /** + * Find all matches & all file types. Confirm file.jpg is found on all three + * and file.docx is found on two. + */ + public void testOneA() { + try { + Map dataSources = this.utils.getDataSourceMap(); + + CommonFilesMetadataBuilder allSourcesBuilder = new AllDataSourcesCommonFilesAlgorithm(dataSources, false, false); + CommonFilesMetadata metadata = allSourcesBuilder.findCommonFiles(); + + Map objectIdToDataSource = IntraCaseUtils.mapFileInstancesToDataSources(metadata); + + List files = IntraCaseUtils.getFiles(objectIdToDataSource.keySet()); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0)); + assertTrue(IntraCaseUtils.verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0)); + + } catch (NoCurrentCaseException | TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } + + /** + * Find all matches & only image types. Confirm file.jpg is found on all + * three. + */ + public void testOneB() { + try { + Map dataSources = this.utils.getDataSourceMap(); + + CommonFilesMetadataBuilder allSourcesBuilder = new AllDataSourcesCommonFilesAlgorithm(dataSources, true, false); + CommonFilesMetadata metadata = allSourcesBuilder.findCommonFiles(); + + Map objectIdToDataSource = mapFileInstancesToDataSources(metadata); + + List files = getFiles(objectIdToDataSource.keySet()); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0)); + + } catch (NoCurrentCaseException | TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } + + /** + * Find all matches & only image types. Confirm file.jpg is found on all + * three. + */ + public void testOneC() { + try { + Map dataSources = this.utils.getDataSourceMap(); + + CommonFilesMetadataBuilder allSourcesBuilder = new AllDataSourcesCommonFilesAlgorithm(dataSources, false, true); + CommonFilesMetadata metadata = allSourcesBuilder.findCommonFiles(); + + Map objectIdToDataSource = mapFileInstancesToDataSources(metadata); + + List files = getFiles(objectIdToDataSource.keySet()); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0)); + + } catch (NoCurrentCaseException | TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } + + /** + * Find matches on set 1 & all file types. Confirm same results. + * + */ + public void testTwoA() { + try { + Map dataSources = this.utils.getDataSourceMap(); + Long first = getDataSourceIdByName(SET1, dataSources); + + CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(first, dataSources, false, false); + CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles(); + + Map objectIdToDataSource = mapFileInstancesToDataSources(metadata); + + List files = getFiles(objectIdToDataSource.keySet()); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0)); + + } catch (NoCurrentCaseException | TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } + + /** + * Find matches on set 1 & only media types. Confirm same results. + * + */ + public void testTwoB() { + try { + Map dataSources = this.utils.getDataSourceMap(); + Long first = getDataSourceIdByName(SET1, dataSources); + + CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(first, dataSources, true, false); + CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles(); + + Map objectIdToDataSource = mapFileInstancesToDataSources(metadata); + + List files = getFiles(objectIdToDataSource.keySet()); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0)); + + } catch (NoCurrentCaseException | TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } + + /** + * Find matches on set 1 & all file types. Confirm same results. + * + */ + public void testTwoC() { + try { + Map dataSources = this.utils.getDataSourceMap(); + Long first = getDataSourceIdByName(SET1, dataSources); + + CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(first, dataSources, false, true); + CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles(); + + Map objectIdToDataSource = mapFileInstancesToDataSources(metadata); + + List files = getFiles(objectIdToDataSource.keySet()); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0)); + + } catch (NoCurrentCaseException | TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } + + /** + * Find matches on set 2 & all file types: Confirm file.jpg. + * + */ + public void testThree() { + try { + Map dataSources = this.utils.getDataSourceMap(); + Long second = getDataSourceIdByName(SET2, dataSources); + + CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(second, dataSources, false, false); + CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles(); + + Map objectIdToDataSource = mapFileInstancesToDataSources(metadata); + + List files = getFiles(objectIdToDataSource.keySet()); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0)); + + } catch (NoCurrentCaseException | TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } + + /** + * Find matches on set 4 & all file types: Confirm nothing is found. + */ + public void testFour() { + try { + Map dataSources = this.utils.getDataSourceMap(); + Long last = getDataSourceIdByName(SET4, dataSources); + + CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(last, dataSources, false, false); + CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles(); + + Map objectIdToDataSource = mapFileInstancesToDataSources(metadata); + + List files = getFiles(objectIdToDataSource.keySet()); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0)); + + } catch (NoCurrentCaseException | TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } + + /** + * Find matches on set 3 & all file types: Confirm file.jpg and file.docx. + */ + public void testFive() { + try { + Map dataSources = this.utils.getDataSourceMap(); + Long third = getDataSourceIdByName(SET3, dataSources); + + CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(third, dataSources, false, false); + CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles(); + + Map objectIdToDataSource = mapFileInstancesToDataSources(metadata); + + List files = getFiles(objectIdToDataSource.keySet()); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0)); + + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0)); + assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0)); + + } catch (NoCurrentCaseException | TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } +} diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/IngestedWithNoFileTypes.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/IngestedWithNoFileTypes.java new file mode 100644 index 0000000000..0090d0f699 --- /dev/null +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/IngestedWithNoFileTypes.java @@ -0,0 +1,140 @@ +/* + * + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.commonfilessearch; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import static junit.framework.Assert.assertTrue; +import junit.framework.Test; +import org.netbeans.junit.NbModuleSuite; +import org.netbeans.junit.NbTestCase; +import org.openide.util.Exceptions; +import org.python.icu.impl.Assert; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.commonfilesearch.AllDataSourcesCommonFilesAlgorithm; +import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadata; +import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadataBuilder; +import org.sleuthkit.autopsy.commonfilesearch.SingleDataSource; +import org.sleuthkit.autopsy.ingest.IngestJobSettings; +import org.sleuthkit.autopsy.ingest.IngestModuleTemplate; +import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupModuleFactory; +import org.sleuthkit.autopsy.testutils.IngestUtils; +import static org.sleuthkit.autopsy.testutils.IngestUtils.getIngestModuleTemplate; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Ingested w/o mime type info added to DB. + * + * Setup: + * + * Add images set 1, set 2, set 3, and set 4 to case. Do not run mime type + * module. + */ +public class IngestedWithNoFileTypes extends NbTestCase { + + public static Test suite() { + NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(IngestedWithNoFileTypes.class). + clusters(".*"). + enableModules(".*"); + return conf.suite(); + } + + private final IntraCaseUtils utils; + + public IngestedWithNoFileTypes(String name) { + super(name); + + this.utils = new IntraCaseUtils(this, "IngestedWithNoFileTypes"); + } + + @Override + public void setUp() { + this.utils.setUp(); + + IngestModuleTemplate hashLookupTemplate = getIngestModuleTemplate(new HashLookupModuleFactory()); + + ArrayList templates = new ArrayList<>(); + templates.add(hashLookupTemplate); + + IngestJobSettings ingestJobSettings = new IngestJobSettings(IngestedWithHashAndFileType.class.getCanonicalName(), IngestJobSettings.IngestType.FILES_ONLY, templates); + + try { + IngestUtils.runIngestJob(Case.getCurrentCaseThrows().getDataSources(), ingestJobSettings); + } catch (NoCurrentCaseException | TskCoreException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } + + @Override + public void tearDown(){ + this.utils.tearDown(); + } + + /** + * Search using all data sources and filtering for media types. We should + * find nothing and no errors should arise. + */ + public void testOne() { + try { + Map dataSources = this.utils.getDataSourceMap(); + + CommonFilesMetadataBuilder allSourcesBuilder = new AllDataSourcesCommonFilesAlgorithm(dataSources, true, false); + CommonFilesMetadata metadata = allSourcesBuilder.findCommonFiles(); + + Map objectIdToDataSource = IntraCaseUtils.mapFileInstancesToDataSources(metadata); + + List files = IntraCaseUtils.getFiles(objectIdToDataSource.keySet()); + + assertTrue(files.isEmpty()); + + } catch (NoCurrentCaseException | TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + } + } + + /** + * Search using single data source and filtering for doc types. Observe that + * nothing is found and that nothing blows up. + */ + public void testTwo() { + try { + Map dataSources = this.utils.getDataSourceMap(); + Long third = IntraCaseUtils.getDataSourceIdByName(IntraCaseUtils.SET3, dataSources); + + CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(third, dataSources, true, false); + CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles(); + + Map objectIdToDataSource = IntraCaseUtils.mapFileInstancesToDataSources(metadata); + + List files = IntraCaseUtils.getFiles(objectIdToDataSource.keySet()); + + assertTrue(files.isEmpty()); + + } catch (NoCurrentCaseException | TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } +} diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/IntraCaseUtils.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/IntraCaseUtils.java new file mode 100644 index 0000000000..66a68f3a38 --- /dev/null +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/IntraCaseUtils.java @@ -0,0 +1,220 @@ +/* + * + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.commonfilessearch; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.netbeans.junit.NbTestCase; +import org.openide.util.Exceptions; +import org.python.icu.impl.Assert; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.ImageDSProcessor; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadata; +import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader; +import org.sleuthkit.autopsy.commonfilesearch.FileInstanceMetadata; +import org.sleuthkit.autopsy.commonfilesearch.Md5Metadata; +import org.sleuthkit.autopsy.testutils.CaseUtils; +import org.sleuthkit.autopsy.testutils.IngestUtils; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * + * Provides setup and utility for testing presence of files in different data + * sets discoverable by Common Files Features. + * + * Data set definitions: + * + * set 1 + * + file1 + * - IMG_6175.jpg + * + file2 + * - IMG_6175.jpg + * + file3 + * - BasicStyleGuide.doc + * + * set 2 + * - adsf.pdf + * - IMG_6175.jpg + * + * set 3 + * - BasicStyleGuide.doc + * - IMG_6175.jpg + * + * set 4 + * - file.dat (empty file) + */ +class IntraCaseUtils { + + private static final String CASE_NAME = "IntraCaseCommonFilesSearchTest"; + static final Path CASE_DIRECTORY_PATH = Paths.get(System.getProperty("java.io.tmpdir"), CASE_NAME); + + private final Path imagePath1; + private final Path imagePath2; + private final Path imagePath3; + private final Path imagePath4; + + static final String IMG = "IMG_6175.jpg"; + static final String DOC = "BasicStyleGuide.doc"; + static final String PDF = "adsf.pdf"; //not a typo - it appears this way in the test image + static final String EMPTY = "file.dat"; + + static final String SET1 = "commonfiles_image1_v1.vhd"; + static final String SET2 = "commonfiles_image2_v1.vhd"; + static final String SET3 = "commonfiles_image3_v1.vhd"; + static final String SET4 = "commonfiles_image4_v1.vhd"; + + private final DataSourceLoader dataSourceLoader; + + private final String caseName; + + IntraCaseUtils(NbTestCase nbTestCase, String caseName){ + imagePath1 = Paths.get(nbTestCase.getDataDir().toString(), "commonfiles_image1_v1.vhd"); + imagePath2 = Paths.get(nbTestCase.getDataDir().toString(), "commonfiles_image2_v1.vhd"); + imagePath3 = Paths.get(nbTestCase.getDataDir().toString(), "commonfiles_image3_v1.vhd"); + imagePath4 = Paths.get(nbTestCase.getDataDir().toString(), "commonfiles_image4_v1.vhd"); + + this.dataSourceLoader = new DataSourceLoader(); + + this.caseName = caseName; + } + + void setUp(){ + CaseUtils.createAsCurrentCase(this.caseName); + + final ImageDSProcessor imageDSProcessor = new ImageDSProcessor(); + + IngestUtils.addDataSource(imageDSProcessor, imagePath1); + IngestUtils.addDataSource(imageDSProcessor, imagePath2); + IngestUtils.addDataSource(imageDSProcessor, imagePath3); + IngestUtils.addDataSource(imageDSProcessor, imagePath4); + } + + Map getDataSourceMap() throws NoCurrentCaseException, TskCoreException, SQLException{ + return this.dataSourceLoader.getDataSourceMap(); + } + + void tearDown(){ + CaseUtils.closeCurrentCase(false); + try { + CaseUtils.deleteCaseDir(CASE_DIRECTORY_PATH.toFile()); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + //does not represent a failure in the common files search feature + } + } + + /** + * Verify that the given file appears a precise number times in the given + * data source. + * + * @param files search domain + * @param objectIdToDataSource mapping of file ids to data source names + * @param name name of file to search for + * @param dataSource name of data source where file should appear + * @param count number of appearances of the given file + * @return true if a file with the given name exists the specified number + * of times in the given data source + */ + static boolean verifyFileExistanceAndCount(List files, Map objectIdToDataSource, String name, String dataSource, int count) { + + int tally = 0; + + for (AbstractFile file : files) { + + Long objectId = file.getId(); + + String fileName = file.getName(); + + String dataSourceName = objectIdToDataSource.get(objectId); + + if (fileName.equals(name) && dataSourceName.equals(dataSource)) { + tally++; + } + } + + return tally == count; + } + + /** + * Convenience method which verifies that a file exists within a given data + * source exactly once. + * + * @param files search domain + * @param objectIdToDataSource mapping of file ids to data source names + * @param name name of file to search for + * @param dataSource name of data source where file should appear + * @return true if a file with the given name exists once in the given data + * source + */ + static boolean verifySingularFileExistance(List files, Map objectIdToDataSource, String name, String dataSource) { + return verifyFileExistanceAndCount(files, objectIdToDataSource, name, dataSource, 1); + } + + static Map mapFileInstancesToDataSources(CommonFilesMetadata metadata) { + Map instanceIdToDataSource = new HashMap<>(); + + for (Map.Entry entry : metadata.getMetadata().entrySet()) { + for (FileInstanceMetadata md : entry.getValue().getMetadata()) { + instanceIdToDataSource.put(md.getObjectId(), md.getDataSourceName()); + } + } + + return instanceIdToDataSource; + } + + static List getFiles(Set objectIds) { + List files = new ArrayList<>(objectIds.size()); + + for (Long id : objectIds) { + try { + AbstractFile file = Case.getCurrentCaseThrows().getSleuthkitCase().getAbstractFileById(id); + files.add(file); + } catch (NoCurrentCaseException | TskCoreException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } + + return files; + } + + static Long getDataSourceIdByName(String name, Map dataSources){ + + if(dataSources.containsValue(name)){ + for(Map.Entry dataSource : dataSources.entrySet()){ + if(dataSource.getValue().equals(name)){ + return dataSource.getKey(); + } + } + } else { + throw new IndexOutOfBoundsException(String.format("Name should be one of: {0}", String.join(",", dataSources.values()))); + } + return null; + } +} diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/UningestedCases.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/UningestedCases.java new file mode 100644 index 0000000000..9bd7a02bae --- /dev/null +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonfilessearch/UningestedCases.java @@ -0,0 +1,114 @@ +/* + * + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.commonfilessearch; + +import java.sql.SQLException; +import java.util.Map; +import static junit.framework.Assert.assertEquals; +import junit.framework.Test; +import org.netbeans.junit.NbModuleSuite; +import org.netbeans.junit.NbTestCase; +import org.openide.util.Exceptions; +import org.python.icu.impl.Assert; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.commonfilesearch.AllDataSourcesCommonFilesAlgorithm; +import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadata; +import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadataBuilder; +import org.sleuthkit.autopsy.commonfilesearch.SingleDataSource; +import static org.sleuthkit.autopsy.commonfilessearch.IntraCaseUtils.SET1; +import static org.sleuthkit.autopsy.commonfilessearch.IntraCaseUtils.getDataSourceIdByName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Test that cases which are created but have not run any ingest modules turn up + * no results. + * + * Setup: + * + * Add images set 1, set 2, set 3, and set 4 to case. Do not ingest. + * + */ +public class UningestedCases extends NbTestCase { + + public static Test suite() { + NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(UningestedCases.class). + clusters(".*"). + enableModules(".*"); + return conf.suite(); + } + + private final IntraCaseUtils utils; + + public UningestedCases(String name) { + super(name); + + this.utils = new IntraCaseUtils(this, "UningestedCasesTests"); + } + + @Override + public void setUp(){ + this.utils.setUp(); + } + + @Override + public void tearDown(){ + this.utils.tearDown(); + } + + /** + * Find all matches & all file types. Confirm no matches are found (since + * there are no hashes to match). + */ + public void testOne() { + try { + Map dataSources = this.utils.getDataSourceMap(); + + CommonFilesMetadataBuilder allSourcesBuilder = new AllDataSourcesCommonFilesAlgorithm(dataSources, false, false); + CommonFilesMetadata metadata = allSourcesBuilder.findCommonFiles(); + + int resultCount = metadata.size(); + assertEquals(resultCount, 0); + + } catch (NoCurrentCaseException | TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } + + /** + * Find all matches on image #1 & all file types. Confirm no matches. + */ + public void testTwo() { + try { + Map dataSources = this.utils.getDataSourceMap(); + Long first = getDataSourceIdByName(SET1, dataSources); + + CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(first, dataSources, false, false); + CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles(); + + int resultCount = metadata.size(); + assertEquals(resultCount, 0); + + } catch (NoCurrentCaseException | TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } +} diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/CaseUtils.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/CaseUtils.java index a1bbd0ae24..224f2c9dd6 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/CaseUtils.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/CaseUtils.java @@ -125,5 +125,4 @@ public final class CaseUtils { */ private CaseUtils() { } - } diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index b1adb5d40b..9a9a904cc5 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Mon, 19 Mar 2018 11:17:11 -0700 +#Tue, 08 May 2018 10:29:55 -0600 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 @@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18 SplashRunningTextColor=0x0 SplashRunningTextFontSize=19 -currentVersion=Autopsy 4.6.0 +currentVersion=Autopsy 4.7.0 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 6cb9d4bdea..db3cd01af5 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Fri, 09 Mar 2018 13:03:41 -0700 -CTL_MainWindow_Title=Autopsy 4.6.0 -CTL_MainWindow_Title_No_Project=Autopsy 4.6.0 +#Tue, 08 May 2018 10:29:55 -0600 +CTL_MainWindow_Title=Autopsy 4.7.0 +CTL_MainWindow_Title_No_Project=Autopsy 4.7.0