From 4f8266805c1491952f26cc27665a5ff6e26e80d6 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 29 Apr 2020 09:00:35 -0400 Subject: [PATCH 01/81] purely gui changes without event listeners --- .../modules/hashdatabase/Bundle.properties | 4 + .../modules/hashdatabase/Bundle_ja.properties | 3 + .../HashDbCreateDatabaseDialog.form | 28 +++- .../HashDbCreateDatabaseDialog.java | 31 ++++- .../HashDbImportDatabaseDialog.form | 105 ++++++++------ .../HashDbImportDatabaseDialog.java | 90 +++++++----- .../HashLookupModuleSettingsPanel.form | 131 +++++++++++++----- .../HashLookupModuleSettingsPanel.java | 92 ++++++++---- 8 files changed, 333 insertions(+), 151 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index d9fb142cf4..69a349aeb7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -241,3 +241,7 @@ AddHashValuesToDatabaseDialog.okButton.text_2=OK HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.text=Copy hash set into user configuration folder HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.toolTipText=In Live Triage situations, this option ensures that path to the hash set will be valid HashLookupSettingsPanel.indexPathLabel.text= +HashDbImportDatabaseDialog.unspecifiedRadioButton.text=Unspecified +HashDbImportDatabaseDialog.unspecifiedRadioButton.toolTipText= +HashLookupModuleSettingsPanel.unspecifiedHashDbsLabel.text=Select unspecified hash sets to use: +HashDbCreateDatabaseDialog.unspecifiedRadioButton.text=Unspecified diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties index 3f5ea43a61..6f361b96ba 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties @@ -295,3 +295,6 @@ AddHashValuesToDatabaseDialog.okButton.text_2=OK HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.text=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u3092\u30e6\u30fc\u30b6\u30fc\u69cb\u6210\u30d5\u30a1\u30a4\u30eb\u306b\u30b3\u30d4\u30fc HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.toolTipText=\u30e9\u30a4\u30d6\u30c8\u30ea\u30a2\u30fc\u30b8\u306e\u72b6\u6cc1\u3067\u306f\u3001\u3053\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u306b\u3088\u3063\u3066\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u3078\u306e\u30d1\u30b9\u304c\u6709\u52b9\u3067\u3042\u308b\u3053\u3068\u304c\u4fdd\u8a3c\u3055\u308c\u307e\u3059\u3002 HashLookupSettingsPanel.indexPathLabel.text= +HashDbImportDatabaseDialog.unspecifiedRadioButton.text=\u9855\u8457 +HashLookupModuleSettingsPanel.unspecifiedHashDbsLabel.text=\u4f7f\u7528\u3059\u308b\u9855\u8457\u306a\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u3092\u9078\u629e: +HashDbCreateDatabaseDialog.unspecifiedRadioButton.text=\u9855\u8457 diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form index 7c74b4b583..142b2ed500 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form @@ -78,6 +78,7 @@ + @@ -125,19 +126,21 @@ - + - - - - + + + + + + @@ -183,7 +186,6 @@ - @@ -313,5 +315,19 @@ + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java index 5470b385fb..95b4596348 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java @@ -198,6 +198,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { lbOrg = new javax.swing.JLabel(); orgComboBox = new javax.swing.JComboBox<>(); orgButton = new javax.swing.JButton(); + unspecifiedRadioButton = new javax.swing.JRadioButton(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); @@ -224,7 +225,6 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { }); buttonGroup1.add(knownBadRadioButton); - knownBadRadioButton.setSelected(true); org.openide.awt.Mnemonics.setLocalizedText(knownBadRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.knownBadRadioButton.text")); // NOI18N knownBadRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -292,6 +292,15 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } }); + buttonGroup1.add(unspecifiedRadioButton); + unspecifiedRadioButton.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(unspecifiedRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.unspecifiedRadioButton.text")); // NOI18N + unspecifiedRadioButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + unspecifiedRadioButtonActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( @@ -334,7 +343,8 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { .addGap(32, 32, 32) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(knownRadioButton) - .addComponent(knownBadRadioButton))) + .addComponent(knownBadRadioButton) + .addComponent(unspecifiedRadioButton))) .addGroup(layout.createSequentialGroup() .addGap(12, 12, 12) .addComponent(jLabel2)) @@ -374,16 +384,18 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { .addComponent(knownRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(knownBadRadioButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(sendIngestMessagesCheckbox) - .addGap(0, 0, Short.MAX_VALUE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cancelButton) - .addComponent(okButton)))) + .addComponent(okButton))) + .addGroup(layout.createSequentialGroup() + .addComponent(unspecifiedRadioButton) + .addGap(24, 24, 24) + .addComponent(sendIngestMessagesCheckbox) + .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()) ); @@ -586,6 +598,10 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { enableComponents(); }//GEN-LAST:event_centralRepoRadioButtonActionPerformed + private void unspecifiedRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_unspecifiedRadioButtonActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_unspecifiedRadioButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; private javax.swing.JButton cancelButton; @@ -606,5 +622,6 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { private javax.swing.JButton saveAsButton; private javax.swing.JCheckBox sendIngestMessagesCheckbox; private javax.swing.ButtonGroup storageTypeButtonGroup; + private javax.swing.JRadioButton unspecifiedRadioButton; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form index e285e99a12..d192e1713d 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form @@ -29,7 +29,7 @@ - + @@ -54,10 +54,6 @@ - - - - @@ -76,7 +72,16 @@ - + + + + + + + + + + @@ -86,16 +91,17 @@ - - + + + @@ -113,52 +119,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - + @@ -220,7 +228,6 @@ - @@ -367,5 +374,21 @@ + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index a08f324a44..72e90fad30 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -182,6 +182,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { centralRepoRadioButton = new javax.swing.JRadioButton(); jLabel4 = new javax.swing.JLabel(); saveInUserConfigFolderCheckbox = new javax.swing.JCheckBox(); + unspecifiedRadioButton = new javax.swing.JRadioButton(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); @@ -218,7 +219,6 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { }); buttonGroup1.add(knownBadRadioButton); - knownBadRadioButton.setSelected(true); org.openide.awt.Mnemonics.setLocalizedText(knownBadRadioButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.knownBadRadioButton.text")); // NOI18N knownBadRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -291,6 +291,15 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { org.openide.awt.Mnemonics.setLocalizedText(saveInUserConfigFolderCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.text")); // NOI18N saveInUserConfigFolderCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.toolTipText")); // NOI18N + buttonGroup1.add(unspecifiedRadioButton); + org.openide.awt.Mnemonics.setLocalizedText(unspecifiedRadioButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.unspecifiedRadioButton.text")); // NOI18N + unspecifiedRadioButton.setToolTipText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.unspecifiedRadioButton.toolTipText")); // NOI18N + unspecifiedRadioButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + unspecifiedRadioButtonActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( @@ -315,9 +324,6 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addComponent(openButton)))) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(sendIngestMessagesCheckbox) - .addGap(0, 0, Short.MAX_VALUE)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addComponent(lbOrg) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -331,7 +337,13 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addGap(40, 40, 40) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(versionTextField) - .addComponent(hashSetNameTextField))) + .addComponent(hashSetNameTextField)))) + .addGap(81, 81, 81)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(sendIngestMessagesCheckbox) + .addGap(0, 0, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) .addComponent(okButton))) @@ -339,14 +351,15 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addComponent(cancelButton)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(saveInUserConfigFolderCheckbox) .addComponent(jLabel2) - .addComponent(readOnlyCheckbox) .addGroup(layout.createSequentialGroup() .addGap(19, 19, 19) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(knownRadioButton) - .addComponent(knownBadRadioButton)))) + .addComponent(knownBadRadioButton) + .addComponent(unspecifiedRadioButton))) + .addComponent(saveInUserConfigFolderCheckbox) + .addComponent(readOnlyCheckbox)) .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()) ); @@ -361,44 +374,46 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addComponent(databasePathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel3) .addComponent(openButton)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(fileTypeRadioButton) + .addComponent(centralRepoRadioButton) + .addComponent(jLabel4)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel1) + .addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lbVersion) + .addComponent(versionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(5, 5, 5) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(orgButton) + .addComponent(orgComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbOrg)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(knownRadioButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(knownBadRadioButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(unspecifiedRadioButton) + .addGap(5, 5, 5) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(fileTypeRadioButton) - .addComponent(centralRepoRadioButton) - .addComponent(jLabel4)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel1) - .addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lbVersion) - .addComponent(versionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(5, 5, 5) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(orgButton) - .addComponent(orgComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbOrg)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabel2) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(knownRadioButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(knownBadRadioButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(readOnlyCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(sendIngestMessagesCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(saveInUserConfigFolderCheckbox) - .addGap(0, 29, Short.MAX_VALUE)) + .addGap(0, 0, Short.MAX_VALUE)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) + .addGap(81, 81, 81) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cancelButton) .addComponent(okButton)))) - .addContainerGap()) + .addGap(18, 18, 18)) ); pack(); @@ -629,6 +644,10 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { enableComponents(); }//GEN-LAST:event_readOnlyCheckboxActionPerformed + private void unspecifiedRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_unspecifiedRadioButtonActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_unspecifiedRadioButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; private javax.swing.JButton cancelButton; @@ -652,6 +671,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private javax.swing.JCheckBox saveInUserConfigFolderCheckbox; private javax.swing.JCheckBox sendIngestMessagesCheckbox; private javax.swing.ButtonGroup storageTypeButtonGroup; + private javax.swing.JRadioButton unspecifiedRadioButton; private javax.swing.JTextField versionTextField; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form index c0a486fce9..f369da6e78 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form @@ -28,18 +28,31 @@ - + - - + + + + + + + + + + + + + + + @@ -48,20 +61,34 @@ - + - + + + + + + + + - + + + + + + + + @@ -93,35 +120,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -155,5 +154,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java index 6dcd567226..f27e895781 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java @@ -66,8 +66,8 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } private void customizeComponents(HashLookupModuleSettings settings) { - customizeHashSetsTable(jScrollPane1, knownHashTable, knownHashSetsTableModel); - customizeHashSetsTable(jScrollPane2, knownBadHashTable, knownBadHashSetsTableModel); + customizeHashSetsTable(knownHashDbsScrollPane, knownHashTable, knownHashSetsTableModel); + customizeHashSetsTable(knownBadHashDbsScrollPane, knownBadHashTable, knownBadHashSetsTableModel); alwaysCalcHashesCheckbox.setSelected(settings.shouldCalculateHashes()); hashDbManager.addPropertyChangeListener(this); alwaysCalcHashesCheckbox.setText("" + org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text") + ""); // NOI18N NON-NLS @@ -285,36 +285,31 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe // //GEN-BEGIN:initComponents private void initComponents() { - jScrollPane1 = new javax.swing.JScrollPane(); + knownHashDbsLabel = new javax.swing.JLabel(); + knownHashDbsScrollPane = new javax.swing.JScrollPane(); knownHashTable = new javax.swing.JTable(); knownBadHashDbsLabel = new javax.swing.JLabel(); - knownHashDbsLabel = new javax.swing.JLabel(); - alwaysCalcHashesCheckbox = new javax.swing.JCheckBox(); - jScrollPane2 = new javax.swing.JScrollPane(); + knownBadHashDbsScrollPane = new javax.swing.JScrollPane(); knownBadHashTable = new javax.swing.JTable(); + unspecifiedHashDbsLabel = new javax.swing.JLabel(); + unspecifiedHashDbsScrollPane = new javax.swing.JScrollPane(); + unspecifiedHashTable = new javax.swing.JTable(); + alwaysCalcHashesCheckbox = new javax.swing.JCheckBox(); setPreferredSize(new java.awt.Dimension(292, 150)); - jScrollPane1.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + knownHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.knownHashDbsLabel.text")); // NOI18N + + knownHashDbsScrollPane.setBorder(javax.swing.BorderFactory.createEtchedBorder()); knownHashTable.setBackground(new java.awt.Color(240, 240, 240)); knownHashTable.setShowHorizontalLines(false); knownHashTable.setShowVerticalLines(false); - jScrollPane1.setViewportView(knownHashTable); + knownHashDbsScrollPane.setViewportView(knownHashTable); knownBadHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.knownBadHashDbsLabel.text")); // NOI18N - knownHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.knownHashDbsLabel.text")); // NOI18N - - alwaysCalcHashesCheckbox.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text")); // NOI18N - alwaysCalcHashesCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.toolTipText")); // NOI18N - alwaysCalcHashesCheckbox.setMaximumSize(new java.awt.Dimension(290, 35)); - alwaysCalcHashesCheckbox.setMinimumSize(new java.awt.Dimension(290, 35)); - alwaysCalcHashesCheckbox.setPreferredSize(new java.awt.Dimension(271, 35)); - alwaysCalcHashesCheckbox.setVerticalAlignment(javax.swing.SwingConstants.TOP); - alwaysCalcHashesCheckbox.setVerticalTextPosition(javax.swing.SwingConstants.TOP); - - jScrollPane2.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + knownBadHashDbsScrollPane.setBorder(javax.swing.BorderFactory.createEtchedBorder()); knownBadHashTable.setBackground(new java.awt.Color(240, 240, 240)); knownBadHashTable.setModel(new javax.swing.table.DefaultTableModel( @@ -327,7 +322,32 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe )); knownBadHashTable.setShowHorizontalLines(false); knownBadHashTable.setShowVerticalLines(false); - jScrollPane2.setViewportView(knownBadHashTable); + knownBadHashDbsScrollPane.setViewportView(knownBadHashTable); + + unspecifiedHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.unspecifiedHashDbsLabel.text")); // NOI18N + + unspecifiedHashDbsScrollPane.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + unspecifiedHashTable.setBackground(new java.awt.Color(240, 240, 240)); + unspecifiedHashTable.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + + }, + new String [] { + + } + )); + unspecifiedHashTable.setShowHorizontalLines(false); + unspecifiedHashTable.setShowVerticalLines(false); + unspecifiedHashDbsScrollPane.setViewportView(unspecifiedHashTable); + + alwaysCalcHashesCheckbox.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text")); // NOI18N + alwaysCalcHashesCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.toolTipText")); // NOI18N + alwaysCalcHashesCheckbox.setMaximumSize(new java.awt.Dimension(290, 35)); + alwaysCalcHashesCheckbox.setMinimumSize(new java.awt.Dimension(290, 35)); + alwaysCalcHashesCheckbox.setPreferredSize(new java.awt.Dimension(271, 35)); + alwaysCalcHashesCheckbox.setVerticalAlignment(javax.swing.SwingConstants.TOP); + alwaysCalcHashesCheckbox.setVerticalTextPosition(javax.swing.SwingConstants.TOP); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -339,14 +359,23 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe .addGroup(layout.createSequentialGroup() .addComponent(knownHashDbsLabel) .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(knownBadHashDbsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 290, Short.MAX_VALUE) + .addComponent(knownBadHashDbsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 347, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addGap(10, 10, 10) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))) + .addComponent(knownHashDbsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addComponent(knownBadHashDbsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))) .addComponent(alwaysCalcHashesCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap()) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(unspecifiedHashDbsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 347, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(unspecifiedHashDbsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))) + .addContainerGap())) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -354,24 +383,33 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe .addGap(2, 2, 2) .addComponent(knownHashDbsLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 29, Short.MAX_VALUE) + .addComponent(knownHashDbsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 68, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(knownBadHashDbsLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 29, Short.MAX_VALUE) + .addComponent(knownBadHashDbsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 67, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(unspecifiedHashDbsLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(unspecifiedHashDbsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 68, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(alwaysCalcHashesCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 330, Short.MAX_VALUE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JCheckBox alwaysCalcHashesCheckbox; - private javax.swing.JScrollPane jScrollPane1; - private javax.swing.JScrollPane jScrollPane2; private javax.swing.JLabel knownBadHashDbsLabel; + private javax.swing.JScrollPane knownBadHashDbsScrollPane; private javax.swing.JTable knownBadHashTable; private javax.swing.JLabel knownHashDbsLabel; + private javax.swing.JScrollPane knownHashDbsScrollPane; private javax.swing.JTable knownHashTable; + private javax.swing.JLabel unspecifiedHashDbsLabel; + private javax.swing.JScrollPane unspecifiedHashDbsScrollPane; + private javax.swing.JTable unspecifiedHashTable; // End of variables declaration//GEN-END:variables } From a0824372d393812712681588059e8f143abc084c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 29 Apr 2020 11:12:04 -0400 Subject: [PATCH 02/81] updated settings panel gui --- .../AnnotationsContentViewer.form | 4 +- .../AnnotationsContentViewer.java | 4 +- .../modules/hashdatabase/Bundle.properties | 4 +- .../modules/hashdatabase/Bundle_ja.properties | 4 +- .../HashLookupModuleSettingsPanel.form | 128 ++--------------- .../HashLookupModuleSettingsPanel.java | 131 ++++-------------- 6 files changed, 43 insertions(+), 232 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.form index 4fe61b2fb5..986492a810 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.form @@ -21,12 +21,12 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index c5c92b11c0..84b68b02df 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -399,11 +399,11 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane5, javax.swing.GroupLayout.DEFAULT_SIZE, 907, Short.MAX_VALUE) + .addComponent(jScrollPane5, javax.swing.GroupLayout.DEFAULT_SIZE, 696, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane5, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 435, Short.MAX_VALUE) + .addComponent(jScrollPane5, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 494, Short.MAX_VALUE) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index 69a349aeb7..58e1214518 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -162,8 +162,6 @@ AddContentToHashDbAction.multipleSelectionNameEmpty=Add Files to Hash Set (Empty HashDbManager.ingestRunningExceptionMsg=Ingest is ongoing; this service will be unavailable until it finishes. HashDbManager.saveErrorExceptionMsg=Error saving hash configuration HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text=Calculate MD5 even if no hash set is selected -HashLookupModuleSettingsPanel.knownHashDbsLabel.text=Select known hash sets to use: -HashLookupModuleSettingsPanel.knownBadHashDbsLabel.text=Select notable hash sets to use: AddContentToHashDbAction.addFilesToHashSet.files=files AddContentToHashDbAction.addFilesToHashSet.file=file HashDbManager.errCreatingIndex.title=Error creating index @@ -243,5 +241,5 @@ HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.toolTipText=In Live Tr HashLookupSettingsPanel.indexPathLabel.text= HashDbImportDatabaseDialog.unspecifiedRadioButton.text=Unspecified HashDbImportDatabaseDialog.unspecifiedRadioButton.toolTipText= -HashLookupModuleSettingsPanel.unspecifiedHashDbsLabel.text=Select unspecified hash sets to use: HashDbCreateDatabaseDialog.unspecifiedRadioButton.text=Unspecified +HashLookupModuleSettingsPanel.hashDbsLabel.text=Select hash sets to use: diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties index 6f361b96ba..3cd52c36ae 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties @@ -216,8 +216,6 @@ HashLookupSettingsPanel.jLabel6.text=\u30bf\u30a4\u30d7: HashLookupSettingsPanel.jLabel4.text=\u5834\u6240: HashLookupSettingsPanel.jLabel2.text=\u540d\u524d: HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u306a\u3044\u5834\u5408\u3067\u3082MD5\u3092\u8a08\u7b97 -HashLookupModuleSettingsPanel.knownHashDbsLabel.text=\u4f7f\u7528\u3059\u308b\u65e2\u77e5\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u3092\u9078\u629e: -HashLookupModuleSettingsPanel.knownBadHashDbsLabel.text=\u4f7f\u7528\u3059\u308b\u9855\u8457\u306a\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u3092\u9078\u629e: AddContentToHashDbAction.addFilesToHashSet.files=\u30d5\u30a1\u30a4\u30eb AddContentToHashDbAction.addFilesToHashSet.file=\u30d5\u30a1\u30a4\u30eb HashDbManager.errCreatingIndex.title=\u7d22\u5f15\u306e\u4f5c\u6210\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f @@ -296,5 +294,5 @@ HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.text=\u30cf\u30c3\u30b HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.toolTipText=\u30e9\u30a4\u30d6\u30c8\u30ea\u30a2\u30fc\u30b8\u306e\u72b6\u6cc1\u3067\u306f\u3001\u3053\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u306b\u3088\u3063\u3066\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u3078\u306e\u30d1\u30b9\u304c\u6709\u52b9\u3067\u3042\u308b\u3053\u3068\u304c\u4fdd\u8a3c\u3055\u308c\u307e\u3059\u3002 HashLookupSettingsPanel.indexPathLabel.text= HashDbImportDatabaseDialog.unspecifiedRadioButton.text=\u9855\u8457 -HashLookupModuleSettingsPanel.unspecifiedHashDbsLabel.text=\u4f7f\u7528\u3059\u308b\u9855\u8457\u306a\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u3092\u9078\u629e: HashDbCreateDatabaseDialog.unspecifiedRadioButton.text=\u9855\u8457 +HashLookupModuleSettingsPanel.hashDbsLabel.text=\u4f7f\u7528\u3059\u308b\u65e2\u77e5\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u3092\u9078\u629e: diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form index f369da6e78..3e2e525560 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form @@ -25,70 +25,42 @@ - + - - - - - + - - - - - - - - - - - - - - + - + - - - - - - - - - - - - + - + - + - + @@ -102,7 +74,7 @@ - + @@ -113,88 +85,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java index f27e895781..be13e5e2af 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java @@ -44,8 +44,6 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe private final HashDbManager hashDbManager = HashDbManager.getInstance(); private final List knownHashSetModels = new ArrayList<>(); private final HashSetsTableModel knownHashSetsTableModel = new HashSetsTableModel(knownHashSetModels); - private final List knownBadHashSetModels = new ArrayList<>(); - private final HashSetsTableModel knownBadHashSetsTableModel = new HashSetsTableModel(knownBadHashSetModels); HashLookupModuleSettingsPanel(HashLookupModuleSettings settings) { initializeHashSetModels(settings); @@ -54,20 +52,15 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } private void initializeHashSetModels(HashLookupModuleSettings settings) { - initializeHashSetModels(settings, validSetsOnly(hashDbManager.getKnownFileHashSets()), knownHashSetModels); - initializeHashSetModels(settings, validSetsOnly(hashDbManager.getKnownBadFileHashSets()), knownBadHashSetModels); - } - - private void initializeHashSetModels(HashLookupModuleSettings settings, List hashDbs, List hashSetModels) { - hashSetModels.clear(); + List hashDbs = validSetsOnly(hashDbManager.getAllHashSets()); + knownHashSetModels.clear(); for (HashDb db : hashDbs) { - hashSetModels.add(new HashSetModel(db, settings.isHashSetEnabled(db), isHashDbValid(db))); + knownHashSetModels.add(new HashSetModel(db, settings.isHashSetEnabled(db), isHashDbValid(db))); } } private void customizeComponents(HashLookupModuleSettings settings) { - customizeHashSetsTable(knownHashDbsScrollPane, knownHashTable, knownHashSetsTableModel); - customizeHashSetsTable(knownBadHashDbsScrollPane, knownBadHashTable, knownBadHashSetsTableModel); + customizeHashSetsTable(hashDbsScrollPane, hashTable, knownHashSetsTableModel); alwaysCalcHashesCheckbox.setSelected(settings.shouldCalculateHashes()); hashDbManager.addPropertyChangeListener(this); alwaysCalcHashesCheckbox.setText("" + org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text") + ""); // NOI18N NON-NLS @@ -78,7 +71,7 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe table.setTableHeader(null); table.setRowSelectionAllowed(false); final int width1 = scrollPane.getPreferredSize().width; - knownHashTable.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); + hashTable.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); TableColumn column; for (int i = 0; i < table.getColumnCount(); i++) { column = table.getColumnModel().getColumn(i); @@ -104,7 +97,6 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe List enabledHashSets = new ArrayList<>(); List disabledHashSets = new ArrayList<>(); addHashSets(knownHashSetModels, enabledHashSets, disabledHashSets); - addHashSets(knownBadHashSetModels, enabledHashSets, disabledHashSets); return new HashLookupModuleSettings(alwaysCalcHashesCheckbox.isSelected(), enabledHashSets, disabledHashSets); } @@ -122,12 +114,10 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe void update() { updateHashSetModels(); knownHashSetsTableModel.fireTableDataChanged(); - knownBadHashSetsTableModel.fireTableDataChanged(); } private void updateHashSetModels() { - updateHashSetModels(validSetsOnly(hashDbManager.getKnownFileHashSets()), knownHashSetModels); - updateHashSetModels(validSetsOnly(hashDbManager.getKnownBadFileHashSets()), knownBadHashSetModels); + updateHashSetModels(validSetsOnly(hashDbManager.getAllHashSets()), knownHashSetModels); } private List validSetsOnly(List hashDbs){ @@ -180,7 +170,6 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe initializeHashSetModels(newSettings); alwaysCalcHashesCheckbox.setSelected(newSettings.shouldCalculateHashes()); knownHashSetsTableModel.fireTableDataChanged(); - knownBadHashSetsTableModel.fireTableDataChanged(); } private boolean isHashDbValid(HashDb hashDb) { @@ -213,6 +202,10 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe return db.getDisplayName(); } + String getFormattedName() { + return String.format("%s (%s)", db.getDisplayName(), db.getKnownFilesType()); + } + void setEnabled(boolean enabled) { this.enabled = enabled; } @@ -254,7 +247,7 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe if (columnIndex == 0) { return hashSets.get(rowIndex).isEnabled(); } else { - return hashSets.get(rowIndex).getName(); + return hashSets.get(rowIndex).getFormattedName(); } } @@ -285,61 +278,21 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe // //GEN-BEGIN:initComponents private void initComponents() { - knownHashDbsLabel = new javax.swing.JLabel(); - knownHashDbsScrollPane = new javax.swing.JScrollPane(); - knownHashTable = new javax.swing.JTable(); - knownBadHashDbsLabel = new javax.swing.JLabel(); - knownBadHashDbsScrollPane = new javax.swing.JScrollPane(); - knownBadHashTable = new javax.swing.JTable(); - unspecifiedHashDbsLabel = new javax.swing.JLabel(); - unspecifiedHashDbsScrollPane = new javax.swing.JScrollPane(); - unspecifiedHashTable = new javax.swing.JTable(); + hashDbsLabel = new javax.swing.JLabel(); + hashDbsScrollPane = new javax.swing.JScrollPane(); + hashTable = new javax.swing.JTable(); alwaysCalcHashesCheckbox = new javax.swing.JCheckBox(); setPreferredSize(new java.awt.Dimension(292, 150)); - knownHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.knownHashDbsLabel.text")); // NOI18N + hashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.hashDbsLabel.text")); // NOI18N - knownHashDbsScrollPane.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + hashDbsScrollPane.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - knownHashTable.setBackground(new java.awt.Color(240, 240, 240)); - knownHashTable.setShowHorizontalLines(false); - knownHashTable.setShowVerticalLines(false); - knownHashDbsScrollPane.setViewportView(knownHashTable); - - knownBadHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.knownBadHashDbsLabel.text")); // NOI18N - - knownBadHashDbsScrollPane.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - - knownBadHashTable.setBackground(new java.awt.Color(240, 240, 240)); - knownBadHashTable.setModel(new javax.swing.table.DefaultTableModel( - new Object [][] { - - }, - new String [] { - - } - )); - knownBadHashTable.setShowHorizontalLines(false); - knownBadHashTable.setShowVerticalLines(false); - knownBadHashDbsScrollPane.setViewportView(knownBadHashTable); - - unspecifiedHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.unspecifiedHashDbsLabel.text")); // NOI18N - - unspecifiedHashDbsScrollPane.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - - unspecifiedHashTable.setBackground(new java.awt.Color(240, 240, 240)); - unspecifiedHashTable.setModel(new javax.swing.table.DefaultTableModel( - new Object [][] { - - }, - new String [] { - - } - )); - unspecifiedHashTable.setShowHorizontalLines(false); - unspecifiedHashTable.setShowVerticalLines(false); - unspecifiedHashDbsScrollPane.setViewportView(unspecifiedHashTable); + hashTable.setBackground(new java.awt.Color(240, 240, 240)); + hashTable.setShowHorizontalLines(false); + hashTable.setShowVerticalLines(false); + hashDbsScrollPane.setViewportView(hashTable); alwaysCalcHashesCheckbox.setText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text")); // NOI18N alwaysCalcHashesCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.toolTipText")); // NOI18N @@ -357,59 +310,31 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(knownHashDbsLabel) + .addComponent(hashDbsLabel) .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(knownBadHashDbsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 347, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addGap(10, 10, 10) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(knownHashDbsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addComponent(knownBadHashDbsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))) + .addComponent(hashDbsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 494, Short.MAX_VALUE)) .addComponent(alwaysCalcHashesCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap()) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(unspecifiedHashDbsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 347, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addGap(10, 10, 10) - .addComponent(unspecifiedHashDbsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))) - .addContainerGap())) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(2, 2, 2) - .addComponent(knownHashDbsLabel) + .addComponent(hashDbsLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(knownHashDbsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 68, Short.MAX_VALUE) + .addComponent(hashDbsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 207, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(knownBadHashDbsLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(knownBadHashDbsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 67, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(unspecifiedHashDbsLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(unspecifiedHashDbsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 68, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(alwaysCalcHashesCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 330, Short.MAX_VALUE)) + .addContainerGap()) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JCheckBox alwaysCalcHashesCheckbox; - private javax.swing.JLabel knownBadHashDbsLabel; - private javax.swing.JScrollPane knownBadHashDbsScrollPane; - private javax.swing.JTable knownBadHashTable; - private javax.swing.JLabel knownHashDbsLabel; - private javax.swing.JScrollPane knownHashDbsScrollPane; - private javax.swing.JTable knownHashTable; - private javax.swing.JLabel unspecifiedHashDbsLabel; - private javax.swing.JScrollPane unspecifiedHashDbsScrollPane; - private javax.swing.JTable unspecifiedHashTable; + private javax.swing.JLabel hashDbsLabel; + private javax.swing.JScrollPane hashDbsScrollPane; + private javax.swing.JTable hashTable; // End of variables declaration//GEN-END:variables } From 60068ec93a876966b80a28db1d7c4e7525134443 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 29 Apr 2020 12:26:00 -0400 Subject: [PATCH 03/81] updates for naming --- .../HashLookupModuleSettingsPanel.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java index be13e5e2af..55959db35c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java @@ -27,6 +27,7 @@ import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableColumn; +import org.apache.commons.lang.StringUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; @@ -42,8 +43,8 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe private static final long serialVersionUID = 1L; private final HashDbManager hashDbManager = HashDbManager.getInstance(); - private final List knownHashSetModels = new ArrayList<>(); - private final HashSetsTableModel knownHashSetsTableModel = new HashSetsTableModel(knownHashSetModels); + private final List hashSetModels = new ArrayList<>(); + private final HashSetsTableModel hashSetsTableModel = new HashSetsTableModel(hashSetModels); HashLookupModuleSettingsPanel(HashLookupModuleSettings settings) { initializeHashSetModels(settings); @@ -53,14 +54,14 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe private void initializeHashSetModels(HashLookupModuleSettings settings) { List hashDbs = validSetsOnly(hashDbManager.getAllHashSets()); - knownHashSetModels.clear(); + hashSetModels.clear(); for (HashDb db : hashDbs) { - knownHashSetModels.add(new HashSetModel(db, settings.isHashSetEnabled(db), isHashDbValid(db))); + hashSetModels.add(new HashSetModel(db, settings.isHashSetEnabled(db), isHashDbValid(db))); } } private void customizeComponents(HashLookupModuleSettings settings) { - customizeHashSetsTable(hashDbsScrollPane, hashTable, knownHashSetsTableModel); + customizeHashSetsTable(hashDbsScrollPane, hashTable, hashSetsTableModel); alwaysCalcHashesCheckbox.setSelected(settings.shouldCalculateHashes()); hashDbManager.addPropertyChangeListener(this); alwaysCalcHashesCheckbox.setText("" + org.openide.util.NbBundle.getMessage(HashLookupModuleSettingsPanel.class, "HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text") + ""); // NOI18N NON-NLS @@ -96,7 +97,7 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe public IngestModuleIngestJobSettings getSettings() { List enabledHashSets = new ArrayList<>(); List disabledHashSets = new ArrayList<>(); - addHashSets(knownHashSetModels, enabledHashSets, disabledHashSets); + addHashSets(hashSetModels, enabledHashSets, disabledHashSets); return new HashLookupModuleSettings(alwaysCalcHashesCheckbox.isSelected(), enabledHashSets, disabledHashSets); } @@ -113,13 +114,9 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe void update() { updateHashSetModels(); - knownHashSetsTableModel.fireTableDataChanged(); + hashSetsTableModel.fireTableDataChanged(); } - private void updateHashSetModels() { - updateHashSetModels(validSetsOnly(hashDbManager.getAllHashSets()), knownHashSetModels); - } - private List validSetsOnly(List hashDbs){ List validDbs = new ArrayList<>(); for(HashDb db:hashDbs){ @@ -134,8 +131,9 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe return validDbs; } - void updateHashSetModels(List hashDbs, List hashSetModels) { - + void updateHashSetModels() { + List hashDbs = validSetsOnly(hashDbManager.getAllHashSets()); + List hashDatabases = new ArrayList<>(hashDbs); // Update the hash sets and detect deletions. @@ -169,7 +167,7 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe void reset(HashLookupModuleSettings newSettings) { initializeHashSetModels(newSettings); alwaysCalcHashesCheckbox.setSelected(newSettings.shouldCalculateHashes()); - knownHashSetsTableModel.fireTableDataChanged(); + hashSetsTableModel.fireTableDataChanged(); } private boolean isHashDbValid(HashDb hashDb) { @@ -203,7 +201,12 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } String getFormattedName() { - return String.format("%s (%s)", db.getDisplayName(), db.getKnownFilesType()); + String knownTypeName = (db != null && db.getKnownFilesType() != null) ? db.getKnownFilesType().getDisplayName() : ""; + if (!StringUtils.isBlank(knownTypeName)) + knownTypeName = String.format(" (%s)", knownTypeName); + + String displayName = db != null ? db.getDisplayName() : ""; + return displayName + knownTypeName; } void setEnabled(boolean enabled) { From 72ef5267e18d9bd5b9543fcd44135b7d322d3324 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 29 Apr 2020 16:22:33 -0400 Subject: [PATCH 04/81] added NO_CHANGE KnownFileType --- .../modules/hashdatabase/Bundle.properties | 6 +- .../hashdatabase/Bundle.properties-MERGED | 1 + .../modules/hashdatabase/Bundle_ja.properties | 4 +- .../HashDbCreateDatabaseDialog.form | 10 +-- .../HashDbCreateDatabaseDialog.java | 49 ++++++----- .../HashDbImportDatabaseDialog.form | 12 +-- .../HashDbImportDatabaseDialog.java | 39 +++++---- .../modules/hashdatabase/HashDbManager.java | 83 +++++++++++++------ .../hashdatabase/HashLookupSettingsPanel.java | 2 +- .../ImportCentralRepoDbProgressDialog.java | 7 +- 10 files changed, 127 insertions(+), 86 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index 58e1214518..ffd0a535ac 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -239,7 +239,7 @@ AddHashValuesToDatabaseDialog.okButton.text_2=OK HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.text=Copy hash set into user configuration folder HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.toolTipText=In Live Triage situations, this option ensures that path to the hash set will be valid HashLookupSettingsPanel.indexPathLabel.text= -HashDbImportDatabaseDialog.unspecifiedRadioButton.text=Unspecified -HashDbImportDatabaseDialog.unspecifiedRadioButton.toolTipText= -HashDbCreateDatabaseDialog.unspecifiedRadioButton.text=Unspecified HashLookupModuleSettingsPanel.hashDbsLabel.text=Select hash sets to use: +HashDbCreateDatabaseDialog.noChangeRadioButton.text=No Change +HashDbImportDatabaseDialog.noChangeRadioButton.toolTipText= +HashDbImportDatabaseDialog.noChangeRadioButton.text=No Change diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED index 44057d0016..44e551c028 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED @@ -190,6 +190,7 @@ HashDbManager.hashDbAlreadyAddedExceptionMsg=The hash set at\n{0}\nhas already b HashDbManager.illegalHashDbFileNameExtensionMsg=The hash set file name must have a .{0} extension. HashDbManager.moduleErr=Module Error HashDbManager.knownBad.text=Notable +HashDbManager.noChange.text=No Change HashDbManager.known.text=Known HashDbManager.fileNameExtensionFilter.title=Hash Set File HashDbSearchAction.dlgMsg.title=File Search by MD5 Hash diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties index 3cd52c36ae..c800aca094 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties @@ -293,6 +293,6 @@ AddHashValuesToDatabaseDialog.okButton.text_2=OK HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.text=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u3092\u30e6\u30fc\u30b6\u30fc\u69cb\u6210\u30d5\u30a1\u30a4\u30eb\u306b\u30b3\u30d4\u30fc HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.toolTipText=\u30e9\u30a4\u30d6\u30c8\u30ea\u30a2\u30fc\u30b8\u306e\u72b6\u6cc1\u3067\u306f\u3001\u3053\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u306b\u3088\u3063\u3066\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u3078\u306e\u30d1\u30b9\u304c\u6709\u52b9\u3067\u3042\u308b\u3053\u3068\u304c\u4fdd\u8a3c\u3055\u308c\u307e\u3059\u3002 HashLookupSettingsPanel.indexPathLabel.text= -HashDbImportDatabaseDialog.unspecifiedRadioButton.text=\u9855\u8457 -HashDbCreateDatabaseDialog.unspecifiedRadioButton.text=\u9855\u8457 HashLookupModuleSettingsPanel.hashDbsLabel.text=\u4f7f\u7528\u3059\u308b\u65e2\u77e5\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u3092\u9078\u629e: +HashDbCreateDatabaseDialog.noChangeRadioButton.text=\u9855\u8457 +HashDbImportDatabaseDialog.noChangeRadioButton.text=\u9855\u8457 diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form index 142b2ed500..8eae9f15c4 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form @@ -78,7 +78,7 @@ - + @@ -136,7 +136,7 @@ - + @@ -315,18 +315,18 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java index 95b4596348..5b7c0f1944 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java @@ -198,7 +198,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { lbOrg = new javax.swing.JLabel(); orgComboBox = new javax.swing.JComboBox<>(); orgButton = new javax.swing.JButton(); - unspecifiedRadioButton = new javax.swing.JRadioButton(); + noChangeRadioButton = new javax.swing.JRadioButton(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); @@ -292,12 +292,12 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } }); - buttonGroup1.add(unspecifiedRadioButton); - unspecifiedRadioButton.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(unspecifiedRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.unspecifiedRadioButton.text")); // NOI18N - unspecifiedRadioButton.addActionListener(new java.awt.event.ActionListener() { + buttonGroup1.add(noChangeRadioButton); + noChangeRadioButton.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(noChangeRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.noChangeRadioButton.text")); // NOI18N + noChangeRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - unspecifiedRadioButtonActionPerformed(evt); + noChangeRadioButtonActionPerformed(evt); } }); @@ -344,7 +344,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(knownRadioButton) .addComponent(knownBadRadioButton) - .addComponent(unspecifiedRadioButton))) + .addComponent(noChangeRadioButton))) .addGroup(layout.createSequentialGroup() .addGap(12, 12, 12) .addComponent(jLabel2)) @@ -392,7 +392,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { .addComponent(cancelButton) .addComponent(okButton))) .addGroup(layout.createSequentialGroup() - .addComponent(unspecifiedRadioButton) + .addComponent(noChangeRadioButton) .addGap(24, 24, 24) .addComponent(sendIngestMessagesCheckbox) .addGap(0, 0, Short.MAX_VALUE))) @@ -403,13 +403,13 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { }// //GEN-END:initComponents private void knownRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownRadioButtonActionPerformed - sendIngestMessagesCheckbox.setSelected(false); - sendIngestMessagesCheckbox.setEnabled(false); + sendIngestMessagesCheckbox.setSelected(KnownFilesType.KNOWN.isDefaultInboxMessages()); + sendIngestMessagesCheckbox.setEnabled(KnownFilesType.KNOWN.isInboxMessagesAllowed()); }//GEN-LAST:event_knownRadioButtonActionPerformed private void knownBadRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownBadRadioButtonActionPerformed - sendIngestMessagesCheckbox.setSelected(true); - sendIngestMessagesCheckbox.setEnabled(true); + sendIngestMessagesCheckbox.setSelected(KnownFilesType.KNOWN_BAD.isDefaultInboxMessages()); + sendIngestMessagesCheckbox.setEnabled(KnownFilesType.KNOWN_BAD.isInboxMessagesAllowed()); }//GEN-LAST:event_knownBadRadioButtonActionPerformed private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed @@ -488,14 +488,18 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } KnownFilesType type; - TskData.FileKnown fileKnown; + if (knownRadioButton.isSelected()) { - type = KnownFilesType.KNOWN; - fileKnown = TskData.FileKnown.KNOWN; - } else { - type = KnownFilesType.KNOWN_BAD; - fileKnown = TskData.FileKnown.BAD; + type = KnownFilesType.KNOWN; + } + else if (noChangeRadioButton.isSelected()) { + type = KnownFilesType.NO_CHANGE; } + else { + type = KnownFilesType.KNOWN_BAD; + } + + TskData.FileKnown fileKnown = type.getFileKnown(); String errorMessage = NbBundle .getMessage(this.getClass(), "HashDbCreateDatabaseDialog.errMsg.hashDbCreationErr"); @@ -598,9 +602,10 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { enableComponents(); }//GEN-LAST:event_centralRepoRadioButtonActionPerformed - private void unspecifiedRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_unspecifiedRadioButtonActionPerformed - // TODO add your handling code here: - }//GEN-LAST:event_unspecifiedRadioButtonActionPerformed + private void noChangeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_noChangeRadioButtonActionPerformed + sendIngestMessagesCheckbox.setSelected(KnownFilesType.NO_CHANGE.isDefaultInboxMessages()); + sendIngestMessagesCheckbox.setEnabled(KnownFilesType.NO_CHANGE.isInboxMessagesAllowed()); + }//GEN-LAST:event_noChangeRadioButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; @@ -616,12 +621,12 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { private javax.swing.JRadioButton knownBadRadioButton; private javax.swing.JRadioButton knownRadioButton; private javax.swing.JLabel lbOrg; + private javax.swing.JRadioButton noChangeRadioButton; private javax.swing.JButton okButton; private javax.swing.JButton orgButton; private javax.swing.JComboBox orgComboBox; private javax.swing.JButton saveAsButton; private javax.swing.JCheckBox sendIngestMessagesCheckbox; private javax.swing.ButtonGroup storageTypeButtonGroup; - private javax.swing.JRadioButton unspecifiedRadioButton; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form index d192e1713d..720d3763a2 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form @@ -97,7 +97,7 @@ - + @@ -147,7 +147,7 @@ - + @@ -374,20 +374,20 @@ - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index 72e90fad30..10b9827404 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -182,7 +182,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { centralRepoRadioButton = new javax.swing.JRadioButton(); jLabel4 = new javax.swing.JLabel(); saveInUserConfigFolderCheckbox = new javax.swing.JCheckBox(); - unspecifiedRadioButton = new javax.swing.JRadioButton(); + noChangeRadioButton = new javax.swing.JRadioButton(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); @@ -291,12 +291,12 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { org.openide.awt.Mnemonics.setLocalizedText(saveInUserConfigFolderCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.text")); // NOI18N saveInUserConfigFolderCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.toolTipText")); // NOI18N - buttonGroup1.add(unspecifiedRadioButton); - org.openide.awt.Mnemonics.setLocalizedText(unspecifiedRadioButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.unspecifiedRadioButton.text")); // NOI18N - unspecifiedRadioButton.setToolTipText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.unspecifiedRadioButton.toolTipText")); // NOI18N - unspecifiedRadioButton.addActionListener(new java.awt.event.ActionListener() { + buttonGroup1.add(noChangeRadioButton); + org.openide.awt.Mnemonics.setLocalizedText(noChangeRadioButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.noChangeRadioButton.text")); // NOI18N + noChangeRadioButton.setToolTipText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.noChangeRadioButton.toolTipText")); // NOI18N + noChangeRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - unspecifiedRadioButtonActionPerformed(evt); + noChangeRadioButtonActionPerformed(evt); } }); @@ -357,7 +357,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(knownRadioButton) .addComponent(knownBadRadioButton) - .addComponent(unspecifiedRadioButton))) + .addComponent(noChangeRadioButton))) .addComponent(saveInUserConfigFolderCheckbox) .addComponent(readOnlyCheckbox)) .addGap(0, 0, Short.MAX_VALUE))) @@ -398,7 +398,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(knownBadRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(unspecifiedRadioButton) + .addComponent(noChangeRadioButton) .addGap(5, 5, 5) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() @@ -451,13 +451,13 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { }//GEN-LAST:event_openButtonActionPerformed private void knownRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownRadioButtonActionPerformed - sendIngestMessagesCheckbox.setSelected(false); - sendIngestMessagesCheckbox.setEnabled(false); + sendIngestMessagesCheckbox.setSelected(KnownFilesType.KNOWN.isDefaultInboxMessages()); + sendIngestMessagesCheckbox.setEnabled(KnownFilesType.KNOWN.isInboxMessagesAllowed()); }//GEN-LAST:event_knownRadioButtonActionPerformed private void knownBadRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownBadRadioButtonActionPerformed - sendIngestMessagesCheckbox.setSelected(true); - sendIngestMessagesCheckbox.setEnabled(true); + sendIngestMessagesCheckbox.setSelected(KnownFilesType.KNOWN_BAD.isDefaultInboxMessages()); + sendIngestMessagesCheckbox.setEnabled(KnownFilesType.KNOWN_BAD.isInboxMessagesAllowed()); }//GEN-LAST:event_knownBadRadioButtonActionPerformed private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed @@ -546,7 +546,11 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { KnownFilesType type; if (knownRadioButton.isSelected()) { type = KnownFilesType.KNOWN; - } else { + } + else if (noChangeRadioButton.isSelected()) { + type = KnownFilesType.NO_CHANGE; + } + else { type = KnownFilesType.KNOWN_BAD; } @@ -644,9 +648,10 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { enableComponents(); }//GEN-LAST:event_readOnlyCheckboxActionPerformed - private void unspecifiedRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_unspecifiedRadioButtonActionPerformed - // TODO add your handling code here: - }//GEN-LAST:event_unspecifiedRadioButtonActionPerformed + private void noChangeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_noChangeRadioButtonActionPerformed + sendIngestMessagesCheckbox.setSelected(KnownFilesType.NO_CHANGE.isDefaultInboxMessages()); + sendIngestMessagesCheckbox.setEnabled(KnownFilesType.NO_CHANGE.isInboxMessagesAllowed()); + }//GEN-LAST:event_noChangeRadioButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; @@ -663,6 +668,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private javax.swing.JRadioButton knownRadioButton; private javax.swing.JLabel lbOrg; private javax.swing.JLabel lbVersion; + private javax.swing.JRadioButton noChangeRadioButton; private javax.swing.JButton okButton; private javax.swing.JButton openButton; private javax.swing.JButton orgButton; @@ -671,7 +677,6 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private javax.swing.JCheckBox saveInUserConfigFolderCheckbox; private javax.swing.JCheckBox sendIngestMessagesCheckbox; private javax.swing.ButtonGroup storageTypeButtonGroup; - private javax.swing.JRadioButton unspecifiedRadioButton; private javax.swing.JTextField versionTextField; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index c6ae0d5ef4..372538be64 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -28,9 +28,11 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.logging.Level; +import java.util.stream.Stream; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.SwingWorker; @@ -58,6 +60,7 @@ import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; /** * This class implements a singleton that manages the set of hash databases used @@ -499,9 +502,9 @@ public class HashDbManager implements PropertyChangeListener { // Defaults for fields not stored in the central repository: // searchDuringIngest: false // sendIngestMessages: true if the hash set is notable - boolean sendIngestMessages = convertFileKnown(globalSet.getFileKnownStatus()).equals(HashDb.KnownFilesType.KNOWN_BAD); + boolean sendIngestMessages = KnownFilesType.fromFileKnown(globalSet.getFileKnownStatus()).equals(HashDb.KnownFilesType.KNOWN_BAD); crHashSets.add(new HashDbInfo(globalSet.getSetName(), globalSet.getVersion(), - globalSet.getGlobalSetID(), convertFileKnown(globalSet.getFileKnownStatus()), globalSet.isReadOnly(), false, sendIngestMessages)); + globalSet.getGlobalSetID(), KnownFilesType.fromFileKnown(globalSet.getFileKnownStatus()), globalSet.isReadOnly(), false, sendIngestMessages)); } } catch (CentralRepoException ex){ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS @@ -509,13 +512,6 @@ public class HashDbManager implements PropertyChangeListener { } return crHashSets; } - - private static HashDb.KnownFilesType convertFileKnown(TskData.FileKnown fileKnown){ - if(fileKnown.equals(TskData.FileKnown.BAD)){ - return HashDb.KnownFilesType.KNOWN_BAD; - } - return HashDb.KnownFilesType.KNOWN; - } /** * Restores the last saved hash sets configuration. This supports @@ -701,17 +697,65 @@ public class HashDbManager implements PropertyChangeListener { */ public enum KnownFilesType { - KNOWN(NbBundle.getMessage(HashDbManager.class, "HashDbManager.known.text")), - KNOWN_BAD(NbBundle.getMessage(HashDbManager.class, "HashDbManager.knownBad.text")); + KNOWN(NbBundle.getMessage(HashDbManager.class, "HashDbManager.known.text"), TskData.FileKnown.KNOWN, false, false), + KNOWN_BAD(NbBundle.getMessage(HashDbManager.class, "HashDbManager.knownBad.text"), TskData.FileKnown.BAD, true, true), + NO_CHANGE(NbBundle.getMessage(HashDbManager.class, "HashDbManager.noChange.text"), TskData.FileKnown.UNKNOWN, true , false); + private final String displayName; + private final TskData.FileKnown fileKnown; + private final boolean allowSendInboxMessages; + private final boolean defaultSendInboxMessages; - private KnownFilesType(String displayName) { + private KnownFilesType(String displayName, TskData.FileKnown fileKnown, boolean allowSendInboxMessages, boolean defaultSendInboxMessages) { this.displayName = displayName; + this.fileKnown = fileKnown; + this.allowSendInboxMessages = allowSendInboxMessages; + this.defaultSendInboxMessages = defaultSendInboxMessages; } + /** + * Returns whether or not it is allowable to send inbox messages with this known files type. + * @return Whether or not it is allowable to send inbox messages with this known files type. + */ + boolean isInboxMessagesAllowed() { + return allowSendInboxMessages; + } + + /** + * Returns whether or not by default for this type is to send inbox messages. + * @return Whether or not by default for this type is to send inbox messages. + */ + boolean isDefaultInboxMessages() { + return defaultSendInboxMessages; + } + + public String getDisplayName() { return this.displayName; } + + /** + * Retrieves the corresponding TskData.FileKnown enum type that relates to this. + * @return The corresponding TskData.FileKnown. + */ + TskData.FileKnown getFileKnown() { + return this.fileKnown; + } + + /** + * Converts a TskData.FileKnown to the corresponding KnownFilesType. + * @param fileKnown The TskData.FileKnown type. + * @return The corresponding KnownFilesType. + */ + static KnownFilesType fromFileKnown(TskData.FileKnown fileKnown) { + if (fileKnown == null) + return null; + + return Stream.of(KnownFilesType.values()) + .filter((type) -> type.getFileKnown() == fileKnown) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unknown TskData.FileKnown type: " + fileKnown)); + } } /** @@ -1229,12 +1273,7 @@ public class HashDbManager implements PropertyChangeListener { if (content instanceof AbstractFile) { AbstractFile file = (AbstractFile) content; if (null != file.getMd5Hash()) { - TskData.FileKnown type; - if(knownFilesType.equals(HashDb.KnownFilesType.KNOWN_BAD)){ - type = TskData.FileKnown.BAD; - } else { - type = TskData.FileKnown.KNOWN; - } + TskData.FileKnown type = knownFilesType.getFileKnown(); try{ CentralRepoFileInstance fileInstance = new CentralRepoFileInstance(referenceSetID, file.getMd5Hash(), @@ -1258,12 +1297,8 @@ public class HashDbManager implements PropertyChangeListener { public void addHashes(List hashes) throws TskCoreException { Set globalFileInstances = new HashSet<>(); for(HashEntry hashEntry:hashes){ - TskData.FileKnown type; - if(knownFilesType.equals(HashDb.KnownFilesType.KNOWN_BAD)){ - type = TskData.FileKnown.BAD; - } else { - type = TskData.FileKnown.KNOWN; - } + TskData.FileKnown type = knownFilesType.getFileKnown(); + try { globalFileInstances.add(new CentralRepoFileInstance(referenceSetID, hashEntry.getMd5Hash(), type, hashEntry.getComment())); } catch (CentralRepoException | CorrelationAttributeNormalizationException ex){ diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java index 0f1f97ba97..0f9f99d79b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -282,7 +282,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan // Update ingest option components. sendIngestMessagesCheckBox.setSelected(db.getSendIngestMessages()); - sendIngestMessagesCheckBox.setEnabled(!ingestIsRunning && db.getKnownFilesType().equals(KnownFilesType.KNOWN_BAD)); + sendIngestMessagesCheckBox.setEnabled(!ingestIsRunning && db.getKnownFilesType().isInboxMessagesAllowed()); // Update database action buttons. createDatabaseButton.setEnabled(true); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java index f25471b0e0..355f509a37 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java @@ -231,12 +231,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P try { // Conver to the FileKnown enum used by EamGlobalSet - TskData.FileKnown knownStatus; - if (knownFilesType.equals(HashDbManager.HashDb.KnownFilesType.KNOWN)) { - knownStatus = TskData.FileKnown.KNOWN; - } else { - knownStatus = TskData.FileKnown.BAD; - } + TskData.FileKnown knownStatus = knownFilesType.getFileKnown(); // Create an empty hashset in the central repository CentralRepository dbManager = CentralRepository.getInstance(); From 842ccc52f3a155afa1a0444a4dae3f63c9931ed0 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 30 Apr 2020 11:17:49 -0400 Subject: [PATCH 05/81] working through kdb hashsetparser --- .../modules/hashdatabase/HashSetParser.java | 15 +++++ .../hashdatabase/KdbHashSetParser.java | 61 +++++++++++++------ 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java index 8a7a3ae034..9bd77717ce 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.modules.hashdatabase; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.HashEntry; interface HashSetParser { @@ -50,4 +51,18 @@ interface HashSetParser { * Closes the import file */ void close(); + + /** + * Get the next hash to import as a HashEntry object. + * + * @return A new hash entry for the next item parsed or null if no more items. + * @throws TskCoreException + */ + default HashEntry getNextHashEntry() throws TskCoreException { + String next = getNextHash(); + if (next == null) + return null; + + return new HashEntry(null, next, null, null, null); + } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java index 94d2724995..46eee12b6e 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java @@ -25,6 +25,7 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.HashEntry; import org.sleuthkit.datamodel.TskCoreException; /** @@ -68,7 +69,7 @@ public class KdbHashSetParser implements HashSetParser { } // Get the hashes - resultSet = statement.executeQuery("SELECT md5 FROM hashes"); + resultSet = statement.executeQuery("SELECT id, md5 FROM hashes"); // At this point, getNextHash can read each hash from the result set } catch (ClassNotFoundException | SQLException ex) { @@ -76,6 +77,38 @@ public class KdbHashSetParser implements HashSetParser { } } + + private static class HashRow { + private final String md5Hash; + private + } + + private Stuff getNextHashEntry() throws TskCoreException { + try { + if (resultSet.next()) { + long hashId = resultSet.getLong("id"); + byte[] hashBytes = resultSet.getBytes("md5"); + StringBuilder sb = new StringBuilder(); + for (byte b : hashBytes) { + sb.append(String.format("%02x", b)); + } + + if (sb.toString().length() != 32) { + throw new TskCoreException("Hash has incorrect length: " + sb.toString()); + } + + String md5Hash = sb.toString(); + return new + + totalHashesRead++; + + } else { + throw new TskCoreException("Could not read expected number of hashes from hash set " + filename); + } + } catch (SQLException ex) { + throw new TskCoreException("Error reading hash from result set for hash set " + filename, ex); + } + } /** * Get the next hash to import @@ -86,28 +119,16 @@ public class KdbHashSetParser implements HashSetParser { @Override public String getNextHash() throws TskCoreException { - try { - if (resultSet.next()) { - byte[] hashBytes = resultSet.getBytes("md5"); - StringBuilder sb = new StringBuilder(); - for (byte b : hashBytes) { - sb.append(String.format("%02x", b)); - } - if (sb.toString().length() != 32) { - throw new TskCoreException("Hash has incorrect length: " + sb.toString()); - } - - totalHashesRead++; - return sb.toString(); - } else { - throw new TskCoreException("Could not read expected number of hashes from hash set " + filename); - } - } catch (SQLException ex) { - throw new TskCoreException("Error reading hash from result set for hash set " + filename, ex); - } } + @Override + public HashEntry getNextHashEntry() throws TskCoreException { + return HashSetParser.super.getNextHashEntry(); //To change body of generated methods, choose Tools | Templates. + } + + + /** * Check if there are more hashes to read * From e4b13b9df1b5468ea4574beeb3e374ea8326c65c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 30 Apr 2020 13:17:25 -0400 Subject: [PATCH 06/81] worked through kdb parser and integration --- .../modules/hashdatabase/HashSetParser.java | 2 +- .../ImportCentralRepoDbProgressDialog.java | 7 +-- .../hashdatabase/KdbHashSetParser.java | 48 +++++++++++++++---- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java index 9bd77717ce..e4b5d55632 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java @@ -55,7 +55,7 @@ interface HashSetParser { /** * Get the next hash to import as a HashEntry object. * - * @return A new hash entry for the next item parsed or null if no more items. + * @return A new hash entry for the next item parsed. * @throws TskCoreException */ default HashEntry getNextHashEntry() throws TskCoreException { diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java index 355f509a37..d626bd5c98 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java @@ -41,6 +41,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.datamodel.HashEntry; /** * Imports a hash set into the central repository and updates a progress dialog @@ -250,14 +251,14 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P return null; } - String newHash = hashSetParser.getNextHash(); + HashEntry newHash = hashSetParser.getNextHashEntry(); if (newHash != null) { CentralRepoFileInstance eamGlobalFileInstance = new CentralRepoFileInstance( referenceSetID.get(), - newHash, + newHash.getMd5Hash(), knownStatus, - ""); + newHash.getComment() != null ? newHash.getComment() : ""); globalInstances.add(eamGlobalFileInstance); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java index 46eee12b6e..d9b29b257c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java @@ -20,9 +20,12 @@ package org.sleuthkit.autopsy.modules.hashdatabase; import java.sql.Connection; import java.sql.DriverManager; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.HashEntry; @@ -80,10 +83,28 @@ public class KdbHashSetParser implements HashSetParser { private static class HashRow { private final String md5Hash; - private + private final long hashId; + + HashRow(String md5Hash, long hashId) { + this.md5Hash = md5Hash; + this.hashId = hashId; + } + + String getMd5Hash() { + return md5Hash; + } + + long getHashId() { + return hashId; + } } - private Stuff getNextHashEntry() throws TskCoreException { + /** + * Retrieves the row id and md5 hash for the next item in the hashes table. + * @return A hash row object containing the hash and id. + * @throws TskCoreException + */ + private HashRow getNextHashRow() throws TskCoreException { try { if (resultSet.next()) { long hashId = resultSet.getLong("id"); @@ -98,10 +119,8 @@ public class KdbHashSetParser implements HashSetParser { } String md5Hash = sb.toString(); - return new - totalHashesRead++; - + return new HashRow(md5Hash, hashId); } else { throw new TskCoreException("Could not read expected number of hashes from hash set " + filename); } @@ -118,13 +137,26 @@ public class KdbHashSetParser implements HashSetParser { */ @Override public String getNextHash() throws TskCoreException { - - + return getNextHashRow().getMd5Hash(); } @Override public HashEntry getNextHashEntry() throws TskCoreException { - return HashSetParser.super.getNextHashEntry(); //To change body of generated methods, choose Tools | Templates. + HashRow row = getNextHashRow(); + try { + PreparedStatement getComment = conn.prepareStatement("SELECT comment FROM comments WHERE hash_id = ?"); + getComment.setLong(0, row.getHashId()); + ResultSet commentResults = getComment.executeQuery(); + List comments = new ArrayList<>(); + while (commentResults.next()) + comments.add(commentResults.getString("comment")); + + String comment = comments.size() > 0 ? String.join(" ", comments) : null; + return new HashEntry(null, row.getMd5Hash(), null, null, comment); + } + catch (SQLException ex) { + throw new TskCoreException("Error opening/reading hash set " + filename, ex); + } } From 98ee56978e2bba6d209e388dd3cff81679420c41 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 30 Apr 2020 16:01:39 -0400 Subject: [PATCH 07/81] mostly worked through HashDbIngestModule --- .../modules/hashdatabase/Bundle.properties | 1 + .../hashdatabase/HashDbIngestModule.java | 407 ++++++++++++------ .../ImportCentralRepoDbProgressDialog.java | 2 +- 3 files changed, 274 insertions(+), 136 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index ffd0a535ac..2e32d65089 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -95,6 +95,7 @@ HashDbIngestModule.calcHashValueErr=Error encountered while calculating the hash HashDbIngestModule.hashLookupErrorMsg=Hash Lookup Error: {0} HashDbIngestModule.settingKnownBadStateErr=Error encountered while setting notable state for {0}. HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}. +HashDbIngestModule.lookingUpNoChangeHashValueErr=Error encountered while looking up no change hash value for {0}. HashDbIngestModule.lookingUpKnownHashValueErr=Error encountered while looking up known hash value for {0}. HashDbIngestModule.postToBB.fileName=File Name HashDbIngestModule.postToBB.md5Hash=MD5 Hash diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index a562ab2a22..32268ccf53 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -24,7 +24,9 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; import java.util.logging.Level; +import java.util.stream.Collectors; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; @@ -38,6 +40,7 @@ import org.sleuthkit.autopsy.ingest.IngestMessage; import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Blackboard; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -63,6 +66,16 @@ import org.sleuthkit.datamodel.TskException; public class HashDbIngestModule implements FileIngestModule { private static final Logger logger = Logger.getLogger(HashDbIngestModule.class.getName()); + + private final Function knownBadLookupError = + (file) -> NbBundle.getMessage(this.getClass(), "HashDbIngestModule.lookingUpKnownBadHashValueErr", file.getName()); + + private final Function noChangeLookupError = + (file) -> NbBundle.getMessage(this.getClass(), "HashDbIngestModule.lookingUpNoChangeHashValueErr", file.getName()); + + private final Function knownLookupError = + (file) -> NbBundle.getMessage(this.getClass(), "HashDbIngestModule.lookingUpKnownHashValueErr", file.getName()); + private static final int MAX_COMMENT_SIZE = 500; private final IngestServices services = IngestServices.getInstance(); private final SleuthkitCase skCase; @@ -70,6 +83,7 @@ public class HashDbIngestModule implements FileIngestModule { private final HashLookupModuleSettings settings; private final List knownBadHashSets = new ArrayList<>(); private final List knownHashSets = new ArrayList<>(); + private final List noChangeHashSets = new ArrayList<>(); private long jobId; private static final HashMap totalsForIngestJobs = new HashMap<>(); private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); @@ -81,6 +95,7 @@ public class HashDbIngestModule implements FileIngestModule { private static class IngestJobTotals { private final AtomicLong totalKnownBadCount = new AtomicLong(0); + private final AtomicLong totalNoChangeCount = new AtomicLong(0); private final AtomicLong totalCalctime = new AtomicLong(0); private final AtomicLong totalLookuptime = new AtomicLong(0); } @@ -111,12 +126,11 @@ public class HashDbIngestModule implements FileIngestModule { @Override public void startUp(org.sleuthkit.autopsy.ingest.IngestJobContext context) throws IngestModuleException { jobId = context.getJobId(); - if (!hashDbManager.verifyAllDatabasesLoadedCorrectly()) { + if (!hashDbManager.verifyAllDatabasesLoadedCorrectly()) throw new IngestModuleException("Could not load all hash sets"); - } - updateEnabledHashSets(hashDbManager.getKnownBadFileHashSets(), knownBadHashSets); - updateEnabledHashSets(hashDbManager.getKnownFileHashSets(), knownHashSets); + initializeHashsets(hashDbManager.getAllHashSets()); + if (refCounter.incrementAndGet(jobId) == 1) { // initialize job totals getTotalsForIngestJobs(jobId); @@ -139,18 +153,27 @@ public class HashDbIngestModule implements FileIngestModule { } /** - * Cycle through list of hashsets and return the subset that is enabled. + * Cycle through list of hashsets and place each HashDB in the appropriate list based on KnownFilesType. * * @param allHashSets List of all hashsets from DB manager - * @param enabledHashSets List of enabled ones to return. */ - private void updateEnabledHashSets(List allHashSets, List enabledHashSets) { - enabledHashSets.clear(); + private void initializeHashsets(List allHashSets) { for (HashDb db : allHashSets) { if (settings.isHashSetEnabled(db)) { try { if (db.isValid()) { - enabledHashSets.add(db); + switch (db.getKnownFilesType()) { + case KNOWN: + knownHashSets.add(db); + break; + case KNOWN_BAD: + knownBadHashSets.add(db); + break; + case NO_CHANGE: + noChangeHashSets.add(db); + break; + default: throw new TskCoreException("Unknown KnownFilesType: " + db.getKnownFilesType()); + } } } catch (TskCoreException ex) { logger.log(Level.WARNING, "Error getting index status for " + db.getDisplayName() + " hash set", ex); //NON-NLS @@ -173,135 +196,41 @@ public class HashDbIngestModule implements FileIngestModule { logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS return ProcessResult.ERROR; } - - // Skip unallocated space files. - if ((file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) - || file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) { + + if (shouldSkip(file)) return ProcessResult.OK; - } - - /* - * Skip directories. One reason for this is because we won't accurately - * calculate hashes of NTFS directories that have content that spans the - * IDX_ROOT and IDX_ALLOC artifacts. So we disable that until a solution - * for it is developed. - */ - if (file.isDir()) { - return ProcessResult.OK; - } - - // bail out if we have no hashes set - if ((knownHashSets.isEmpty()) && (knownBadHashSets.isEmpty()) && (!settings.shouldCalculateHashes())) { - return ProcessResult.OK; - } // Safely get a reference to the totalsForIngestJobs object IngestJobTotals totals = getTotalsForIngestJobs(jobId); - // calc hash value - String name = file.getName(); - long fileId = file.getId(); - String md5Hash = file.getMd5Hash(); - if (md5Hash == null || md5Hash.isEmpty()) { - try { - TimingMetric metric = HealthMonitor.getTimingMetric("Disk Reads: Hash calculation"); - long calcstart = System.currentTimeMillis(); - md5Hash = HashUtility.calculateMd5Hash(file); - if (file.getSize() > 0) { - // Surprisingly, the hash calculation does not seem to be correlated that - // strongly with file size until the files get large. - // Only normalize if the file size is greater than ~1MB. - if (file.getSize() < 1000000) { - HealthMonitor.submitTimingMetric(metric); - } else { - // In testing, this normalization gave reasonable resuls - HealthMonitor.submitNormalizedTimingMetric(metric, file.getSize() / 500000); - } - } - file.setMd5Hash(md5Hash); - long delta = (System.currentTimeMillis() - calcstart); - totals.totalCalctime.addAndGet(delta); + // calc hash value + String md5Hash = GetHash(file, totals); + if (md5Hash == null) + return ProcessResult.ERROR; - } catch (IOException ex) { - logger.log(Level.WARNING, String.format("Error calculating hash of file '%s' (id=%d).", name, fileId), ex); //NON-NLS - services.postMessage(IngestMessage.createErrorMessage( - HashLookupModuleFactory.getModuleName(), - NbBundle.getMessage(this.getClass(), "HashDbIngestModule.fileReadErrorMsg", name), - NbBundle.getMessage(this.getClass(), "HashDbIngestModule.calcHashValueErr", - file.getParentPath() + file.getName(), - file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)?"Allocated File" : "Deleted File"))); - return ProcessResult.ERROR; - } - } - - // look up in notable first - boolean foundBad = false; + // the processing result of handling this file ProcessResult ret = ProcessResult.OK; - for (HashDb db : knownBadHashSets) { - try { - long lookupstart = System.currentTimeMillis(); - HashHitInfo hashInfo = db.lookupMD5(file); - if (null != hashInfo) { - foundBad = true; - totals.totalKnownBadCount.incrementAndGet(); + + // look up in notable first + FindInHashsetsResult knownBadResult = findInHashsets(file, totals.totalKnownBadCount, + totals.totalLookuptime, knownBadHashSets, TskData.FileKnown.BAD, knownBadLookupError); + + boolean foundBad = knownBadResult.isFound(); + if (knownBadResult.isError()) + ret = ProcessResult.ERROR; - file.setKnown(TskData.FileKnown.BAD); - - String hashSetName = db.getDisplayName(); - - String comment = ""; - ArrayList comments = hashInfo.getComments(); - int i = 0; - for (String c : comments) { - if (++i > 1) { - comment += " "; - } - comment += c; - if (comment.length() > MAX_COMMENT_SIZE) { - comment = comment.substring(0, MAX_COMMENT_SIZE) + "..."; - break; - } - } - - /* - * We have a match. Now create an artifact if it is - * determined that one hasn't been created yet. - */ - List attributesList = new ArrayList<>(); - attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, HashLookupModuleFactory.getModuleName(), hashSetName)); - try { - org.sleuthkit.datamodel.Blackboard tskBlackboard = skCase.getBlackboard(); - if (tskBlackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, attributesList) == false) { - postHashSetHitToBlackboard(file, md5Hash, hashSetName, comment, db.getSendIngestMessages()); - } - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, String.format( - "A problem occurred while checking for existing artifacts for file '%s' (id=%d).", name, fileId), ex); //NON-NLS - services.postMessage(IngestMessage.createErrorMessage( - HashLookupModuleFactory.getModuleName(), - Bundle.HashDbIngestModule_dialogTitle_errorFindingArtifacts(name), - Bundle.HashDbIngestModule_errorMessage_lookingForFileArtifacts(name))); - ret = ProcessResult.ERROR; - } - } - long delta = (System.currentTimeMillis() - lookupstart); - totals.totalLookuptime.addAndGet(delta); - - } catch (TskException ex) { - logger.log(Level.WARNING, String.format( - "Couldn't lookup notable hash for file '%s' (id=%d) - see sleuthkit log for details", name, fileId), ex); //NON-NLS - services.postMessage(IngestMessage.createErrorMessage( - HashLookupModuleFactory.getModuleName(), - NbBundle.getMessage(this.getClass(), "HashDbIngestModule.hashLookupErrorMsg", name), - NbBundle.getMessage(this.getClass(), "HashDbIngestModule.lookingUpKnownBadHashValueErr", name))); - ret = ProcessResult.ERROR; - } - } + // look up no change items next + FindInHashsetsResult noChangeResult = findInHashsets(file, totals.totalNoChangeCount, + totals.totalLookuptime, noChangeHashSets, TskData.FileKnown.BAD, noChangeLookupError); + + boolean foundNoChange = noChangeResult.isFound(); + if (noChangeResult.isError()) + ret = ProcessResult.ERROR; // If the file is not in the notable sets, search for it in the known sets. // Any hit is sufficient to classify it as known, and there is no need to create // a hit artifact or send a message to the application inbox. - if (!foundBad) { + if (!foundBad && !foundNoChange) { for (HashDb db : knownHashSets) { try { long lookupstart = System.currentTimeMillis(); @@ -313,12 +242,7 @@ public class HashDbIngestModule implements FileIngestModule { totals.totalLookuptime.addAndGet(delta); } catch (TskException ex) { - logger.log(Level.WARNING, String.format( - "Couldn't lookup known hash for file '%s' (id=%d) - see sleuthkit log for details", name, fileId), ex); //NON-NLS - services.postMessage(IngestMessage.createErrorMessage( - HashLookupModuleFactory.getModuleName(), - NbBundle.getMessage(this.getClass(), "HashDbIngestModule.hashLookupErrorMsg", name), - NbBundle.getMessage(this.getClass(), "HashDbIngestModule.lookingUpKnownHashValueErr", name))); + reportLookupError(ex, file, knownLookupError); ret = ProcessResult.ERROR; } } @@ -326,6 +250,218 @@ public class HashDbIngestModule implements FileIngestModule { return ret; } + + /** + * Returns true if this file should be skipped for processing. + * @param file The file to potentially skip. + * @return True if this file should be skipped. + */ + private boolean shouldSkip(AbstractFile file) { + // Skip unallocated space files. + if ((file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) + || file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) { + return true; + } + + /* + * Skip directories. One reason for this is because we won't accurately + * calculate hashes of NTFS directories that have content that spans the + * IDX_ROOT and IDX_ALLOC artifacts. So we disable that until a solution + * for it is developed. + */ + if (file.isDir()) + return true; + + // bail out if we have no hashes set + if ((knownHashSets.isEmpty()) && (knownBadHashSets.isEmpty()) && (!settings.shouldCalculateHashes())) + return true; + + return false; + } + + + /** + * Reports an error when an issue is encountered looking up a file. + * @param ex The exception thrown in the error. + * @param file The file for which this error applies. + * @param lookupErrorMessage The function that generates an error message specific to which piece of the ingest processing failed. + */ + private void reportLookupError(TskException ex, AbstractFile file, Function lookupErrorMessage) { + logger.log(Level.WARNING, String.format( + "Couldn't lookup notable hash for file '%s' (id=%d) - see sleuthkit log for details", file.getName(), file.getId()), ex); //NON-NLS + services.postMessage(IngestMessage.createErrorMessage( + HashLookupModuleFactory.getModuleName(), + NbBundle.getMessage(this.getClass(), "HashDbIngestModule.hashLookupErrorMsg", file.getName()), + lookupErrorMessage.apply(file))); + } + + /** + * The result of attempting to find a file in a list of HashDB objects. + */ + private static class FindInHashsetsResult { + private final boolean found; + private final boolean error; + + FindInHashsetsResult(boolean found, boolean error) { + this.found = found; + this.error = error; + } + + /** + * Returns true if the file was found in the HashDB. + * @return True if the file was found in the HashDB. + */ + boolean isFound() { + return found; + } + + /** + * Returns true if there was an error in the process of finding a file in a HashDB. + * @return True if there was an error in the process of finding a file in a HashDB. + */ + boolean isError() { + return error; + } + } + + /** + * Attempts to find an abstract file in a list of HashDB objects. + * @param file The file to find. + * @param totalCount The total cound of files found in this type + * @param totalLookupTime The counter tracking the total amount of run time for this operation. + * @param hashSets The HashDB objects to cycle through looking for a hash hit. + * @param statusIfFound The FileKnown status to set on the file if the file is found in the hashSets. + * @param lookupErrorMessage The function that generates a message should there be an error in looking up the file in the hashSets. + * @return Whether or not the file was found and whether or not there was an error during the operation. + */ + private FindInHashsetsResult findInHashsets(AbstractFile file, AtomicLong totalCount, AtomicLong totalLookupTime, + List hashSets, TskData.FileKnown statusIfFound, Function lookupErrorMessage) { + + boolean found = false; + boolean wasError = false; + for (HashDb db : hashSets) { + try { + long lookupstart = System.currentTimeMillis(); + HashHitInfo hashInfo = db.lookupMD5(file); + if (null != hashInfo) { + found = true; + + totalCount.incrementAndGet(); + file.setKnown(statusIfFound); + String hashSetName = db.getDisplayName(); + String comment = generateComment(hashInfo); + if (!createArtifactIfNoneExists(hashSetName, file, comment, db)) + wasError = true; + } + long delta = (System.currentTimeMillis() - lookupstart); + totalLookupTime.addAndGet(delta); + + } catch (TskException ex) { + reportLookupError(ex, file, lookupErrorMessage); + wasError = true; + } + } + + return new FindInHashsetsResult(found, wasError); + } + + /** + * Generates a formatted comment. + * @param hashInfo The HashHitInfo. + * @return The formatted comment. + */ + private String generateComment(HashHitInfo hashInfo) { + String comment = ""; + ArrayList comments = hashInfo.getComments(); + int i = 0; + for (String c : comments) { + if (++i > 1) { + comment += " "; + } + comment += c; + if (comment.length() > MAX_COMMENT_SIZE) { + comment = comment.substring(0, MAX_COMMENT_SIZE) + "..."; + break; + } + } + return comment; + } + + /** + * Creates a BlackboardArtifact if no TSK_HASHSET_HIT artifact exists for this file. + * @param hashSetName The name of the hashset found. + * @param file The file that had a hash hit. + * @param comment The comment to associate with this artifact. + * @param db the database in which this file was found. + * @return True if the operation occurred successfully and without error. + */ + private boolean createArtifactIfNoneExists(String hashSetName, AbstractFile file, String comment, HashDb db) { + /* + * We have a match. Now create an artifact if it is + * determined that one hasn't been created yet. + */ + List attributesList = new ArrayList<>(); + attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, HashLookupModuleFactory.getModuleName(), hashSetName)); + try { + Blackboard tskBlackboard = skCase.getBlackboard(); + if (tskBlackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, attributesList) == false) { + postHashSetHitToBlackboard(file, file.getMd5Hash(), hashSetName, comment, db.getSendIngestMessages()); + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format( + "A problem occurred while checking for existing artifacts for file '%s' (id=%d).", file.getName(), file.getId()), ex); //NON-NLS + services.postMessage(IngestMessage.createErrorMessage( + HashLookupModuleFactory.getModuleName(), + Bundle.HashDbIngestModule_dialogTitle_errorFindingArtifacts(file.getName()), + Bundle.HashDbIngestModule_errorMessage_lookingForFileArtifacts(file.getName()))); + return false; + } + return true; + } + + /** + * Retrieves the md5 hash for a file or generates one if no one exists on the file. + * @param file The file in order to determine the hash. + * @param totals The timing metrics for this process. + * @return The found or determined md5 hash or null if none could be determined. + */ + private String GetHash(AbstractFile file, IngestJobTotals totals) { + String md5Hash = file.getMd5Hash(); + if (md5Hash != null && md5Hash.isEmpty()) + return md5Hash; + + try { + TimingMetric metric = HealthMonitor.getTimingMetric("Disk Reads: Hash calculation"); + long calcstart = System.currentTimeMillis(); + md5Hash = HashUtility.calculateMd5Hash(file); + if (file.getSize() > 0) { + // Surprisingly, the hash calculation does not seem to be correlated that + // strongly with file size until the files get large. + // Only normalize if the file size is greater than ~1MB. + if (file.getSize() < 1000000) { + HealthMonitor.submitTimingMetric(metric); + } + else { + // In testing, this normalization gave reasonable resuls + HealthMonitor.submitNormalizedTimingMetric(metric, file.getSize() / 500000); + } + } + file.setMd5Hash(md5Hash); + long delta = (System.currentTimeMillis() - calcstart); + totals.totalCalctime.addAndGet(delta); + return md5Hash; + } + catch (IOException ex) { + logger.log(Level.WARNING, String.format("Error calculating hash of file '%s' (id=%d).", file.getName(), file.getId()), ex); //NON-NLS + services.postMessage(IngestMessage.createErrorMessage( + HashLookupModuleFactory.getModuleName(), + NbBundle.getMessage(this.getClass(), "HashDbIngestModule.fileReadErrorMsg", file.getName()), + NbBundle.getMessage(this.getClass(), "HashDbIngestModule.calcHashValueErr", + file.getParentPath() + file.getName(), + file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)?"Allocated File" : "Deleted File"))); + return null; + } + } /** * Post a hash set hit to the blackboard. @@ -413,8 +549,9 @@ public class HashDbIngestModule implements FileIngestModule { * @param knownBadHashSets The list of hash sets for "known bad" files. * @param knownHashSets The list of hash sets for "known" files. */ - private static synchronized void postSummary(long jobId, - List knownBadHashSets, List knownHashSets) { + private static synchronized void postSummary(long jobId, List knownBadHashSets, + List noChangeHashSets, List knownHashSets) { + IngestJobTotals jobTotals = getTotalsForIngestJobs(jobId); totalsForIngestJobs.remove(jobId); @@ -456,7 +593,7 @@ public class HashDbIngestModule implements FileIngestModule { @Override public void shutDown() { if (refCounter.decrementAndGet(jobId) == 0) { - postSummary(jobId, knownBadHashSets, knownHashSets); + postSummary(jobId, knownBadHashSets, noChangeHashSets, knownHashSets); } } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java index d626bd5c98..030a38cb35 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java @@ -258,7 +258,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P referenceSetID.get(), newHash.getMd5Hash(), knownStatus, - newHash.getComment() != null ? newHash.getComment() : ""); + newHash.getComment()); globalInstances.add(eamGlobalFileInstance); From 928bbd40ed362743b32c8bc8e7e9e08ebdd5e113 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 1 May 2020 08:45:09 -0400 Subject: [PATCH 08/81] requires comma for comment --- ...AddHashValuesToDatabaseProgressDialog.java | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java index 99eecf50d2..73d1a02314 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java @@ -30,6 +30,7 @@ import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingWorker; +import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.datamodel.HashEntry; @@ -46,7 +47,14 @@ public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { private final HashDb hashDb; private final List hashes; private final List invalidHashes; - private final Pattern md5Pattern; + + // Matches hash with optional comma separated comment. + private static final Pattern HASH_LINE_PATTERN = Pattern.compile("^([a-fA-F0-9]{32})(,(.*))?$"); + // The regex group for the hash. + private static final int HASH_GROUP = 1; + // The regex group for the comment. + private static final int COMMENT_GROUP = 3; + private String errorTitle; private String errorMessage; private final String text; @@ -64,7 +72,6 @@ public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { display(parent); this.hashes = new ArrayList<>(); this.invalidHashes = new ArrayList<>(); - this.md5Pattern = Pattern.compile("^([a-fA-F0-9]{32})"); // NON-NLS this.parentRef = parent; this.hashDb = hashDb; this.text = text; @@ -161,17 +168,15 @@ public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { // These entries may be of or format for (String hashEntry : linesInTextArea) { hashEntry = hashEntry.trim(); - Matcher m = md5Pattern.matcher(hashEntry); + Matcher m = HASH_LINE_PATTERN.matcher(hashEntry); if (m.find()) { - // Is there any text left on this line? If so, treat it as a comment. - String comment = hashEntry.substring(m.end()).trim(); - if (comment.length() > 0) { - comment = (comment.charAt(0) == ',') ? comment.substring(1) : comment; - hashes.add(new HashEntry(null, m.group(0), null, null, comment)); - } else { - // more information can be added to the HashEntry - sha-1, sha-512, comment - hashes.add(new HashEntry(null, m.group(0), null, null, null)); - } + String hash = m.group(HASH_GROUP); + + // if there was a match and the match is not empty, assign to comment + String comment = StringUtils.isNotBlank(m.group(COMMENT_GROUP)) ? + m.group(COMMENT_GROUP).trim() : null; + + hashes.add(new HashEntry(null, hash, null, null, comment)); } else { if (!hashEntry.isEmpty()) { invalidHashes.add(hashEntry); From d542a29a27670b9f282db7ec183ab53ab21a6373 Mon Sep 17 00:00:00 2001 From: apriestman Date: Fri, 1 May 2020 11:34:56 -0400 Subject: [PATCH 09/81] AddImageTask no longer gets write lock --- Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index 17980cd0cd..2a26a714f9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -132,7 +132,7 @@ class AddImageTask implements Runnable { List errorMessages = new ArrayList<>(); List newDataSources = new ArrayList<>(); try { - currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock(); + //currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock(); synchronized (tskAddImageProcessLock) { if (!tskAddImageProcessStopped) { tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, true, ignoreFatOrphanFiles, imageWriterPath); @@ -147,7 +147,7 @@ class AddImageTask implements Runnable { commitOrRevertAddImageProcess(currentCase, errorMessages, newDataSources); progressMonitor.setProgress(100); } finally { - currentCase.getSleuthkitCase().releaseSingleUserCaseWriteLock(); + //currentCase.getSleuthkitCase().releaseSingleUserCaseWriteLock(); DataSourceProcessorCallback.DataSourceProcessorResult result; if (criticalErrorOccurred) { result = DataSourceProcessorResult.CRITICAL_ERRORS; From 9c86982ca2db3812e5ab85817c48cef6624b1fef Mon Sep 17 00:00:00 2001 From: apriestman Date: Mon, 4 May 2020 14:21:04 -0400 Subject: [PATCH 10/81] Cleanup --- Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index 2a26a714f9..a1443bde31 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -132,7 +132,6 @@ class AddImageTask implements Runnable { List errorMessages = new ArrayList<>(); List newDataSources = new ArrayList<>(); try { - //currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock(); synchronized (tskAddImageProcessLock) { if (!tskAddImageProcessStopped) { tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, true, ignoreFatOrphanFiles, imageWriterPath); @@ -147,7 +146,6 @@ class AddImageTask implements Runnable { commitOrRevertAddImageProcess(currentCase, errorMessages, newDataSources); progressMonitor.setProgress(100); } finally { - //currentCase.getSleuthkitCase().releaseSingleUserCaseWriteLock(); DataSourceProcessorCallback.DataSourceProcessorResult result; if (criticalErrorOccurred) { result = DataSourceProcessorResult.CRITICAL_ERRORS; From 781d6fd65516dd1b28a3558698e6596dc94df4d6 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 5 May 2020 10:03:41 -0400 Subject: [PATCH 11/81] fix for initial selected --- .../modules/hashdatabase/HashDbCreateDatabaseDialog.form | 2 +- .../modules/hashdatabase/HashDbCreateDatabaseDialog.java | 2 +- .../modules/hashdatabase/HashDbImportDatabaseDialog.form | 1 + .../modules/hashdatabase/HashDbImportDatabaseDialog.java | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form index 8eae9f15c4..b274f93d3c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form @@ -186,6 +186,7 @@ + @@ -320,7 +321,6 @@ - diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java index 5b7c0f1944..7f15bb47ac 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java @@ -225,6 +225,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { }); buttonGroup1.add(knownBadRadioButton); + knownBadRadioButton.setSelected(true); org.openide.awt.Mnemonics.setLocalizedText(knownBadRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.knownBadRadioButton.text")); // NOI18N knownBadRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -293,7 +294,6 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { }); buttonGroup1.add(noChangeRadioButton); - noChangeRadioButton.setSelected(true); org.openide.awt.Mnemonics.setLocalizedText(noChangeRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.noChangeRadioButton.text")); // NOI18N noChangeRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form index 720d3763a2..13ed7fbf57 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form @@ -228,6 +228,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index 10b9827404..c2716c4927 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -219,6 +219,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { }); buttonGroup1.add(knownBadRadioButton); + knownBadRadioButton.setSelected(true); org.openide.awt.Mnemonics.setLocalizedText(knownBadRadioButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.knownBadRadioButton.text")); // NOI18N knownBadRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { From ca79ad38de9d4419f5f3ebacc11f296224241640 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 5 May 2020 10:06:18 -0400 Subject: [PATCH 12/81] revert annotations viewer --- .../autopsy/contentviewers/AnnotationsContentViewer.form | 4 ++-- .../autopsy/contentviewers/AnnotationsContentViewer.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.form index 986492a810..4fe61b2fb5 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.form @@ -21,12 +21,12 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index 84b68b02df..c5c92b11c0 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -399,11 +399,11 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane5, javax.swing.GroupLayout.DEFAULT_SIZE, 696, Short.MAX_VALUE) + .addComponent(jScrollPane5, javax.swing.GroupLayout.DEFAULT_SIZE, 907, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane5, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 494, Short.MAX_VALUE) + .addComponent(jScrollPane5, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 435, Short.MAX_VALUE) ); }// //GEN-END:initComponents From dc01c80bdae5e92290dcf4a0bfd7ed5eb66eb994 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 5 May 2020 10:19:26 -0400 Subject: [PATCH 13/81] Added isNewCase to CaseContext --- .../autopsy/appservices/AutopsyService.java | 15 +++++++++++++++ .../org/sleuthkit/autopsy/casemodule/Case.java | 8 ++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/appservices/AutopsyService.java b/Core/src/org/sleuthkit/autopsy/appservices/AutopsyService.java index 3e67e6a442..1271b622dd 100644 --- a/Core/src/org/sleuthkit/autopsy/appservices/AutopsyService.java +++ b/Core/src/org/sleuthkit/autopsy/appservices/AutopsyService.java @@ -90,6 +90,7 @@ public interface AutopsyService { private final Case theCase; private final ProgressIndicator progressIndicator; private volatile boolean cancelRequested; + private final boolean isNewCase; /** * Constructs the context for the creation/opening/upgrading of @@ -100,9 +101,23 @@ public interface AutopsyService { * case-level resources */ public CaseContext(Case theCase, ProgressIndicator progressIndicator) { + this(theCase, progressIndicator, false); + } + + /** + * Constructs the context for the creation/opening/upgrading of + * case-level resources by a service. + * + * @param theCase The case. + * @param progressIndicator A progress indicator for the opening of the + * case-level resources. + * @param isNewCase True if theCase is a new case. + */ + public CaseContext(Case theCase, ProgressIndicator progressIndicator, boolean isNewCase) { this.theCase = theCase; this.progressIndicator = progressIndicator; this.cancelRequested = false; + this.isNewCase = isNewCase; } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 6c6e102dac..fe6dce83c4 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -1956,7 +1956,7 @@ public class Case { checkForCancellation(); openCaseLevelServices(progressIndicator); checkForCancellation(); - openAppServiceCaseResources(progressIndicator); + openAppServiceCaseResources(progressIndicator, true); checkForCancellation(); openCommunicationChannels(progressIndicator); return null; @@ -2005,7 +2005,7 @@ public class Case { checkForCancellation(); openCaseLevelServices(progressIndicator); checkForCancellation(); - openAppServiceCaseResources(progressIndicator); + openAppServiceCaseResources(progressIndicator, false); checkForCancellation(); openCommunicationChannels(progressIndicator); checkForCancellation(); @@ -2514,7 +2514,7 @@ public class Case { "# {0} - service name", "Case.serviceOpenCaseResourcesProgressIndicator.cancellingMessage=Cancelling opening case resources by {0}...", "# {0} - service name", "Case.servicesException.notificationTitle={0} Error" }) - private void openAppServiceCaseResources(ProgressIndicator progressIndicator) throws CaseActionException { + private void openAppServiceCaseResources(ProgressIndicator progressIndicator, boolean isNewCase) throws CaseActionException { /* * Each service gets its own independently cancellable/interruptible * task, running in a named thread managed by an executor service, with @@ -2546,7 +2546,7 @@ public class Case { appServiceProgressIndicator = new LoggingProgressIndicator(); } appServiceProgressIndicator.start(Bundle.Case_progressMessage_preparing()); - AutopsyService.CaseContext context = new AutopsyService.CaseContext(this, appServiceProgressIndicator); + AutopsyService.CaseContext context = new AutopsyService.CaseContext(this, appServiceProgressIndicator, isNewCase); String threadNameSuffix = service.getServiceName().replaceAll("[ ]", "-"); //NON-NLS threadNameSuffix = threadNameSuffix.toLowerCase(); TaskThreadFactory threadFactory = new TaskThreadFactory(String.format(CASE_RESOURCES_THREAD_NAME, threadNameSuffix)); From 306632cc3cfb205aa2aa8d676abb3111b788d062 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 5 May 2020 11:40:13 -0400 Subject: [PATCH 14/81] some minor bug fixes --- .../autopsy/modules/hashdatabase/Bundle.properties | 5 ----- .../modules/hashdatabase/HashDbIngestModule.java | 14 ++++++++------ .../modules/hashdatabase/HashDbManager.java | 11 ++++++++--- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index 2e32d65089..e7ed2dedd7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -94,9 +94,6 @@ HashDbIngestModule.fileReadErrorMsg=Read Error: {0} HashDbIngestModule.calcHashValueErr=Error encountered while calculating the hash value for {0} ({1}). HashDbIngestModule.hashLookupErrorMsg=Hash Lookup Error: {0} HashDbIngestModule.settingKnownBadStateErr=Error encountered while setting notable state for {0}. -HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}. -HashDbIngestModule.lookingUpNoChangeHashValueErr=Error encountered while looking up no change hash value for {0}. -HashDbIngestModule.lookingUpKnownHashValueErr=Error encountered while looking up known hash value for {0}. HashDbIngestModule.postToBB.fileName=File Name HashDbIngestModule.postToBB.md5Hash=MD5 Hash HashDbIngestModule.postToBB.hashsetName=Hash Set Name @@ -146,8 +143,6 @@ HashDbManager.hashDbFileExistsExceptionMsg=A file already exists at\n{0} HashDbManager.hashDbAlreadyAddedExceptionMsg=The hash set at\n{0}\nhas already been created or imported. HashDbManager.illegalHashDbFileNameExtensionMsg=The hash set file name must have a .{0} extension. HashDbManager.moduleErr=Module Error -HashDbManager.knownBad.text=Notable -HashDbManager.known.text=Known HashDbManager.fileNameExtensionFilter.title=Hash Set File HashDbSearchAction.dlgMsg.title=File Search by MD5 Hash HashDbSearchAction.getName.text=Hash Search diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 32268ccf53..0f471c0f76 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -61,20 +61,23 @@ import org.sleuthkit.datamodel.TskException; "HashDbIngestModule.noKnownBadHashDbSetMsg=No notable hash set.", "HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=Notable file search will not be executed.", "HashDbIngestModule.noKnownHashDbSetMsg=No known hash set.", - "HashDbIngestModule.knownFileSearchWillNotExecuteWarn=Known file search will not be executed." + "HashDbIngestModule.knownFileSearchWillNotExecuteWarn=Known file search will not be executed.", + "# {0} - fileName", "HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}.", + "# {0} - fileName", "HashDbIngestModule.lookingUpNoChangeHashValueErr=Error encountered while looking up no change hash value for {0}.", + "# {0} - fileName", "HashDbIngestModule.lookingUpKnownHashValueErr=Error encountered while looking up known hash value for {0}.", }) public class HashDbIngestModule implements FileIngestModule { private static final Logger logger = Logger.getLogger(HashDbIngestModule.class.getName()); private final Function knownBadLookupError = - (file) -> NbBundle.getMessage(this.getClass(), "HashDbIngestModule.lookingUpKnownBadHashValueErr", file.getName()); + (file) -> Bundle.HashDbIngestModule_lookingUpKnownBadHashValueErr(file.getName()); private final Function noChangeLookupError = - (file) -> NbBundle.getMessage(this.getClass(), "HashDbIngestModule.lookingUpNoChangeHashValueErr", file.getName()); + (file) -> Bundle.HashDbIngestModule_lookingUpNoChangeHashValueErr(file.getName()); private final Function knownLookupError = - (file) -> NbBundle.getMessage(this.getClass(), "HashDbIngestModule.lookingUpKnownHashValueErr", file.getName()); + (file) -> Bundle.HashDbIngestModule_lookingUpKnownHashValueErr(file.getName()); private static final int MAX_COMMENT_SIZE = 500; private final IngestServices services = IngestServices.getInstance(); @@ -223,14 +226,13 @@ public class HashDbIngestModule implements FileIngestModule { FindInHashsetsResult noChangeResult = findInHashsets(file, totals.totalNoChangeCount, totals.totalLookuptime, noChangeHashSets, TskData.FileKnown.BAD, noChangeLookupError); - boolean foundNoChange = noChangeResult.isFound(); if (noChangeResult.isError()) ret = ProcessResult.ERROR; // If the file is not in the notable sets, search for it in the known sets. // Any hit is sufficient to classify it as known, and there is no need to create // a hit artifact or send a message to the application inbox. - if (!foundBad && !foundNoChange) { + if (!foundBad) { for (HashDb db : knownHashSets) { try { long lookupstart = System.currentTimeMillis(); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index 372538be64..ebc31b1d4a 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -695,11 +695,16 @@ public class HashDbManager implements PropertyChangeListener { * Indicates how files with hashes stored in a particular hash database * object should be classified. */ + @Messages({ + "HashDbManager.noChange.text=No Change", + "HashDbManager.known.text=Known", + "HashDbManager.knownBad.text=Notable" + }) public enum KnownFilesType { - KNOWN(NbBundle.getMessage(HashDbManager.class, "HashDbManager.known.text"), TskData.FileKnown.KNOWN, false, false), - KNOWN_BAD(NbBundle.getMessage(HashDbManager.class, "HashDbManager.knownBad.text"), TskData.FileKnown.BAD, true, true), - NO_CHANGE(NbBundle.getMessage(HashDbManager.class, "HashDbManager.noChange.text"), TskData.FileKnown.UNKNOWN, true , false); + KNOWN(Bundle.HashDbManager_known_text(), TskData.FileKnown.KNOWN, false, false), + KNOWN_BAD(Bundle.HashDbManager_knownBad_text(), TskData.FileKnown.BAD, true, true), + NO_CHANGE(Bundle.HashDbManager_noChange_text(), TskData.FileKnown.UNKNOWN, true , false); private final String displayName; private final TskData.FileKnown fileKnown; From d1b1bb88ae59d872c49c87630cb3486d629f1833 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 5 May 2020 12:04:13 -0400 Subject: [PATCH 15/81] naming convention change --- .../autopsy/modules/hashdatabase/HashDbIngestModule.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 0f471c0f76..dc8646dbe4 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -352,7 +352,7 @@ public class HashDbIngestModule implements FileIngestModule { file.setKnown(statusIfFound); String hashSetName = db.getDisplayName(); String comment = generateComment(hashInfo); - if (!createArtifactIfNoneExists(hashSetName, file, comment, db)) + if (!createArtifactIfNotExists(hashSetName, file, comment, db)) wasError = true; } long delta = (System.currentTimeMillis() - lookupstart); @@ -390,14 +390,14 @@ public class HashDbIngestModule implements FileIngestModule { } /** - * Creates a BlackboardArtifact if no TSK_HASHSET_HIT artifact exists for this file. + * Creates a BlackboardArtifact if artifact does not already exist. * @param hashSetName The name of the hashset found. * @param file The file that had a hash hit. * @param comment The comment to associate with this artifact. * @param db the database in which this file was found. * @return True if the operation occurred successfully and without error. */ - private boolean createArtifactIfNoneExists(String hashSetName, AbstractFile file, String comment, HashDb db) { + private boolean createArtifactIfNotExists(String hashSetName, AbstractFile file, String comment, HashDb db) { /* * We have a match. Now create an artifact if it is * determined that one hasn't been created yet. From aeb78fe9046916572d4357a0a834c23c59481ffe Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 5 May 2020 14:25:06 -0400 Subject: [PATCH 16/81] added reporting of no change items --- .../modules/hashdatabase/HashDbIngestModule.java | 15 +++++++++++---- .../modules/hashdatabase/KdbHashSetParser.java | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index dc8646dbe4..2f5b4f9c51 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -27,6 +27,7 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; import java.util.logging.Level; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; @@ -551,13 +552,14 @@ public class HashDbIngestModule implements FileIngestModule { * @param knownBadHashSets The list of hash sets for "known bad" files. * @param knownHashSets The list of hash sets for "known" files. */ + @Messages("HashDbIngestModule.complete.noChangesFound=No Change items found:") private static synchronized void postSummary(long jobId, List knownBadHashSets, List noChangeHashSets, List knownHashSets) { IngestJobTotals jobTotals = getTotalsForIngestJobs(jobId); totalsForIngestJobs.remove(jobId); - if ((!knownBadHashSets.isEmpty()) || (!knownHashSets.isEmpty())) { + if ((!knownBadHashSets.isEmpty()) || (!knownHashSets.isEmpty()) || (!noChangeHashSets.isEmpty())) { StringBuilder detailsSb = new StringBuilder(); //details detailsSb.append("
"); //NON-NLS @@ -567,6 +569,11 @@ public class HashDbIngestModule implements FileIngestModule { .append(""); //NON-NLS detailsSb.append(""); //NON-NLS + detailsSb.append(""); //NON-NLS + detailsSb.append(""); //NON-NLS + detailsSb.append("\n"); //NON-NLS @@ -578,9 +585,9 @@ public class HashDbIngestModule implements FileIngestModule { detailsSb.append("

") //NON-NLS .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.databasesUsed")) .append("

\n
    "); //NON-NLS - for (HashDb db : knownBadHashSets) { - detailsSb.append("
  • ").append(db.getHashSetName()).append("
  • \n"); //NON-NLS - } + Stream.concat(knownBadHashSets.stream(), noChangeHashSets.stream()).forEach((db) -> { + detailsSb.append("
  • ").append(db.getHashSetName()).append("
  • \n"); //NON-NLS + }); detailsSb.append("
"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java index d9b29b257c..023314bab0 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java @@ -145,7 +145,7 @@ public class KdbHashSetParser implements HashSetParser { HashRow row = getNextHashRow(); try { PreparedStatement getComment = conn.prepareStatement("SELECT comment FROM comments WHERE hash_id = ?"); - getComment.setLong(0, row.getHashId()); + getComment.setLong(1, row.getHashId()); ResultSet commentResults = getComment.executeQuery(); List comments = new ArrayList<>(); while (commentResults.next()) From f838c2217fe6d49ace0428da169caa2f278c1860 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 6 May 2020 09:48:58 -0400 Subject: [PATCH 17/81] comment fixes --- .../HashDbCreateDatabaseDialog.java | 12 +- .../HashDbImportDatabaseDialog.java | 6 +- .../hashdatabase/HashDbIngestModule.java | 237 +++++----- .../modules/hashdatabase/HashDbManager.java | 406 +++++++++--------- .../HashLookupModuleSettingsPanel.java | 40 +- .../hashdatabase/HashLookupSettingsPanel.java | 9 +- .../modules/hashdatabase/HashSetParser.java | 15 +- .../ImportCentralRepoDbProgressDialog.java | 6 +- .../hashdatabase/KdbHashSetParser.java | 22 +- 9 files changed, 398 insertions(+), 355 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java index 7f15bb47ac..63a8c84e93 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java @@ -488,17 +488,15 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } KnownFilesType type; - + if (knownRadioButton.isSelected()) { - type = KnownFilesType.KNOWN; - } - else if (noChangeRadioButton.isSelected()) { + type = KnownFilesType.KNOWN; + } else if (noChangeRadioButton.isSelected()) { type = KnownFilesType.NO_CHANGE; - } - else { + } else { type = KnownFilesType.KNOWN_BAD; } - + TskData.FileKnown fileKnown = type.getFileKnown(); String errorMessage = NbBundle diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index c2716c4927..c854cb165d 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -547,11 +547,9 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { KnownFilesType type; if (knownRadioButton.isSelected()) { type = KnownFilesType.KNOWN; - } - else if (noChangeRadioButton.isSelected()) { + } else if (noChangeRadioButton.isSelected()) { type = KnownFilesType.NO_CHANGE; - } - else { + } else { type = KnownFilesType.KNOWN_BAD; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 2f5b4f9c51..4752d80186 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -26,7 +26,6 @@ import java.util.List; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; import java.util.logging.Level; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; @@ -41,7 +40,6 @@ import org.sleuthkit.autopsy.ingest.IngestMessage; import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Blackboard; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -65,21 +63,20 @@ import org.sleuthkit.datamodel.TskException; "HashDbIngestModule.knownFileSearchWillNotExecuteWarn=Known file search will not be executed.", "# {0} - fileName", "HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}.", "# {0} - fileName", "HashDbIngestModule.lookingUpNoChangeHashValueErr=Error encountered while looking up no change hash value for {0}.", - "# {0} - fileName", "HashDbIngestModule.lookingUpKnownHashValueErr=Error encountered while looking up known hash value for {0}.", -}) + "# {0} - fileName", "HashDbIngestModule.lookingUpKnownHashValueErr=Error encountered while looking up known hash value for {0}.",}) public class HashDbIngestModule implements FileIngestModule { private static final Logger logger = Logger.getLogger(HashDbIngestModule.class.getName()); - - private final Function knownBadLookupError = - (file) -> Bundle.HashDbIngestModule_lookingUpKnownBadHashValueErr(file.getName()); - - private final Function noChangeLookupError = - (file) -> Bundle.HashDbIngestModule_lookingUpNoChangeHashValueErr(file.getName()); - - private final Function knownLookupError = - (file) -> Bundle.HashDbIngestModule_lookingUpKnownHashValueErr(file.getName()); - + + private final Function knownBadLookupError + = (file) -> Bundle.HashDbIngestModule_lookingUpKnownBadHashValueErr(file.getName()); + + private final Function noChangeLookupError + = (file) -> Bundle.HashDbIngestModule_lookingUpNoChangeHashValueErr(file.getName()); + + private final Function knownLookupError + = (file) -> Bundle.HashDbIngestModule_lookingUpKnownHashValueErr(file.getName()); + private static final int MAX_COMMENT_SIZE = 500; private final IngestServices services = IngestServices.getInstance(); private final SleuthkitCase skCase; @@ -130,11 +127,12 @@ public class HashDbIngestModule implements FileIngestModule { @Override public void startUp(org.sleuthkit.autopsy.ingest.IngestJobContext context) throws IngestModuleException { jobId = context.getJobId(); - if (!hashDbManager.verifyAllDatabasesLoadedCorrectly()) + if (!hashDbManager.verifyAllDatabasesLoadedCorrectly()) { throw new IngestModuleException("Could not load all hash sets"); + } initializeHashsets(hashDbManager.getAllHashSets()); - + if (refCounter.incrementAndGet(jobId) == 1) { // initialize job totals getTotalsForIngestJobs(jobId); @@ -157,9 +155,10 @@ public class HashDbIngestModule implements FileIngestModule { } /** - * Cycle through list of hashsets and place each HashDB in the appropriate list based on KnownFilesType. + * Cycle through list of hashsets and place each HashDB in the appropriate + * list based on KnownFilesType. * - * @param allHashSets List of all hashsets from DB manager + * @param allHashSets List of all hashsets from DB manager */ private void initializeHashsets(List allHashSets) { for (HashDb db : allHashSets) { @@ -167,7 +166,7 @@ public class HashDbIngestModule implements FileIngestModule { try { if (db.isValid()) { switch (db.getKnownFilesType()) { - case KNOWN: + case KNOWN: knownHashSets.add(db); break; case KNOWN_BAD: @@ -176,7 +175,8 @@ public class HashDbIngestModule implements FileIngestModule { case NO_CHANGE: noChangeHashSets.add(db); break; - default: throw new TskCoreException("Unknown KnownFilesType: " + db.getKnownFilesType()); + default: + throw new TskCoreException("Unknown KnownFilesType: " + db.getKnownFilesType()); } } } catch (TskCoreException ex) { @@ -200,35 +200,39 @@ public class HashDbIngestModule implements FileIngestModule { logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS return ProcessResult.ERROR; } - - if (shouldSkip(file)) + + if (shouldSkip(file)) { return ProcessResult.OK; + } // Safely get a reference to the totalsForIngestJobs object IngestJobTotals totals = getTotalsForIngestJobs(jobId); // calc hash value String md5Hash = GetHash(file, totals); - if (md5Hash == null) + if (md5Hash == null) { return ProcessResult.ERROR; + } // the processing result of handling this file ProcessResult ret = ProcessResult.OK; - + // look up in notable first - FindInHashsetsResult knownBadResult = findInHashsets(file, totals.totalKnownBadCount, - totals.totalLookuptime, knownBadHashSets, TskData.FileKnown.BAD, knownBadLookupError); - + FindInHashsetsResult knownBadResult = findInHashsets(file, totals.totalKnownBadCount, + totals.totalLookuptime, knownBadHashSets, TskData.FileKnown.BAD, knownBadLookupError); + boolean foundBad = knownBadResult.isFound(); - if (knownBadResult.isError()) + if (knownBadResult.isError()) { ret = ProcessResult.ERROR; + } // look up no change items next - FindInHashsetsResult noChangeResult = findInHashsets(file, totals.totalNoChangeCount, - totals.totalLookuptime, noChangeHashSets, TskData.FileKnown.BAD, noChangeLookupError); - - if (noChangeResult.isError()) - ret = ProcessResult.ERROR; + FindInHashsetsResult noChangeResult = findInHashsets(file, totals.totalNoChangeCount, + totals.totalLookuptime, noChangeHashSets, TskData.FileKnown.BAD, noChangeLookupError); + + if (noChangeResult.isError()) { + ret = ProcessResult.ERROR; + } // If the file is not in the notable sets, search for it in the known sets. // Any hit is sufficient to classify it as known, and there is no need to create @@ -253,16 +257,18 @@ public class HashDbIngestModule implements FileIngestModule { return ret; } - + /** * Returns true if this file should be skipped for processing. + * * @param file The file to potentially skip. + * * @return True if this file should be skipped. */ private boolean shouldSkip(AbstractFile file) { // Skip unallocated space files. if ((file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) - || file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) { + || file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) { return true; } @@ -272,36 +278,41 @@ public class HashDbIngestModule implements FileIngestModule { * IDX_ROOT and IDX_ALLOC artifacts. So we disable that until a solution * for it is developed. */ - if (file.isDir()) + if (file.isDir()) { return true; + } // bail out if we have no hashes set - if ((knownHashSets.isEmpty()) && (knownBadHashSets.isEmpty()) && (!settings.shouldCalculateHashes())) + if ((knownHashSets.isEmpty()) && (knownBadHashSets.isEmpty()) && (!settings.shouldCalculateHashes())) { return true; + } return false; } - /** - * Reports an error when an issue is encountered looking up a file. - * @param ex The exception thrown in the error. - * @param file The file for which this error applies. - * @param lookupErrorMessage The function that generates an error message specific to which piece of the ingest processing failed. + * Reports an error when an issue is encountered looking up a file. + * + * @param ex The exception thrown in the error. + * @param file The file for which this error applies. + * @param lookupErrorMessage The function that generates an error message + * specific to which piece of the ingest + * processing failed. */ private void reportLookupError(TskException ex, AbstractFile file, Function lookupErrorMessage) { logger.log(Level.WARNING, String.format( - "Couldn't lookup notable hash for file '%s' (id=%d) - see sleuthkit log for details", file.getName(), file.getId()), ex); //NON-NLS + "Couldn't lookup notable hash for file '%s' (id=%d) - see sleuthkit log for details", file.getName(), file.getId()), ex); //NON-NLS services.postMessage(IngestMessage.createErrorMessage( HashLookupModuleFactory.getModuleName(), NbBundle.getMessage(this.getClass(), "HashDbIngestModule.hashLookupErrorMsg", file.getName()), lookupErrorMessage.apply(file))); } - + /** * The result of attempting to find a file in a list of HashDB objects. */ private static class FindInHashsetsResult { + private final boolean found; private final boolean error; @@ -312,6 +323,7 @@ public class HashDbIngestModule implements FileIngestModule { /** * Returns true if the file was found in the HashDB. + * * @return True if the file was found in the HashDB. */ boolean isFound() { @@ -319,8 +331,11 @@ public class HashDbIngestModule implements FileIngestModule { } /** - * Returns true if there was an error in the process of finding a file in a HashDB. - * @return True if there was an error in the process of finding a file in a HashDB. + * Returns true if there was an error in the process of finding a file + * in a HashDB. + * + * @return True if there was an error in the process of finding a file + * in a HashDB. */ boolean isError() { return error; @@ -329,17 +344,25 @@ public class HashDbIngestModule implements FileIngestModule { /** * Attempts to find an abstract file in a list of HashDB objects. - * @param file The file to find. - * @param totalCount The total cound of files found in this type - * @param totalLookupTime The counter tracking the total amount of run time for this operation. - * @param hashSets The HashDB objects to cycle through looking for a hash hit. - * @param statusIfFound The FileKnown status to set on the file if the file is found in the hashSets. - * @param lookupErrorMessage The function that generates a message should there be an error in looking up the file in the hashSets. - * @return Whether or not the file was found and whether or not there was an error during the operation. + * + * @param file The file to find. + * @param totalCount The total cound of files found in this type + * @param totalLookupTime The counter tracking the total amount of run + * time for this operation. + * @param hashSets The HashDB objects to cycle through looking for + * a hash hit. + * @param statusIfFound The FileKnown status to set on the file if the + * file is found in the hashSets. + * @param lookupErrorMessage The function that generates a message should + * there be an error in looking up the file in the + * hashSets. + * + * @return Whether or not the file was found and whether or not there was an + * error during the operation. */ - private FindInHashsetsResult findInHashsets(AbstractFile file, AtomicLong totalCount, AtomicLong totalLookupTime, + private FindInHashsetsResult findInHashsets(AbstractFile file, AtomicLong totalCount, AtomicLong totalLookupTime, List hashSets, TskData.FileKnown statusIfFound, Function lookupErrorMessage) { - + boolean found = false; boolean wasError = false; for (HashDb db : hashSets) { @@ -348,13 +371,14 @@ public class HashDbIngestModule implements FileIngestModule { HashHitInfo hashInfo = db.lookupMD5(file); if (null != hashInfo) { found = true; - + totalCount.incrementAndGet(); file.setKnown(statusIfFound); String hashSetName = db.getDisplayName(); String comment = generateComment(hashInfo); - if (!createArtifactIfNotExists(hashSetName, file, comment, db)) + if (!createArtifactIfNotExists(hashSetName, file, comment, db)) { wasError = true; + } } long delta = (System.currentTimeMillis() - lookupstart); totalLookupTime.addAndGet(delta); @@ -364,13 +388,15 @@ public class HashDbIngestModule implements FileIngestModule { wasError = true; } } - + return new FindInHashsetsResult(found, wasError); } /** * Generates a formatted comment. + * * @param hashInfo The HashHitInfo. + * * @return The formatted comment. */ private String generateComment(HashHitInfo hashInfo) { @@ -392,16 +418,18 @@ public class HashDbIngestModule implements FileIngestModule { /** * Creates a BlackboardArtifact if artifact does not already exist. + * * @param hashSetName The name of the hashset found. - * @param file The file that had a hash hit. - * @param comment The comment to associate with this artifact. - * @param db the database in which this file was found. + * @param file The file that had a hash hit. + * @param comment The comment to associate with this artifact. + * @param db the database in which this file was found. + * * @return True if the operation occurred successfully and without error. */ private boolean createArtifactIfNotExists(String hashSetName, AbstractFile file, String comment, HashDb db) { /* - * We have a match. Now create an artifact if it is - * determined that one hasn't been created yet. + * We have a match. Now create an artifact if it is determined that one + * hasn't been created yet. */ List attributesList = new ArrayList<>(); attributesList.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, HashLookupModuleFactory.getModuleName(), hashSetName)); @@ -421,49 +449,52 @@ public class HashDbIngestModule implements FileIngestModule { } return true; } - + /** - * Retrieves the md5 hash for a file or generates one if no one exists on the file. - * @param file The file in order to determine the hash. + * Retrieves the md5 hash for a file or generates one if no one exists on + * the file. + * + * @param file The file in order to determine the hash. * @param totals The timing metrics for this process. - * @return The found or determined md5 hash or null if none could be determined. + * + * @return The found or determined md5 hash or null if none could be + * determined. */ private String GetHash(AbstractFile file, IngestJobTotals totals) { String md5Hash = file.getMd5Hash(); - if (md5Hash != null && md5Hash.isEmpty()) + if (md5Hash != null && md5Hash.isEmpty()) { return md5Hash; - + } + try { - TimingMetric metric = HealthMonitor.getTimingMetric("Disk Reads: Hash calculation"); - long calcstart = System.currentTimeMillis(); - md5Hash = HashUtility.calculateMd5Hash(file); - if (file.getSize() > 0) { - // Surprisingly, the hash calculation does not seem to be correlated that - // strongly with file size until the files get large. - // Only normalize if the file size is greater than ~1MB. - if (file.getSize() < 1000000) { - HealthMonitor.submitTimingMetric(metric); - } - else { - // In testing, this normalization gave reasonable resuls - HealthMonitor.submitNormalizedTimingMetric(metric, file.getSize() / 500000); - } - } - file.setMd5Hash(md5Hash); - long delta = (System.currentTimeMillis() - calcstart); - totals.totalCalctime.addAndGet(delta); - return md5Hash; - } - catch (IOException ex) { - logger.log(Level.WARNING, String.format("Error calculating hash of file '%s' (id=%d).", file.getName(), file.getId()), ex); //NON-NLS - services.postMessage(IngestMessage.createErrorMessage( - HashLookupModuleFactory.getModuleName(), - NbBundle.getMessage(this.getClass(), "HashDbIngestModule.fileReadErrorMsg", file.getName()), - NbBundle.getMessage(this.getClass(), "HashDbIngestModule.calcHashValueErr", - file.getParentPath() + file.getName(), - file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)?"Allocated File" : "Deleted File"))); - return null; - } + TimingMetric metric = HealthMonitor.getTimingMetric("Disk Reads: Hash calculation"); + long calcstart = System.currentTimeMillis(); + md5Hash = HashUtility.calculateMd5Hash(file); + if (file.getSize() > 0) { + // Surprisingly, the hash calculation does not seem to be correlated that + // strongly with file size until the files get large. + // Only normalize if the file size is greater than ~1MB. + if (file.getSize() < 1000000) { + HealthMonitor.submitTimingMetric(metric); + } else { + // In testing, this normalization gave reasonable resuls + HealthMonitor.submitNormalizedTimingMetric(metric, file.getSize() / 500000); + } + } + file.setMd5Hash(md5Hash); + long delta = (System.currentTimeMillis() - calcstart); + totals.totalCalctime.addAndGet(delta); + return md5Hash; + } catch (IOException ex) { + logger.log(Level.WARNING, String.format("Error calculating hash of file '%s' (id=%d).", file.getName(), file.getId()), ex); //NON-NLS + services.postMessage(IngestMessage.createErrorMessage( + HashLookupModuleFactory.getModuleName(), + NbBundle.getMessage(this.getClass(), "HashDbIngestModule.fileReadErrorMsg", file.getName()), + NbBundle.getMessage(this.getClass(), "HashDbIngestModule.calcHashValueErr", + file.getParentPath() + file.getName(), + file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC) ? "Allocated File" : "Deleted File"))); + return null; + } } /** @@ -553,9 +584,9 @@ public class HashDbIngestModule implements FileIngestModule { * @param knownHashSets The list of hash sets for "known" files. */ @Messages("HashDbIngestModule.complete.noChangesFound=No Change items found:") - private static synchronized void postSummary(long jobId, List knownBadHashSets, + private static synchronized void postSummary(long jobId, List knownBadHashSets, List noChangeHashSets, List knownHashSets) { - + IngestJobTotals jobTotals = getTotalsForIngestJobs(jobId); totalsForIngestJobs.remove(jobId); @@ -573,7 +604,7 @@ public class HashDbIngestModule implements FileIngestModule { .append(Bundle.HashDbIngestModule_complete_noChangesFound()) .append(""); //NON-NLS detailsSb.append(""); //NON-NLS - + detailsSb.append("\n"); //NON-NLS @@ -585,7 +616,7 @@ public class HashDbIngestModule implements FileIngestModule { detailsSb.append("

") //NON-NLS .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.databasesUsed")) .append("

\n
    "); //NON-NLS - Stream.concat(knownBadHashSets.stream(), noChangeHashSets.stream()).forEach((db) -> { + Stream.concat(knownBadHashSets.stream(), noChangeHashSets.stream()).forEach((db) -> { detailsSb.append("
  • ").append(db.getHashSetName()).append("
  • \n"); //NON-NLS }); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index ebc31b1d4a..b9833ecafb 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * + * * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,12 +23,10 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; import java.io.IOException; -import java.io.Serializable; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.logging.Level; @@ -106,8 +104,8 @@ public class HashDbManager implements PropertyChangeListener { public synchronized void removePropertyChangeListener(PropertyChangeListener listener) { changeSupport.removePropertyChangeListener(listener); } - - synchronized boolean verifyAllDatabasesLoadedCorrectly(){ + + synchronized boolean verifyAllDatabasesLoadedCorrectly() { return allDatabasesLoadedCorrectly; } @@ -241,7 +239,7 @@ public class HashDbManager implements PropertyChangeListener { } return hashDb; } - + private SleuthkitHashSet addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws TskCoreException { // Wrap an object around the handle. SleuthkitHashSet hashDb = new SleuthkitHashSet(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); @@ -276,22 +274,22 @@ public class HashDbManager implements PropertyChangeListener { } return hashDb; } - - CentralRepoHashSet addExistingCentralRepoHashSet(String hashSetName, String version, int referenceSetID, - boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType, - boolean readOnly) throws TskCoreException{ - - if(! CentralRepository.isEnabled()){ + + CentralRepoHashSet addExistingCentralRepoHashSet(String hashSetName, String version, int referenceSetID, + boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType, + boolean readOnly) throws TskCoreException { + + if (!CentralRepository.isEnabled()) { throw new TskCoreException("Could not load central repository hash set " + hashSetName + " - central repository is not enabled"); } - + CentralRepoHashSet db = new CentralRepoHashSet(hashSetName, version, referenceSetID, searchDuringIngest, - sendIngestMessages, knownFilesType, readOnly); - - if(! db.isValid()){ + sendIngestMessages, knownFilesType, readOnly); + + if (!db.isValid()) { throw new TskCoreException("Error finding hash set " + hashSetName + " in central repository"); } - + // Add the hash database to the collection hashSets.add(db); @@ -305,8 +303,8 @@ public class HashDbManager implements PropertyChangeListener { NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErrorListeningToUpdatesMsg"), MessageNotifyUtil.MessageType.ERROR); } - return db; - + return db; + } synchronized void indexHashDatabase(SleuthkitHashSet hashDb) { @@ -344,7 +342,7 @@ public class HashDbManager implements PropertyChangeListener { this.removeHashDatabaseNoSave(hashDb); this.save(); } - + public synchronized void removeHashDatabaseNoSave(HashDb hashDb) throws HashDbManagerException { // Don't remove a database if ingest is running boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning(); @@ -360,17 +358,16 @@ public class HashDbManager implements PropertyChangeListener { hashSets.remove(hashDb); // Now undertake the operations that could throw. - // Indexing is only relevanet for sleuthkit hashsets - if(hashDb instanceof SleuthkitHashSet){ - SleuthkitHashSet hashDatabase = (SleuthkitHashSet)hashDb; + if (hashDb instanceof SleuthkitHashSet) { + SleuthkitHashSet hashDatabase = (SleuthkitHashSet) hashDb; try { - if(hashDatabase.hasIndex()){ + if (hashDatabase.hasIndex()) { hashSetPaths.remove(hashDatabase.getIndexPath()); } } catch (TskCoreException ex) { Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDatabase.getHashSetName() + " hash set when removing the hash set", ex); //NON-NLS - } + } try { if (!hashDatabase.hasIndexOnly()) { @@ -379,7 +376,7 @@ public class HashDbManager implements PropertyChangeListener { } catch (TskCoreException ex) { Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting hash set path of " + hashDatabase.getHashSetName() + " hash set when removing the hash set", ex); //NON-NLS } - + try { hashDatabase.close(); } catch (TskCoreException ex) { @@ -408,7 +405,7 @@ public class HashDbManager implements PropertyChangeListener { throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.saveErrorExceptionMsg")); } } - + /** * Gets all of the hash databases used to classify files as known or known * bad. Will add any new central repository databases to the list before @@ -417,12 +414,12 @@ public class HashDbManager implements PropertyChangeListener { * @return A list, possibly empty, of hash databases. */ public synchronized List getAllHashSets() { - try{ + try { updateHashSetsFromCentralRepository(); - } catch (TskCoreException ex){ + } catch (TskCoreException ex) { Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS } - + List hashDbs = new ArrayList<>(); hashDbs.addAll(this.hashSets); return hashDbs; @@ -435,9 +432,9 @@ public class HashDbManager implements PropertyChangeListener { */ public synchronized List getKnownFileHashSets() { List hashDbs = new ArrayList<>(); - try{ + try { updateHashSetsFromCentralRepository(); - } catch (TskCoreException ex){ + } catch (TskCoreException ex) { Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS } this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN)).forEach((db) -> { @@ -453,9 +450,9 @@ public class HashDbManager implements PropertyChangeListener { */ public synchronized List getKnownBadFileHashSets() { List hashDbs = new ArrayList<>(); - try{ + try { updateHashSetsFromCentralRepository(); - } catch (TskCoreException ex){ + } catch (TskCoreException ex) { Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS } this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN_BAD)).forEach((db) -> { @@ -475,9 +472,9 @@ public class HashDbManager implements PropertyChangeListener { private List getUpdateableHashSets(List hashDbs) { ArrayList updateableDbs = new ArrayList<>(); - try{ + try { updateHashSetsFromCentralRepository(); - } catch (TskCoreException ex){ + } catch (TskCoreException ex) { Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS } for (HashDb db : hashDbs) { @@ -491,22 +488,22 @@ public class HashDbManager implements PropertyChangeListener { } return updateableDbs; } - - private List getCentralRepoHashSetsFromDatabase(){ + + private List getCentralRepoHashSetsFromDatabase() { List crHashSets = new ArrayList<>(); - if(CentralRepository.isEnabled()){ - try{ + if (CentralRepository.isEnabled()) { + try { List crSets = CentralRepository.getInstance().getAllReferenceSets(CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID)); - for(CentralRepoFileSet globalSet:crSets){ - + for (CentralRepoFileSet globalSet : crSets) { + // Defaults for fields not stored in the central repository: // searchDuringIngest: false // sendIngestMessages: true if the hash set is notable boolean sendIngestMessages = KnownFilesType.fromFileKnown(globalSet.getFileKnownStatus()).equals(HashDb.KnownFilesType.KNOWN_BAD); crHashSets.add(new HashDbInfo(globalSet.getSetName(), globalSet.getVersion(), - globalSet.getGlobalSetID(), KnownFilesType.fromFileKnown(globalSet.getFileKnownStatus()), globalSet.isReadOnly(), false, sendIngestMessages)); - } - } catch (CentralRepoException ex){ + globalSet.getGlobalSetID(), KnownFilesType.fromFileKnown(globalSet.getFileKnownStatus()), globalSet.isReadOnly(), false, sendIngestMessages)); + } + } catch (CentralRepoException ex) { Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS } } @@ -527,9 +524,9 @@ public class HashDbManager implements PropertyChangeListener { private void closeHashDatabases(List hashDatabases) { for (HashDb database : hashDatabases) { - if(database instanceof SleuthkitHashSet){ + if (database instanceof SleuthkitHashSet) { try { - ((SleuthkitHashSet)database).close(); + ((SleuthkitHashSet) database).close(); } catch (TskCoreException ex) { Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + database.getHashSetName() + " hash set", ex); //NON-NLS } @@ -554,13 +551,13 @@ public class HashDbManager implements PropertyChangeListener { * @param settings The settings to configure. */ @Messages({"# {0} - hash set name", "HashDbManager.noDbPath.message=Couldn't get valid hash set path for: {0}", - "HashDbManager.centralRepoLoadError.message=Error loading central repository hash sets"}) + "HashDbManager.centralRepoLoadError.message=Error loading central repository hash sets"}) private void configureSettings(HashLookupSettings settings) { allDatabasesLoadedCorrectly = true; List hashDbInfoList = settings.getHashDbInfo(); for (HashDbInfo hashDbInfo : hashDbInfoList) { try { - if(hashDbInfo.isFileDatabaseType()){ + if (hashDbInfo.isFileDatabaseType()) { String dbPath = this.getValidFilePath(hashDbInfo.getHashSetName(), hashDbInfo.getPath()); if (dbPath != null) { addHashDatabase(SleuthkitJNI.openHashDatabase(dbPath), hashDbInfo.getHashSetName(), hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType()); @@ -569,10 +566,10 @@ public class HashDbManager implements PropertyChangeListener { allDatabasesLoadedCorrectly = false; } } else { - if(CentralRepository.isEnabled()){ - addExistingCentralRepoHashSet(hashDbInfo.getHashSetName(), hashDbInfo.getVersion(), - hashDbInfo.getReferenceSetID(), - hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), + if (CentralRepository.isEnabled()) { + addExistingCentralRepoHashSet(hashDbInfo.getHashSetName(), hashDbInfo.getVersion(), + hashDbInfo.getReferenceSetID(), + hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType(), hashDbInfo.isReadOnly()); } } @@ -586,13 +583,13 @@ public class HashDbManager implements PropertyChangeListener { allDatabasesLoadedCorrectly = false; } } - - if(CentralRepository.isEnabled()){ - try{ + + if (CentralRepository.isEnabled()) { + try { updateHashSetsFromCentralRepository(); - } catch (TskCoreException ex){ + } catch (TskCoreException ex) { Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash set", ex); //NON-NLS - + JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), Bundle.HashDbManager_centralRepoLoadError_message(), NbBundle.getMessage(this.getClass(), "HashDbManager.openHashDbErr"), @@ -600,14 +597,17 @@ public class HashDbManager implements PropertyChangeListener { allDatabasesLoadedCorrectly = false; } } - - /* NOTE: When RuntimeProperties.coreComponentsAreActive() is "false", - I don't think we should overwrite hash db settings file because we - were unable to load a database. The user should have to fix the issue or - remove the database from settings. Overwiting the settings effectively removes - the database from HashLookupSettings and the user may not know about this - because the dialogs are not being displayed. The next time user starts Autopsy, HashDB - will load without errors and the user may think that the problem was solved.*/ + + /* + * NOTE: When RuntimeProperties.coreComponentsAreActive() is "false", I + * don't think we should overwrite hash db settings file because we were + * unable to load a database. The user should have to fix the issue or + * remove the database from settings. Overwiting the settings + * effectively removes the database from HashLookupSettings and the user + * may not know about this because the dialogs are not being displayed. + * The next time user starts Autopsy, HashDB will load without errors + * and the user may think that the problem was solved. + */ if (!allDatabasesLoadedCorrectly && RuntimeProperties.runningWithGUI()) { try { HashLookupSettings.writeSettings(new HashLookupSettings(HashLookupSettings.convertHashSetList(this.hashSets))); @@ -618,31 +618,31 @@ public class HashDbManager implements PropertyChangeListener { } } } - + private void updateHashSetsFromCentralRepository() throws TskCoreException { - if(CentralRepository.isEnabled()){ + if (CentralRepository.isEnabled()) { List crHashDbInfoList = getCentralRepoHashSetsFromDatabase(); - for(HashDbInfo hashDbInfo : crHashDbInfoList) { - if(hashDbInfoIsNew(hashDbInfo)){ - addExistingCentralRepoHashSet(hashDbInfo.getHashSetName(), hashDbInfo.getVersion(), - hashDbInfo.getReferenceSetID(), - hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType(), - hashDbInfo.isReadOnly()); + for (HashDbInfo hashDbInfo : crHashDbInfoList) { + if (hashDbInfoIsNew(hashDbInfo)) { + addExistingCentralRepoHashSet(hashDbInfo.getHashSetName(), hashDbInfo.getVersion(), + hashDbInfo.getReferenceSetID(), + hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType(), + hashDbInfo.isReadOnly()); } } } } - - private boolean hashDbInfoIsNew(HashDbInfo dbInfo){ - for(HashDb db:this.hashSets){ - if(dbInfo.matches(db)){ + + private boolean hashDbInfoIsNew(HashDbInfo dbInfo) { + for (HashDb db : this.hashSets) { + if (dbInfo.matches(db)) { return false; } } return true; } - private String getValidFilePath(String hashSetName, String configuredPath) { + private String getValidFilePath(String hashSetName, String configuredPath) { // Check the configured path. File database = new File(configuredPath); if (database.exists()) { @@ -651,12 +651,12 @@ public class HashDbManager implements PropertyChangeListener { // Give the user an opportunity to find the desired file. String newPath = null; - if (RuntimeProperties.runningWithGUI() && - JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(), - NbBundle.getMessage(this.getClass(), "HashDbManager.dlgMsg.dbNotFoundAtLoc", - hashSetName, configuredPath), - NbBundle.getMessage(this.getClass(), "HashDbManager.dlgTitle.MissingDb"), - JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { + if (RuntimeProperties.runningWithGUI() + && JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(), + NbBundle.getMessage(this.getClass(), "HashDbManager.dlgMsg.dbNotFoundAtLoc", + hashSetName, configuredPath), + NbBundle.getMessage(this.getClass(), "HashDbManager.dlgTitle.MissingDb"), + JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { newPath = searchForFile(); if (null != newPath && !newPath.isEmpty()) { database = new File(newPath); @@ -688,24 +688,24 @@ public class HashDbManager implements PropertyChangeListener { } return filePath; } - + public static abstract class HashDb { - + /** * Indicates how files with hashes stored in a particular hash database * object should be classified. */ @Messages({ - "HashDbManager.noChange.text=No Change", - "HashDbManager.known.text=Known", - "HashDbManager.knownBad.text=Notable" + "HashDbManager.noChange.text=No Change", + "HashDbManager.known.text=Known", + "HashDbManager.knownBad.text=Notable" }) public enum KnownFilesType { KNOWN(Bundle.HashDbManager_known_text(), TskData.FileKnown.KNOWN, false, false), KNOWN_BAD(Bundle.HashDbManager_knownBad_text(), TskData.FileKnown.BAD, true, true), - NO_CHANGE(Bundle.HashDbManager_noChange_text(), TskData.FileKnown.UNKNOWN, true , false); - + NO_CHANGE(Bundle.HashDbManager_noChange_text(), TskData.FileKnown.UNKNOWN, true, false); + private final String displayName; private final TskData.FileKnown fileKnown; private final boolean allowSendInboxMessages; @@ -719,47 +719,57 @@ public class HashDbManager implements PropertyChangeListener { } /** - * Returns whether or not it is allowable to send inbox messages with this known files type. - * @return Whether or not it is allowable to send inbox messages with this known files type. + * Returns whether or not it is allowable to send inbox messages + * with this known files type. + * + * @return Whether or not it is allowable to send inbox messages + * with this known files type. */ boolean isInboxMessagesAllowed() { return allowSendInboxMessages; } /** - * Returns whether or not by default for this type is to send inbox messages. - * @return Whether or not by default for this type is to send inbox messages. + * Returns whether or not by default for this type is to send inbox + * messages. + * + * @return Whether or not by default for this type is to send inbox + * messages. */ boolean isDefaultInboxMessages() { return defaultSendInboxMessages; } - - + public String getDisplayName() { return this.displayName; } - + /** - * Retrieves the corresponding TskData.FileKnown enum type that relates to this. - * @return The corresponding TskData.FileKnown. + * Retrieves the corresponding TskData.FileKnown enum type that + * relates to this. + * + * @return The corresponding TskData.FileKnown. */ TskData.FileKnown getFileKnown() { return this.fileKnown; } - + /** * Converts a TskData.FileKnown to the corresponding KnownFilesType. - * @param fileKnown The TskData.FileKnown type. - * @return The corresponding KnownFilesType. + * + * @param fileKnown The TskData.FileKnown type. + * + * @return The corresponding KnownFilesType. */ static KnownFilesType fromFileKnown(TskData.FileKnown fileKnown) { - if (fileKnown == null) + if (fileKnown == null) { return null; - + } + return Stream.of(KnownFilesType.values()) - .filter((type) -> type.getFileKnown() == fileKnown) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Unknown TskData.FileKnown type: " + fileKnown)); + .filter((type) -> type.getFileKnown() == fileKnown) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unknown TskData.FileKnown type: " + fileKnown)); } } @@ -770,9 +780,9 @@ public class HashDbManager implements PropertyChangeListener { INDEXING_DONE } - + public abstract String getHashSetName(); - + abstract String getDisplayName(); public abstract String getDatabasePath() throws TskCoreException; @@ -780,7 +790,7 @@ public class HashDbManager implements PropertyChangeListener { public abstract HashDb.KnownFilesType getKnownFilesType(); public abstract boolean getSearchDuringIngest(); - + abstract void setSearchDuringIngest(boolean useForIngest); public abstract boolean getSendIngestMessages(); @@ -813,28 +823,30 @@ public class HashDbManager implements PropertyChangeListener { public abstract boolean lookupMD5Quick(Content content) throws TskCoreException; public abstract HashHitInfo lookupMD5(Content content) throws TskCoreException; - + /** - * Returns whether this database can be enabled. - * For file type, this is the same as checking that it has an index + * Returns whether this database can be enabled. For file type, this is + * the same as checking that it has an index + * * @return true if is valid, false otherwise - * @throws TskCoreException + * + * @throws TskCoreException */ abstract boolean isValid() throws TskCoreException; - + public abstract String getIndexPath() throws TskCoreException; - + public abstract boolean hasIndexOnly() throws TskCoreException; - + public abstract void firePropertyChange(String propertyName, Object oldValue, Object newValue); - + public abstract void addPropertyChangeListener(PropertyChangeListener pcl); - + public abstract void removePropertyChangeListener(PropertyChangeListener pcl); - + @Override public abstract String toString(); - + } /** @@ -842,13 +854,13 @@ public class HashDbManager implements PropertyChangeListener { * as known or know bad. */ class SleuthkitHashSet extends HashDb { - + private static final long serialVersionUID = 1L; private final int handle; private final String hashSetName; private boolean searchDuringIngest; private boolean sendIngestMessages; - private final HashDb.KnownFilesType knownFilesType; + private final HashDb.KnownFilesType knownFilesType; private boolean indexing; private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); @@ -862,8 +874,8 @@ public class HashDbManager implements PropertyChangeListener { } /** - * Adds a listener for the events defined in HashDb.Event. - * Listeners are used during indexing. + * Adds a listener for the events defined in HashDb.Event. Listeners are + * used during indexing. * * @param pcl */ @@ -881,8 +893,8 @@ public class HashDbManager implements PropertyChangeListener { public void removePropertyChangeListener(PropertyChangeListener pcl) { propertyChangeSupport.removePropertyChangeListener(pcl); } - - int getHandle(){ + + int getHandle() { return handle; } @@ -890,9 +902,9 @@ public class HashDbManager implements PropertyChangeListener { public String getHashSetName() { return hashSetName; } - + @Override - String getDisplayName(){ + String getDisplayName() { return getHashSetName(); } @@ -900,9 +912,9 @@ public class HashDbManager implements PropertyChangeListener { public String getDatabasePath() throws TskCoreException { return SleuthkitJNI.getHashDatabasePath(handle); } - - public void setIndexing(boolean indexing){ - this.indexing = indexing; + + public void setIndexing(boolean indexing) { + this.indexing = indexing; } @Override @@ -1038,12 +1050,14 @@ public class HashDbManager implements PropertyChangeListener { } return result; } - + /** - * Returns whether this database can be enabled. - * For file type, this is the same as checking that it has an index + * Returns whether this database can be enabled. For file type, this is + * the same as checking that it has an index + * * @return true if is valid, false otherwise - * @throws TskCoreException + * + * @throws TskCoreException */ @Override boolean isValid() throws TskCoreException { @@ -1066,21 +1080,20 @@ public class HashDbManager implements PropertyChangeListener { boolean isIndexing() { return indexing; } - + @Override - public void firePropertyChange(String propertyName, Object oldValue, Object newValue){ + public void firePropertyChange(String propertyName, Object oldValue, Object newValue) { this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); } private void close() throws TskCoreException { SleuthkitJNI.closeHashDatabase(handle); } - + @Override - public String toString(){ + public String toString() { return getHashSetName(); } - @Override public int hashCode() { @@ -1115,13 +1128,13 @@ public class HashDbManager implements PropertyChangeListener { * Instances of this class represent hash databases used to classify files * as known or know bad. */ - class CentralRepoHashSet extends HashDb{ + class CentralRepoHashSet extends HashDb { private static final long serialVersionUID = 1L; private final String hashSetName; private boolean searchDuringIngest; private boolean sendIngestMessages; - private final HashDb.KnownFilesType knownFilesType; + private final HashDb.KnownFilesType knownFilesType; private final int referenceSetID; private final String version; private String orgName; @@ -1129,10 +1142,10 @@ public class HashDbManager implements PropertyChangeListener { private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); @Messages({"HashDbManager.CentralRepoHashDb.orgError=Error loading organization"}) - private CentralRepoHashSet(String hashSetName, String version, int referenceSetID, - boolean useForIngest, boolean sendHitMessages, HashDb.KnownFilesType knownFilesType, + private CentralRepoHashSet(String hashSetName, String version, int referenceSetID, + boolean useForIngest, boolean sendHitMessages, HashDb.KnownFilesType knownFilesType, boolean readOnly) - throws TskCoreException{ + throws TskCoreException { this.hashSetName = hashSetName; this.version = version; this.referenceSetID = referenceSetID; @@ -1140,18 +1153,18 @@ public class HashDbManager implements PropertyChangeListener { this.sendIngestMessages = sendHitMessages; this.knownFilesType = knownFilesType; this.readOnly = readOnly; - - try{ + + try { orgName = CentralRepository.getInstance().getReferenceSetOrganization(referenceSetID).getName(); - } catch (CentralRepoException ex){ + } catch (CentralRepoException ex) { Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error looking up central repository organization for reference set " + referenceSetID, ex); //NON-NLS orgName = Bundle.HashDbManager_CentralRepoHashDb_orgError(); } } /** - * Adds a listener for the events defined in HashDb.Event. - * Listeners are used during indexing. + * Adds a listener for the events defined in HashDb.Event. Listeners are + * used during indexing. * * @param pcl */ @@ -1169,9 +1182,9 @@ public class HashDbManager implements PropertyChangeListener { public void removePropertyChangeListener(PropertyChangeListener pcl) { propertyChangeSupport.removePropertyChangeListener(pcl); } - + @Override - public boolean hasIndexOnly() throws TskCoreException{ + public boolean hasIndexOnly() throws TskCoreException { return true; } @@ -1179,25 +1192,25 @@ public class HashDbManager implements PropertyChangeListener { public String getHashSetName() { return hashSetName; } - + @Override - public String getDisplayName(){ - if(! getVersion().isEmpty()){ + public String getDisplayName() { + if (!getVersion().isEmpty()) { return getHashSetName() + " " + getVersion() + " (remote)"; } else { return getHashSetName() + " (remote)"; } } - - String getVersion(){ + + String getVersion() { return version; } - - String getOrgName(){ + + String getOrgName() { return orgName; } - - int getReferenceSetID(){ + + int getReferenceSetID() { return referenceSetID; } @@ -1245,7 +1258,7 @@ public class HashDbManager implements PropertyChangeListener { */ @Override public boolean isUpdateable() throws TskCoreException { - return (! readOnly); + return (!readOnly); } /** @@ -1279,12 +1292,12 @@ public class HashDbManager implements PropertyChangeListener { AbstractFile file = (AbstractFile) content; if (null != file.getMd5Hash()) { TskData.FileKnown type = knownFilesType.getFileKnown(); - - try{ + + try { CentralRepoFileInstance fileInstance = new CentralRepoFileInstance(referenceSetID, file.getMd5Hash(), - type, comment); - CentralRepository.getInstance().addReferenceInstance(fileInstance,CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID)); - } catch (CentralRepoException | CorrelationAttributeNormalizationException ex){ + type, comment); + CentralRepository.getInstance().addReferenceInstance(fileInstance, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID)); + } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { throw new TskCoreException("Error adding hashes to " + getDisplayName(), ex); //NON-NLS } } @@ -1301,20 +1314,20 @@ public class HashDbManager implements PropertyChangeListener { @Override public void addHashes(List hashes) throws TskCoreException { Set globalFileInstances = new HashSet<>(); - for(HashEntry hashEntry:hashes){ + for (HashEntry hashEntry : hashes) { TskData.FileKnown type = knownFilesType.getFileKnown(); - + try { globalFileInstances.add(new CentralRepoFileInstance(referenceSetID, hashEntry.getMd5Hash(), type, hashEntry.getComment())); - } catch (CentralRepoException | CorrelationAttributeNormalizationException ex){ + } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { throw new TskCoreException("Error adding hashes to " + getDisplayName(), ex); } } - - try{ - CentralRepository.getInstance().bulkInsertReferenceTypeEntries(globalFileInstances, + + try { + CentralRepository.getInstance().bulkInsertReferenceTypeEntries(globalFileInstances, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID)); - } catch (CentralRepoException ex){ + } catch (CentralRepoException ex) { throw new TskCoreException("Error adding hashes to " + getDisplayName(), ex); } } @@ -1335,9 +1348,9 @@ public class HashDbManager implements PropertyChangeListener { if (content instanceof AbstractFile) { AbstractFile file = (AbstractFile) content; if (null != file.getMd5Hash()) { - try{ + try { return CentralRepository.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID); - } catch (CentralRepoException | CorrelationAttributeNormalizationException ex){ + } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup for hash " + file.getMd5Hash() + " in reference set " + referenceSetID, ex); //NON-NLS throw new TskCoreException("Error performing central reposiotry hash lookup", ex); @@ -1364,12 +1377,12 @@ public class HashDbManager implements PropertyChangeListener { if (content instanceof AbstractFile) { AbstractFile file = (AbstractFile) content; if (null != file.getMd5Hash()) { - try{ - if(CentralRepository.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID)){ + try { + if (CentralRepository.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID)) { // Make a bare-bones HashHitInfo for now result = new HashHitInfo(file.getMd5Hash(), "", ""); } - } catch (CentralRepoException | CorrelationAttributeNormalizationException ex){ + } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup for hash " + file.getMd5Hash() + " in reference set " + referenceSetID, ex); //NON-NLS throw new TskCoreException("Error performing central reposiotry hash lookup", ex); @@ -1378,35 +1391,34 @@ public class HashDbManager implements PropertyChangeListener { } return result; } - + /** * Returns whether this database can be enabled. - * + * * @return true if is valid, false otherwise */ @Override boolean isValid() { - if(! CentralRepository.isEnabled()) { + if (!CentralRepository.isEnabled()) { return false; } - try{ + try { return CentralRepository.getInstance().referenceSetIsValid(this.referenceSetID, this.hashSetName, this.version); - } catch (CentralRepoException ex){ + } catch (CentralRepoException ex) { Logger.getLogger(CentralRepoHashSet.class.getName()).log(Level.SEVERE, "Error validating hash set " + hashSetName, ex); //NON-NLS return false; } } - + @Override - public void firePropertyChange(String propertyName, Object oldValue, Object newValue){ + public void firePropertyChange(String propertyName, Object oldValue, Object newValue) { this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); } - + @Override - public String toString(){ + public String toString() { return getDisplayName(); } - @Override public int hashCode() { @@ -1438,8 +1450,8 @@ public class HashDbManager implements PropertyChangeListener { } return true; } - } - + } + /** * Worker thread to make an index of a database */ diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java index 55959db35c..e804e0bea7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * + * * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -34,7 +34,6 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; - /** * Ingest job settings panel for hash lookup file ingest modules. */ @@ -117,14 +116,14 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe hashSetsTableModel.fireTableDataChanged(); } - private List validSetsOnly(List hashDbs){ + private List validSetsOnly(List hashDbs) { List validDbs = new ArrayList<>(); - for(HashDb db:hashDbs){ - try{ - if(db.isValid()){ + for (HashDb db : hashDbs) { + try { + if (db.isValid()) { validDbs.add(db); } - } catch (TskCoreException ex){ + } catch (TskCoreException ex) { Logger.getLogger(HashLookupModuleSettingsPanel.class.getName()).log(Level.SEVERE, "Error checking validity for hash set (name = " + db.getHashSetName() + ")", ex); //NON-NLS } } @@ -133,22 +132,22 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe void updateHashSetModels() { List hashDbs = validSetsOnly(hashDbManager.getAllHashSets()); - + List hashDatabases = new ArrayList<>(hashDbs); - + // Update the hash sets and detect deletions. List deletedHashSetModels = new ArrayList<>(); for (HashSetModel model : hashSetModels) { boolean foundDatabase = false; - for(HashDb db : hashDatabases){ - if(model.getDatabase().equals(db)){ + for (HashDb db : hashDatabases) { + if (model.getDatabase().equals(db)) { model.setValid(isHashDbValid(db)); hashDatabases.remove(db); foundDatabase = true; break; } } - if(! foundDatabase){ + if (!foundDatabase) { deletedHashSetModels.add(model); } } @@ -191,8 +190,8 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe this.enabled = enabled; this.valid = valid; } - - HashDb getDatabase(){ + + HashDb getDatabase() { return db; } @@ -202,13 +201,14 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe String getFormattedName() { String knownTypeName = (db != null && db.getKnownFilesType() != null) ? db.getKnownFilesType().getDisplayName() : ""; - if (!StringUtils.isBlank(knownTypeName)) + if (!StringUtils.isBlank(knownTypeName)) { knownTypeName = String.format(" (%s)", knownTypeName); - + } + String displayName = db != null ? db.getDisplayName() : ""; return displayName + knownTypeName; } - + void setEnabled(boolean enabled) { this.enabled = enabled; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java index 0f9f99d79b..fade3e47c5 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -49,7 +49,6 @@ import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.SleuthkitHashSet; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashSet; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.SetEvt; @@ -95,16 +94,16 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } } }); - + HashDbManager.getInstance().addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { String propName = evt.getPropertyName(); - if(propName.equals(SetEvt.DB_ADDED.toString()) || - propName.equals(SetEvt.DB_DELETED.toString())) { + if (propName.equals(SetEvt.DB_ADDED.toString()) + || propName.equals(SetEvt.DB_DELETED.toString())) { hashSetTableModel.refreshModel(); } - } + } }); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java index e4b5d55632..85d28231a9 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java @@ -27,7 +27,8 @@ interface HashSetParser { * Get the next hash to import * * @return The hash as a string, or null if the end of file was reached - * without error + * without error + * * @throws TskCoreException */ String getNextHash() throws TskCoreException; @@ -51,18 +52,20 @@ interface HashSetParser { * Closes the import file */ void close(); - + /** * Get the next hash to import as a HashEntry object. - * + * * @return A new hash entry for the next item parsed. - * @throws TskCoreException + * + * @throws TskCoreException */ default HashEntry getNextHashEntry() throws TskCoreException { String next = getNextHash(); - if (next == null) + if (next == null) { return null; - + } + return new HashEntry(null, next, null, null, null); } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java index 030a38cb35..d868b39189 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java @@ -187,7 +187,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P * Get the newly created database * * @return the imported database. May be null if an error occurred or - * the user canceled + * the user canceled */ synchronized HashDbManager.CentralRepoHashSet getDatabase() { return newHashDb; @@ -206,7 +206,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P * Check if the import was successful or if there was an error. * * @return true if the import process completed without error, false - * otherwise + * otherwise */ boolean getImportSuccess() { return importSuccess.get(); @@ -236,7 +236,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P // Create an empty hashset in the central repository CentralRepository dbManager = CentralRepository.getInstance(); - referenceSetID.set(dbManager.newReferenceSet(new CentralRepoFileSet(orgId, hashSetName, version, knownStatus, + referenceSetID.set(dbManager.newReferenceSet(new CentralRepoFileSet(orgId, hashSetName, version, knownStatus, readOnly, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID)))); // Get the "FILES" content type. This is a database lookup so we diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java index 023314bab0..fd79636757 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java @@ -80,8 +80,9 @@ public class KdbHashSetParser implements HashSetParser { } } - + private static class HashRow { + private final String md5Hash; private final long hashId; @@ -98,11 +99,13 @@ public class KdbHashSetParser implements HashSetParser { return hashId; } } - + /** * Retrieves the row id and md5 hash for the next item in the hashes table. + * * @return A hash row object containing the hash and id. - * @throws TskCoreException + * + * @throws TskCoreException */ private HashRow getNextHashRow() throws TskCoreException { try { @@ -117,10 +120,10 @@ public class KdbHashSetParser implements HashSetParser { if (sb.toString().length() != 32) { throw new TskCoreException("Hash has incorrect length: " + sb.toString()); } - + String md5Hash = sb.toString(); totalHashesRead++; - return new HashRow(md5Hash, hashId); + return new HashRow(md5Hash, hashId); } else { throw new TskCoreException("Could not read expected number of hashes from hash set " + filename); } @@ -133,6 +136,7 @@ public class KdbHashSetParser implements HashSetParser { * Get the next hash to import * * @return The hash as a string + * * @throws TskCoreException */ @Override @@ -148,18 +152,16 @@ public class KdbHashSetParser implements HashSetParser { getComment.setLong(1, row.getHashId()); ResultSet commentResults = getComment.executeQuery(); List comments = new ArrayList<>(); - while (commentResults.next()) + while (commentResults.next()) { comments.add(commentResults.getString("comment")); + } String comment = comments.size() > 0 ? String.join(" ", comments) : null; return new HashEntry(null, row.getMd5Hash(), null, null, comment); - } - catch (SQLException ex) { + } catch (SQLException ex) { throw new TskCoreException("Error opening/reading hash set " + filename, ex); } } - - /** * Check if there are more hashes to read From 3b054c9a7b9fea2b4246de8097caf5e8f8a2d462 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 6 May 2020 12:11:16 -0400 Subject: [PATCH 18/81] bug fixes --- .../datamodel/CentralRepository.java | 17 ++++++++ .../datamodel/RdbmsCentralRepo.java | 40 +++++++++++++++++++ .../hashdatabase/Bundle.properties-MERGED | 37 +++++++++++------ .../hashdatabase/HashDbIngestModule.java | 13 +++++- .../modules/hashdatabase/HashDbManager.java | 5 +-- 5 files changed, 93 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java index 6a4a138cfb..945e279123 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java @@ -25,6 +25,7 @@ import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.CentralRepoAccountType; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; +import org.sleuthkit.datamodel.HashHitInfo; /** * Main interface for interacting with the database @@ -541,6 +542,22 @@ public interface CentralRepository { */ public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException; + + /** + * Retrieves the given file HashHitInfo if the given file hash is in this + * reference set. Only searches the reference_files table. + * + * @param hash The hash to find in a search. + * @param referenceSetID The referenceSetID within which the file should exist. + * + * @return The HashHitInfo if found or null if not found. + * + * @throws CentralRepoException + * @throws CorrelationAttributeNormalizationException + */ + public HashHitInfo getFileHashInReferenceSet(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException; + + /** * Check if the given value is in a specific reference set * diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java index 24d02ae2c2..a8b65da9d6 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java @@ -51,6 +51,7 @@ import org.sleuthkit.autopsy.healthmonitor.HealthMonitor; import org.sleuthkit.autopsy.healthmonitor.TimingMetric; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber; +import org.sleuthkit.datamodel.HashHitInfo; import org.sleuthkit.datamodel.TskData; /** @@ -2277,6 +2278,45 @@ abstract class RdbmsCentralRepo implements CentralRepository { return isValueInReferenceSet(hash, referenceSetID, CorrelationAttributeInstance.FILES_TYPE_ID); } + @Override + public HashHitInfo getFileHashInReferenceSet(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException { + int correlationTypeID = CorrelationAttributeInstance.FILES_TYPE_ID; + String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), hash); + + Connection conn = connect(); + + PreparedStatement preparedStatement = null; + ResultSet resultSet = null; + String sql = "SELECT value,comment FROM %s WHERE value=? AND reference_set_id=?"; + + String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID)); + + try { + preparedStatement = conn.prepareStatement(String.format(sql, fileTableName)); + preparedStatement.setString(1, normalizeValued); + preparedStatement.setInt(2, referenceSetID); + resultSet = preparedStatement.executeQuery(); + if (resultSet.next()) { + String comment = resultSet.getString("comment"); + String hashFound = resultSet.getString("value"); + HashHitInfo found = new HashHitInfo(hashFound, "", ""); + found.addComment(comment); + return found; + } + else { + return null; + } + } catch (SQLException ex) { + throw new CentralRepoException("Error determining if value (" + normalizeValued + ") is in reference set " + referenceSetID, ex); // NON-NLS + } finally { + CentralRepoDbUtil.closeStatement(preparedStatement); + CentralRepoDbUtil.closeResultSet(resultSet); + CentralRepoDbUtil.closeConnection(conn); + } + } + + + /** * Check if the given value is in a specific reference set * diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED index 44e551c028..853a23d0db 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED @@ -9,6 +9,7 @@ HashDbImportDatabaseDialog.missingOrg=An organization must be selected HashDbImportDatabaseDialog.missingVersion=A version must be entered HashDbImportDatabaseDialog.mustEnterHashSetNameMsg=A hash set name must be entered. HashDbImportDatabaseDialog.populateOrgsError.message=Failure loading organizations. +HashDbIngestModule.complete.noChangesFound=No Change items found: # {0} - File name HashDbIngestModule.dialogTitle.errorFindingArtifacts=Error Finding Artifacts: {0} # {0} - File name @@ -16,10 +17,21 @@ HashDbIngestModule.errorMessage.lookingForFileArtifacts=Error encountered while HashDbIngestModule.indexError.message=Failed to index hashset hit artifact for keyword search. HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=Notable file search will not be executed. HashDbIngestModule.knownFileSearchWillNotExecuteWarn=Known file search will not be executed. +# {0} - fileName +HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}. +# {0} - fileName +HashDbIngestModule.lookingUpKnownHashValueErr=Error encountered while looking up known hash value for {0}. +# {0} - fileName +HashDbIngestModule.lookingUpNoChangeHashValueErr=Error encountered while looking up no change hash value for {0}. +HashDbIngestModule.noChangeFileSearchWillNotExecuteWarn='No Change' file search will not be executed. +HashDbIngestModule.noChangeHashDbSetMsg=No 'No Change' hash set. HashDbIngestModule.noKnownBadHashDbSetMsg=No notable hash set. HashDbIngestModule.noKnownHashDbSetMsg=No known hash set. HashDbManager.CentralRepoHashDb.orgError=Error loading organization HashDbManager.centralRepoLoadError.message=Error loading central repository hash sets +HashDbManager.known.text=Known +HashDbManager.knownBad.text=Notable +HashDbManager.noChange.text=No Change # {0} - hash set name HashDbManager.noDbPath.message=Couldn't get valid hash set path for: {0} HashDbSearchAction.noOpenCase.errMsg=No open case available. @@ -49,7 +61,10 @@ ImportCentralRepoDbProgressDialog.errorParsingFile.message=Error parsing hash se ImportCentralRepoDbProgressDialog.linesProcessed.message=\ hashes processed ImportCentralRepoDbProgressDialog.title.text=Central Repository Import Progress OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Hash Set ingest module. \n\nThe ingest module analyzes files in the disk image and marks them as "known" (based on NSRL hashset lookup for "known" files) and "bad / interesting" (based on one or more hash sets supplied by the user).\n\nThe module also contains additional non-ingest tools that are integrated in the GUI, such as file lookup by hash and hash set configuration. +OpenIDE-Module-Long-Description=\ + Hash Set ingest module. \n\n\ + The ingest module analyzes files in the disk image and marks them as "known" (based on NSRL hashset lookup for "known" files) and "bad / interesting" (based on one or more hash sets supplied by the user).\n\n\ + The module also contains additional non-ingest tools that are integrated in the GUI, such as file lookup by hash and hash set configuration. OpenIDE-Module-Name=HashDatabases OptionsCategory_Name_HashDatabase=Hash Sets OptionsCategory_Keywords_HashDatabase=Hash Sets @@ -141,8 +156,6 @@ HashDbIngestModule.fileReadErrorMsg=Read Error: {0} HashDbIngestModule.calcHashValueErr=Error encountered while calculating the hash value for {0} ({1}). HashDbIngestModule.hashLookupErrorMsg=Hash Lookup Error: {0} HashDbIngestModule.settingKnownBadStateErr=Error encountered while setting notable state for {0}. -HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}. -HashDbIngestModule.lookingUpKnownHashValueErr=Error encountered while looking up known hash value for {0}. HashDbIngestModule.postToBB.fileName=File Name HashDbIngestModule.postToBB.md5Hash=MD5 Hash HashDbIngestModule.postToBB.hashsetName=Hash Set Name @@ -178,7 +191,10 @@ HashDbSearchThread.name.searching=Searching HashDbSearchThread.noMoreFilesWithMD5Msg=No other files with the same MD5 hash were found. ModalNoButtons.indexingDbsTitle=Indexing hash sets ModalNoButtons.indexingDbTitle=Indexing hash set -ModalNoButtons.exitHashDbIndexingMsg=You are about to exit out of indexing your hash sets. \nThe generated index will be left unusable. If you choose to continue,\nplease delete the corresponding -md5.idx file in the hash folder.\nExit indexing? +ModalNoButtons.exitHashDbIndexingMsg=You are about to exit out of indexing your hash sets. \n\ +The generated index will be left unusable. If you choose to continue,\n\ + please delete the corresponding -md5.idx file in the hash folder.\n\ + Exit indexing? ModalNoButtons.dlgTitle.unfinishedIndexing=Unfinished Indexing ModalNoButtons.indexThis.currentlyIndexing1Db=Currently indexing 1 hash set ModalNoButtons.indexThese.currentlyIndexing1OfNDbs=Currently indexing 1 of {0} @@ -189,9 +205,6 @@ HashDbManager.hashDbFileExistsExceptionMsg=A file already exists at\n{0} HashDbManager.hashDbAlreadyAddedExceptionMsg=The hash set at\n{0}\nhas already been created or imported. HashDbManager.illegalHashDbFileNameExtensionMsg=The hash set file name must have a .{0} extension. HashDbManager.moduleErr=Module Error -HashDbManager.knownBad.text=Notable -HashDbManager.noChange.text=No Change -HashDbManager.known.text=Known HashDbManager.fileNameExtensionFilter.title=Hash Set File HashDbSearchAction.dlgMsg.title=File Search by MD5 Hash HashDbSearchAction.getName.text=Hash Search @@ -206,13 +219,7 @@ AddContentToHashDbAction.singleSelectionNameEmpty=Add File to Hash Set (Empty Fi AddContentToHashDbAction.multipleSelectionNameEmpty=Add Files to Hash Set (Empty File) HashDbManager.ingestRunningExceptionMsg=Ingest is ongoing; this service will be unavailable until it finishes. HashDbManager.saveErrorExceptionMsg=Error saving hash configuration -HashLookupSettingsPanel.jButton3.text=Import Hash Set -HashLookupSettingsPanel.jLabel6.text=Type: -HashLookupSettingsPanel.jLabel4.text=Location: -HashLookupSettingsPanel.jLabel2.text=Name: HashLookupModuleSettingsPanel.alwaysCalcHashesCheckbox.text=Calculate MD5 even if no hash set is selected -HashLookupModuleSettingsPanel.knownHashDbsLabel.text=Select known hash sets to use: -HashLookupModuleSettingsPanel.knownBadHashDbsLabel.text=Select notable hash sets to use: AddContentToHashDbAction.addFilesToHashSet.files=files AddContentToHashDbAction.addFilesToHashSet.file=file HashDbManager.errCreatingIndex.title=Error creating index @@ -290,3 +297,7 @@ AddHashValuesToDatabaseDialog.okButton.text_2=OK HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.text=Copy hash set into user configuration folder HashDbImportDatabaseDialog.saveInUserConfigFolderCheckbox.toolTipText=In Live Triage situations, this option ensures that path to the hash set will be valid HashLookupSettingsPanel.indexPathLabel.text= +HashLookupModuleSettingsPanel.hashDbsLabel.text=Select hash sets to use: +HashDbCreateDatabaseDialog.noChangeRadioButton.text=No Change +HashDbImportDatabaseDialog.noChangeRadioButton.toolTipText= +HashDbImportDatabaseDialog.noChangeRadioButton.text=No Change diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 4752d80186..352a89ab55 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -59,6 +59,8 @@ import org.sleuthkit.datamodel.TskException; @Messages({ "HashDbIngestModule.noKnownBadHashDbSetMsg=No notable hash set.", "HashDbIngestModule.knownBadFileSearchWillNotExecuteWarn=Notable file search will not be executed.", + "HashDbIngestModule.noChangeHashDbSetMsg=No 'No Change' hash set.", + "HashDbIngestModule.noChangeFileSearchWillNotExecuteWarn='No Change' file search will not be executed.", "HashDbIngestModule.noKnownHashDbSetMsg=No known hash set.", "HashDbIngestModule.knownFileSearchWillNotExecuteWarn=Known file search will not be executed.", "# {0} - fileName", "HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}.", @@ -144,6 +146,13 @@ public class HashDbIngestModule implements FileIngestModule { Bundle.HashDbIngestModule_noKnownBadHashDbSetMsg(), Bundle.HashDbIngestModule_knownBadFileSearchWillNotExecuteWarn())); } + + if (noChangeHashSets.isEmpty()) { + services.postMessage(IngestMessage.createWarningMessage( + HashLookupModuleFactory.getModuleName(), + Bundle.HashDbIngestModule_noChangeHashDbSetMsg(), + Bundle.HashDbIngestModule_noChangeFileSearchWillNotExecuteWarn())); + } if (knownHashSets.isEmpty()) { services.postMessage(IngestMessage.createWarningMessage( @@ -209,7 +218,7 @@ public class HashDbIngestModule implements FileIngestModule { IngestJobTotals totals = getTotalsForIngestJobs(jobId); // calc hash value - String md5Hash = GetHash(file, totals); + String md5Hash = getHash(file, totals); if (md5Hash == null) { return ProcessResult.ERROR; } @@ -460,7 +469,7 @@ public class HashDbIngestModule implements FileIngestModule { * @return The found or determined md5 hash or null if none could be * determined. */ - private String GetHash(AbstractFile file, IngestJobTotals totals) { + private String getHash(AbstractFile file, IngestJobTotals totals) { String md5Hash = file.getMd5Hash(); if (md5Hash != null && md5Hash.isEmpty()) { return md5Hash; diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index b9833ecafb..ee48978295 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -1378,10 +1378,7 @@ public class HashDbManager implements PropertyChangeListener { AbstractFile file = (AbstractFile) content; if (null != file.getMd5Hash()) { try { - if (CentralRepository.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID)) { - // Make a bare-bones HashHitInfo for now - result = new HashHitInfo(file.getMd5Hash(), "", ""); - } + return CentralRepository.getInstance().getFileHashInReferenceSet(file.getMd5Hash(), referenceSetID); } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup for hash " + file.getMd5Hash() + " in reference set " + referenceSetID, ex); //NON-NLS From 984507f2ecc2eed4af50e4d92401d513ff5a3507 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 6 May 2020 14:27:48 -0400 Subject: [PATCH 19/81] annotations viewer update for tsk hash hit --- .../AnnotationsContentViewer.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index c5c92b11c0..22a8bfe08b 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -22,11 +22,13 @@ import java.awt.Component; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; +import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringEscapeUtils; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.openide.nodes.Node; +import org.openide.util.Exceptions; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -46,6 +48,8 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; /** * Annotations view of file contents. @@ -109,12 +113,86 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data if (sourceFile instanceof AbstractFile) { populateCentralRepositoryData(html, artifact, (AbstractFile) sourceFile); + populateHashHitData(html, sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT); + populateHashHitData(html, sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); } setText(html.toString()); jTextPane1.setCaretPosition(0); } + private void populateHashHitData(StringBuilder html, Content content, BlackboardArtifact.ARTIFACT_TYPE artifactType) { + String artifactTypeName = artifactType.getDisplayName(); + + try { + SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + + startSection(html, artifactTypeName); + List fileHitInfo = tskCase.getBlackboardArtifacts(artifactType, content.getId()); + if (fileHitInfo.isEmpty()) { + addMessage(html, String.format("There are no %s for the selected content.", artifactTypeName)); + } else { + for (BlackboardArtifact fileHit : fileHitInfo) { + addFileHitEntry(html, fileHit); + } + } + endSection(html); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Exception while getting tags from the case database.", ex); //NON-NLS + } + } + + + private String tryGetAttribute(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE attributeType) { + if (artifact == null) { + return null; + } + + BlackboardAttribute attr = null; + try { + attr = artifact.getAttribute(new BlackboardAttribute.Type(attributeType)); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, String.format("Unable to fetch attribute of type %s for artifact %s", attributeType, artifact), ex); + } + + if (attr == null) { + return null; + } + + return attr.getValueString(); + } + + /** + * Add a data table containing information about an file hit artifact (i.e. + * hash hit). + * + * @param html The HTML text to add the table to. + * @param tag The blackboard artifact with hash hit information whose + * information will be used to populate the table. + */ + @NbBundle.Messages({ + "AnnotationsContentViewer.addHashHitEntry.hashSet=Hash Set:", + "AnnotationsContentViewer.addHashHitEntry.comment=Comment:" + }) + private void addFileHitEntry(StringBuilder html, BlackboardArtifact artifact) { + startTable(html); + + String hashset = tryGetAttribute(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME); + String comment = tryGetAttribute(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT); + + if (StringUtils.isNotBlank(hashset)) { + addRow(html, Bundle.AnnotationsContentViewer_addHashHitEntry_hashSet(), hashset); + } + + if (StringUtils.isNotBlank(comment)) { + addRow(html, Bundle.AnnotationsContentViewer_tagEntryDataLabel_comment(), comment); + } + + endTable(html); + } + /** * Populate the "Selected Item" sections with tag data for the supplied * content. From 3660c08f805e2df2cbd370e0fa9210615ee10a40 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 6 May 2020 14:38:46 -0400 Subject: [PATCH 20/81] Inital changes --- .../autopsy/casemodule/services/TagNameDefinition.java | 10 +++++----- .../autopsy/casemodule/services/TagsManager.java | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java index 2e70d407a0..41aa3d0cab 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java @@ -57,11 +57,11 @@ final class TagNameDefinition implements Comparable { private static final String TAG_SETTING_VERSION_KEY = "CustomTagNameVersion"; private static final int TAG_SETTINGS_VERSION = 1; - private static final String CATEGORY_ONE_NAME = "CAT-1: Child Exploitation (Illegal)"; - private static final String CATEGORY_TWO_NAME = "CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"; - private static final String CATEGORY_THREE_NAME = "CAT-3: CGI/Animation (Child Exploitive)"; - private static final String CATEGORY_FOUR_NAME = "CAT-4: Exemplar/Comparison (Internal Use Only)"; - private static final String CATEGORY_FIVE_NAME = "CAT-5: Non-pertinent"; + private static final String CATEGORY_ONE_NAME = "Child Exploitation (Illegal)"; + private static final String CATEGORY_TWO_NAME = "Child Exploitation (Non-Illegal/Age Difficult)"; + private static final String CATEGORY_THREE_NAME = "CGI/Animation (Child Exploitive)"; + private static final String CATEGORY_FOUR_NAME = "Exemplar/Comparison (Internal Use Only)"; + private static final String CATEGORY_FIVE_NAME = "Non-pertinent"; private final String displayName; private final String description; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 5bdb2dc64e..5797cd9783 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -55,7 +55,7 @@ public class TagsManager implements Closeable { private static final Logger LOGGER = Logger.getLogger(TagsManager.class.getName()); private final SleuthkitCase caseDb; - static String DEFAULT_TAG_SET_NAME = "Project VIC (United States)"; + static String DEFAULT_TAG_SET_NAME = "Project VIC"; static { From 23782a90ccd4e5b8fbc001e09ea48f4cc803ef34 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 6 May 2020 15:16:15 -0400 Subject: [PATCH 21/81] updates for comments and formatting --- .../AnnotationsContentViewer.java | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index 22a8bfe08b..c87178bade 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -28,7 +28,6 @@ import org.apache.commons.lang3.StringEscapeUtils; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.openide.nodes.Node; -import org.openide.util.Exceptions; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -49,7 +48,6 @@ import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; /** * Annotations view of file contents. @@ -113,17 +111,25 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data if (sourceFile instanceof AbstractFile) { populateCentralRepositoryData(html, artifact, (AbstractFile) sourceFile); - populateHashHitData(html, sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT); - populateHashHitData(html, sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); + populateFileSetData(html, sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT); + populateFileSetData(html, sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); } setText(html.toString()); jTextPane1.setCaretPosition(0); } - private void populateHashHitData(StringBuilder html, Content content, BlackboardArtifact.ARTIFACT_TYPE artifactType) { + /** + * Populates the html provided with data concerning the source file and + * whether it appears in a file set. + * + * @param html The html to append information. + * @param content The source content to check for blackboard artifacts. + * @param artifactType The artifact type to check for. + */ + private void populateFileSetData(StringBuilder html, Content content, BlackboardArtifact.ARTIFACT_TYPE artifactType) { String artifactTypeName = artifactType.getDisplayName(); - + try { SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); @@ -132,9 +138,9 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data if (fileHitInfo.isEmpty()) { addMessage(html, String.format("There are no %s for the selected content.", artifactTypeName)); } else { - for (BlackboardArtifact fileHit : fileHitInfo) { + fileHitInfo.forEach((fileHit) -> { addFileHitEntry(html, fileHit); - } + }); } endSection(html); } catch (NoCurrentCaseException ex) { @@ -144,7 +150,15 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data } } - + /** + * Attempts to retrieve the attribute of a particular type from a blackboard + * artifact. + * + * @param artifact The artifact from which to retrieve the information. + * @param attributeType The attribute type to retrieve from the artifact. + * + * @return The string value of the attribute or null if not found. + */ private String tryGetAttribute(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE attributeType) { if (artifact == null) { return null; @@ -165,8 +179,8 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data } /** - * Add a data table containing information about an file hit artifact (i.e. - * hash hit). + * Add a data table containing information about an file set hit artifact + * (i.e. hash hit). * * @param html The HTML text to add the table to. * @param tag The blackboard artifact with hash hit information whose From 4e83fdfc60fc997567b6d25e28b8986a0e29c390 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 6 May 2020 15:59:34 -0400 Subject: [PATCH 22/81] method rename --- .../autopsy/centralrepository/datamodel/CentralRepository.java | 2 +- .../autopsy/centralrepository/datamodel/RdbmsCentralRepo.java | 2 +- .../sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java index 945e279123..abeb2bd067 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java @@ -555,7 +555,7 @@ public interface CentralRepository { * @throws CentralRepoException * @throws CorrelationAttributeNormalizationException */ - public HashHitInfo getFileHashInReferenceSet(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException; + public HashHitInfo lookupHash(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException; /** diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java index a8b65da9d6..0a245f9057 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java @@ -2279,7 +2279,7 @@ abstract class RdbmsCentralRepo implements CentralRepository { } @Override - public HashHitInfo getFileHashInReferenceSet(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException { + public HashHitInfo lookupHash(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException { int correlationTypeID = CorrelationAttributeInstance.FILES_TYPE_ID; String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), hash); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index ee48978295..495e9f6705 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -1378,7 +1378,7 @@ public class HashDbManager implements PropertyChangeListener { AbstractFile file = (AbstractFile) content; if (null != file.getMd5Hash()) { try { - return CentralRepository.getInstance().getFileHashInReferenceSet(file.getMd5Hash(), referenceSetID); + return CentralRepository.getInstance().lookupHash(file.getMd5Hash(), referenceSetID); } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup for hash " + file.getMd5Hash() + " in reference set " + referenceSetID, ex); //NON-NLS From eaa58efc48b7027c89e8ba6b7ee81eb21f11d6c4 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 7 May 2020 07:54:23 -0400 Subject: [PATCH 23/81] bug fix --- .../autopsy/modules/hashdatabase/HashDbIngestModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 352a89ab55..9f03c0ab78 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -237,7 +237,7 @@ public class HashDbIngestModule implements FileIngestModule { // look up no change items next FindInHashsetsResult noChangeResult = findInHashsets(file, totals.totalNoChangeCount, - totals.totalLookuptime, noChangeHashSets, TskData.FileKnown.BAD, noChangeLookupError); + totals.totalLookuptime, noChangeHashSets, TskData.FileKnown.UNKNOWN, noChangeLookupError); if (noChangeResult.isError()) { ret = ProcessResult.ERROR; From b25b3a4b3b28efc84bddd0b91c05937f759589c6 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 7 May 2020 12:31:36 -0400 Subject: [PATCH 24/81] address codacy remarks --- .../datamodel/CentralRepository.java | 2 +- .../hashdatabase/HashDbIngestModule.java | 4 +- .../modules/hashdatabase/HashDbManager.java | 2 +- .../hashdatabase/KdbHashSetParser.java | 69 ++++--------------- 4 files changed, 18 insertions(+), 59 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java index b3d8437a7c..a4ce71cb36 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java @@ -567,7 +567,7 @@ public interface CentralRepository { * @throws CentralRepoException * @throws CorrelationAttributeNormalizationException */ - public HashHitInfo lookupHash(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException; + HashHitInfo lookupHash(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException; /** diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 9f03c0ab78..3533fb34d8 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -612,7 +612,7 @@ public class HashDbIngestModule implements FileIngestModule { detailsSb.append("
"); //NON-NLS - detailsSb.append(""); //NON-NLS + detailsSb.append(""); //NON-NLS detailsSb.append(""); //NON-NLS - detailsSb.append(""); //NON-NLS - - detailsSb.append(""); //NON-NLS - detailsSb.append(""); //NON-NLS - - detailsSb.append("\n"); //NON-NLS - detailsSb.append("\n"); //NON-NLS - detailsSb.append("
").append(jobTotals.totalKnownBadCount.get()).append("
") //NON-NLS + .append(Bundle.HashDbIngestModule_complete_noChangesFound()) + .append("").append(jobTotals.totalNoChangeCount.get()).append("
") //NON-NLS .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.totalCalcTime")) .append("").append(jobTotals.totalCalctime.get()).append("
").append(jobTotals.totalNoChangeCount.get()).append("
") //NON-NLS .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.totalCalcTime")) .append("").append(jobTotals.totalCalctime.get()).append("
") //NON-NLS .append(Bundle.HashDbIngestModule_complete_noChangesFound()) .append("").append(jobTotals.totalNoChangeCount.get()).append("
" + jobTotals.totalNoChangeCount.get() + "
") //NON-NLS .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.totalCalcTime")) @@ -626,7 +626,7 @@ public class HashDbIngestModule implements FileIngestModule { .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.databasesUsed")) .append("

\n
    "); //NON-NLS Stream.concat(knownBadHashSets.stream(), noChangeHashSets.stream()).forEach((db) -> { - detailsSb.append("
  • ").append(db.getHashSetName()).append("
  • \n"); //NON-NLS + detailsSb.append("
  • " + db.getHashSetName() + "
  • \n"); //NON-NLS }); detailsSb.append("
"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index 495e9f6705..7559649689 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -711,7 +711,7 @@ public class HashDbManager implements PropertyChangeListener { private final boolean allowSendInboxMessages; private final boolean defaultSendInboxMessages; - private KnownFilesType(String displayName, TskData.FileKnown fileKnown, boolean allowSendInboxMessages, boolean defaultSendInboxMessages) { + KnownFilesType(String displayName, TskData.FileKnown fileKnown, boolean allowSendInboxMessages, boolean defaultSendInboxMessages) { this.displayName = displayName; this.fileKnown = fileKnown; this.allowSendInboxMessages = allowSendInboxMessages; diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java index fd79636757..4045abcda7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java @@ -72,7 +72,9 @@ public class KdbHashSetParser implements HashSetParser { } // Get the hashes - resultSet = statement.executeQuery("SELECT id, md5 FROM hashes"); + resultSet = statement.executeQuery("SELECT h.md5 as md5, " + + " (SELECT group_concat(c.comment, ' ') FROM comments c WHERE h.id = c.hash_id) as comment " + + " from hashes h"); // At this point, getNextHash can read each hash from the result set } catch (ClassNotFoundException | SQLException ex) { @@ -81,36 +83,23 @@ public class KdbHashSetParser implements HashSetParser { } - private static class HashRow { - - private final String md5Hash; - private final long hashId; - - HashRow(String md5Hash, long hashId) { - this.md5Hash = md5Hash; - this.hashId = hashId; - } - - String getMd5Hash() { - return md5Hash; - } - - long getHashId() { - return hashId; - } - } /** - * Retrieves the row id and md5 hash for the next item in the hashes table. + * Get the next hash to import * - * @return A hash row object containing the hash and id. + * @return The hash as a string * * @throws TskCoreException */ - private HashRow getNextHashRow() throws TskCoreException { + @Override + public String getNextHash() throws TskCoreException { + return getNextHashEntry().getMd5Hash(); + } + + @Override + public HashEntry getNextHashEntry() throws TskCoreException { try { if (resultSet.next()) { - long hashId = resultSet.getLong("id"); byte[] hashBytes = resultSet.getBytes("md5"); StringBuilder sb = new StringBuilder(); for (byte b : hashBytes) { @@ -122,42 +111,12 @@ public class KdbHashSetParser implements HashSetParser { } String md5Hash = sb.toString(); + String comment = resultSet.getString("comment"); totalHashesRead++; - return new HashRow(md5Hash, hashId); + return new HashEntry(null, md5Hash, null, null, comment); } else { throw new TskCoreException("Could not read expected number of hashes from hash set " + filename); } - } catch (SQLException ex) { - throw new TskCoreException("Error reading hash from result set for hash set " + filename, ex); - } - } - - /** - * Get the next hash to import - * - * @return The hash as a string - * - * @throws TskCoreException - */ - @Override - public String getNextHash() throws TskCoreException { - return getNextHashRow().getMd5Hash(); - } - - @Override - public HashEntry getNextHashEntry() throws TskCoreException { - HashRow row = getNextHashRow(); - try { - PreparedStatement getComment = conn.prepareStatement("SELECT comment FROM comments WHERE hash_id = ?"); - getComment.setLong(1, row.getHashId()); - ResultSet commentResults = getComment.executeQuery(); - List comments = new ArrayList<>(); - while (commentResults.next()) { - comments.add(commentResults.getString("comment")); - } - - String comment = comments.size() > 0 ? String.join(" ", comments) : null; - return new HashEntry(null, row.getMd5Hash(), null, null, comment); } catch (SQLException ex) { throw new TskCoreException("Error opening/reading hash set " + filename, ex); } From f04398567e6fcefe5ab02d81c0c779fc1462a1f5 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 7 May 2020 12:46:15 -0400 Subject: [PATCH 25/81] more codacy items --- .../autopsy/core/Bundle.properties-MERGED | 8 +++- .../corecomponents/Bundle.properties-MERGED | 12 +++--- .../coreutils/Bundle.properties-MERGED | 4 +- .../directorytree/Bundle.properties-MERGED | 6 +-- .../filesearch/Bundle.properties-MERGED | 10 ++--- .../autopsy/ingest/Bundle.properties-MERGED | 2 +- .../livetriage/Bundle.properties-MERGED | 4 +- .../Bundle.properties-MERGED | 4 +- .../Bundle.properties-MERGED | 8 +++- .../modules/exif/Bundle.properties-MERGED | 4 +- .../fileextmismatch/Bundle.properties-MERGED | 18 ++++----- .../filetypeid/Bundle.properties-MERGED | 6 +-- .../hashdatabase/HashDbIngestModule.java | 37 ++++++++----------- .../hashdatabase/KdbHashSetParser.java | 3 -- .../interestingitems/Bundle.properties-MERGED | 18 ++++----- .../photoreccarver/Bundle.properties-MERGED | 2 +- .../modules/html/Bundle.properties-MERGED | 6 +-- .../ui/Bundle.properties-MERGED | 1 + .../autoingest/Bundle.properties-MERGED | 12 ++++++ .../configuration/Bundle.properties-MERGED | 1 + .../keywordsearch/Bundle.properties-MERGED | 20 +++++----- .../recentactivity/Bundle.properties-MERGED | 8 +++- .../netbeans/core/startup/Bundle.properties | 4 +- .../core/windows/view/ui/Bundle.properties | 6 +-- 24 files changed, 114 insertions(+), 90 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED index c84f1f1b86..0b16a9701f 100755 --- a/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED @@ -3,7 +3,13 @@ Installer.closing.confirmationDialog.title=Ingest is Running # {0} - exception message Installer.closing.messageBox.caseCloseExceptionMessage=Error closing case: {0} OpenIDE-Module-Display-Category=Infrastructure -OpenIDE-Module-Long-Description=This is the core Autopsy module.\n\nThe module contains the core components needed for the bare application to run; the RCP platform, windowing GUI, sleuthkit bindings, datamodel / storage, explorer, result viewers, content viewers, ingest framework, reporting, and core tools, such as the file search.\n\nThe framework included in the module contains APIs for developing modules for ingest, viewers and reporting. The modules can be deployed as Plugins using the Autopsy plugin installer.\nThis module should not be uninstalled - without it, Autopsy will not run.\n\nFor more information, see http://www.sleuthkit.org/autopsy/ +OpenIDE-Module-Long-Description=\ + This is the core Autopsy module.\n\n\ + The module contains the core components needed for the bare application to run; the RCP platform, windowing GUI, sleuthkit bindings, datamodel / storage, explorer, result viewers, content viewers, ingest framework, reporting, and core tools, such as the file search.\n\n\ + The framework included in the module contains APIs for developing modules for ingest, viewers and reporting. \ + The modules can be deployed as Plugins using the Autopsy plugin installer.\n\ + This module should not be uninstalled - without it, Autopsy will not run.\n\n\ + For more information, see http://www.sleuthkit.org/autopsy/ OpenIDE-Module-Name=Autopsy-Core OpenIDE-Module-Short-Description=Autopsy Core Module org_sleuthkit_autopsy_core_update_center=http://sleuthkit.org/autopsy/updates.xml diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED index f252420726..544cfa63c0 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED @@ -63,9 +63,9 @@ DataContentViewerHex.totalPageLabel.text_1=100 DataContentViewerHex.pageLabel2.text=Page # Product Information panel -LBL_Description=
\n Product Version: {0} ({9})
Sleuth Kit Version: {7}
Netbeans RCP Build: {8}
Java: {1}; {2}
System: {3}; {4}; {5}
Userdir: {6}
+LBL_Description=
\n Product Version: {0} ({9})
Sleuth Kit Version: {7}
Netbeans RCP Build: {8}
Java: {1}; {2}
System: {3}; {4}; {5}
Userdir: {6}
Format_OperatingSystem_Value={0} version {1} running on {2} -LBL_Copyright=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2018.
+LBL_Copyright=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2018.
SortChooser.dialogTitle=Choose Sort Criteria ThumbnailViewChildren.progress.cancelling=(Cancelling) # {0} - file name @@ -95,7 +95,7 @@ DataResultViewerThumbnail.pageNextButton.text= DataResultViewerThumbnail.imagesLabel.text=Images: DataResultViewerThumbnail.imagesRangeLabel.text=- DataResultViewerThumbnail.pageNumLabel.text=- -DataResultViewerThumbnail.filePathLabel.text=\ +DataResultViewerThumbnail.filePathLabel.text=\ \ \ DataResultViewerThumbnail.goToPageLabel.text=Go to Page: DataResultViewerThumbnail.goToPageField.text= AdvancedConfigurationDialog.cancelButton.text=Cancel @@ -129,9 +129,9 @@ DataResultViewerThumbnail.switchPage.done.errMsg=Error making thumbnails: {0} AboutWindowPanel.actVerboseLogging.text=Activate verbose logging OptionsCategory_Name_Multi_User_Settings=Multi-User OptionsCategory_Keywords_Multi_User_Options=Multi-User Settings -MultiUserSettingsPanel.lbSolrSettings.text=Solr Settings +MultiUserSettingsPanel.lbSolrSettings.text=Solr Server Settings MultiUserSettingsPanel.cbEnableMultiUser.text=Enable multi-user cases -MultiUserSettingsPanel.lbDatabaseSettings.text=Database Settings +MultiUserSettingsPanel.lbDatabaseSettings.text=Database Server Settings MultiUserSettingsPanel.validationErrMsg.incomplete=Fill in all values MultiUserSettingsPanel.nonWindowsOs.msg=Multi-user cases are only available on Windows platforms MultiUserSettingsPanel.validationErrMsg.invalidDatabasePort=Invalid database port number @@ -159,7 +159,7 @@ MultiUserSettingsPanel.tbSolrHostname.toolTipText=Hostname or IP Address MultiUserSettingsPanel.tbSolrPort.toolTipText=Port Number MultiUserSettingsPanel.lbTestMessageService.text= MultiUserSettingsPanel.bnTestMessageService.text=Test -MultiUserSettingsPanel.lbMessageServiceSettings.text=ActiveMQ Message Service Settings +MultiUserSettingsPanel.lbMessageServiceSettings.text=ActiveMQ Message Server Settings MultiUserSettingsPanel.tbMsgPort.toolTipText=Port Number MultiUserSettingsPanel.tbMsgPort.text= MultiUserSettingsPanel.tbMsgUsername.toolTipText=User Name (optional) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED index 18e279dd2c..a0d535f8e6 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED @@ -30,7 +30,9 @@ PlatformUtil.getProcVmUsed.sigarNotInit.msg=Cannot get virt mem used, sigar not PlatformUtil.getProcVmUsed.gen.msg=Cannot get virt mem used, {0} PlatformUtil.getJvmMemInfo.usageText=JVM heap usage: {0}, JVM non-heap usage: {1} PlatformUtil.getPhysicalMemInfo.usageText=Physical memory usage (max, total, free): {0}, {1}, {2} -PlatformUtil.getAllMemUsageInfo.usageText={0}\n{1}\nProcess Virtual Memory: {2} +PlatformUtil.getAllMemUsageInfo.usageText={0}\n\ +{1}\n\ +Process Virtual Memory: {2} # {0} - file name ReadImageTask.mesageText=Reading image: {0} StringExtract.illegalStateException.cannotInit.msg=Unicode table not properly initialized, cannot instantiate StringExtract diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED index 63b416b176..7e96d8fdaa 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED @@ -38,8 +38,6 @@ HINT_DirectoryTreeTopComponent=This is a DirectoryTree window OpenIDE-Module-Name=DirectoryTree FileSystemDetailsPanel.imgOffsetLabel.text=Image Offset: FileSystemDetailsPanel.fsTypeLabel.text=FileSystem Type: -FileSystemDetailsPanel.jLabel2.text=bytes -FileSystemDetailsPanel.jLabel3.text=bytes FileSystemDetailsPanel.fsTypeValue.text=... FileSystemDetailsPanel.imgOffsetValue.text=... FileSystemDetailsPanel.volumeIDValue.text=... @@ -71,7 +69,6 @@ VolumeDetailsPanel.startLabel.text=Starting Sector: VolumeDetailsPanel.lengthLabel.text=Length in Sectors: VolumeDetailsPanel.descLabel.text=Description: VolumeDetailsPanel.flagsLabel.text=Flags: -VolumeDetailsPanel.jLabel1.text=General Volume Information VolumeDetailsPanel.OKButton.text=OK ImageDetailsPanel.imageInfoLabel.text=Image Information ImageDetailsPanel.imgNameLabel.text=Name: @@ -160,3 +157,6 @@ ExternalViewerGlobalSettingsPanel.jButton2.text=jButton2 ExternalViewerGlobalSettingsPanel.browseHxDDirectory.text=Browse ExternalViewerGlobalSettingsPanel.HxDLabel.text=HxD Editor Path: ExternalViewerGlobalSettingsPanel.ContentViewerExtensionLabel.text=Add content viewer extensions: +FileSystemDetailsPanel.bytesLabel1.text=bytes +FileSystemDetailsPanel.bytesLabel2.text=bytes +VolumeDetailsPanel.generalVolumeLabel.text=General Volume Information diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED index c585d0edf5..b304bc1342 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED @@ -14,11 +14,9 @@ KnownStatusSearchPanel.knownCheckBox.text=Known Status: KnownStatusSearchPanel.knownBadOptionCheckBox.text=Notable KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL or other) KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown -DateSearchFilter.noneSelectedMsg.text=At least one date type must be selected! +DateSearchFilter.noneSelectedMsg.text=At least one date type must be selected\! DateSearchPanel.dateCheckBox.text=Date: DateSearchPanel.jLabel4.text=Timezone: -DateSearchPanel.jLabel3.text=*The date format is mm/dd/yyyy -DateSearchPanel.jLabel2.text=*Empty fields mean "No Limit" DateSearchPanel.createdCheckBox.text=Created DateSearchPanel.accessedCheckBox.text=Accessed DateSearchPanel.changedCheckBox.text=Changed @@ -57,12 +55,11 @@ FileSearchPanel.search.results.details=Large number of matches may impact perfor FileSearchPanel.search.exception.noFilterSelected.msg=At least one filter must be selected. FileSearchPanel.search.validationErr.msg=Validation Error: {0} FileSearchPanel.emptyWhereClause.text=Invalid options, nothing to show. -KnownStatusSearchFilter.noneSelectedMsg.text=At least one known status must be selected! +KnownStatusSearchFilter.noneSelectedMsg.text=At least one known status must be selected\! NameSearchFilter.emptyNameMsg.text=Must enter something for name search. SizeSearchPanel.sizeCompareComboBox.equalTo=equal to SizeSearchPanel.sizeCompareComboBox.greaterThan=greater than SizeSearchPanel.sizeCompareComboBox.lessThan=less than -MimeTypePanel.jLabel1.text=*Note: Multiple MIME types can be selected FileSearchPanel.searchButton.text=Search MimeTypePanel.mimeTypeCheckBox.text=MIME Type: HashSearchPanel.md5CheckBox.text=MD5: @@ -72,3 +69,6 @@ DataSourcePanel.dataSourceCheckBox.label=Data Source: DataSourcePanel.dataSourceCheckBox.actionCommand=Data Source: DataSourcePanel.dataSourceCheckBox.text=Data Source: DataSourcePanel.dataSourceNoteLabel.text=*Note: Multiple data sources can be selected +DateSearchPanel.noLimitLabel.text=*Empty fields mean "No Limit" +DateSearchPanel.dateFormatLabel.text=*The date format is mm/dd/yyyy +MimeTypePanel.noteLabel.text=*Note: Multiple MIME types can be selected diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED index 6be3e48e71..9e4f612b6b 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED @@ -140,7 +140,7 @@ IngestJob.cancelReason.outOfDiskSpace.text=Out of disk space IngestJob.cancelReason.servicesDown.text=Services Down IngestJob.cancelReason.caseClosed.text=Case closed IngestJobSettingsPanel.globalSettingsButton.text=Global Settings -gest= +gest IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced IngestJobSettingsPanel.globalSettingsButton.text=Global Settings IngestJobSettingsPanel.pastJobsButton.text=History diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties-MERGED index e0a2ab0413..309a07d3da 100755 --- a/Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties-MERGED @@ -18,10 +18,10 @@ SelectDriveDialog.diskTable.column2.title=Disk Size SelectDriveDialog.errLabel.disksNotDetected.text=Disks were not detected. On some systems it requires admin privileges SelectDriveDialog.errLabel.disksNotDetected.toolTipText=Disks were not detected. SelectDriveDialog.lbSelectDrive.text=Select the drive to copy the application and script to: -SelectDriveDialog.jLabel1.text=Select drive to use for live triage (may take time to load): SelectDriveDialog.errorLabel.text=jLabel2 SelectDriveDialog.bnCancel.text=Cancel -SelectDriveDialog.jTextArea1.text=This feature copies the application and a batch file to a removable drive,\nallowing systems to be analyzed without installing the software or\nimaging the drives.\n\nTo analyze a system, insert the drive and run "RunFromUSB.bat" as\nadministrator, then select the "Local Disk" option on the Add Data Source\npanel. +SelectDriveDialog.descriptionTextArea.text=This feature copies the application and a batch file to a removable drive,\nallowing systems to be analyzed without installing the software or\nimaging the drives.\n\nTo analyze a system, insert the drive and run "RunFromUSB.bat" as\nadministrator, then select the "Local Disk" option on the Add Data Source\npanel. SelectDriveDialog.localDiskModel.loading.msg= SelectDriveDialog.localDiskModel.nodrives.msg=Executable could not be found +SelectDriveDialog.selectDriveLabel.text=Select drive to use for live triage (may take time to load): SelectDriveDialog.title=Create Live Triage Drive diff --git a/Core/src/org/sleuthkit/autopsy/modules/dataSourceIntegrity/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/dataSourceIntegrity/Bundle.properties-MERGED index b006deb22d..e69126f939 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/dataSourceIntegrity/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/dataSourceIntegrity/Bundle.properties-MERGED @@ -45,6 +45,6 @@ DataSourceIntegrityIngestModule.shutDown.resultLi=
  • Result:{0}
  • DataSourceIntegrityIngestModule.shutDown.calcHashLi=
  • Calculated hash: {0}
  • DataSourceIntegrityIngestModule.shutDown.storedHashLi=
  • Stored hash: {0}
  • DataSourceIntegrityIngestSettingsPanel.computeHashesCheckbox.text=Calculate data source hashes if none are present -DataSourceIntegrityIngestSettingsPanel.jLabel1.text=Note that this module will not run on logical files -DataSourceIntegrityIngestSettingsPanel.jLabel3.text=Ingest Settings DataSourceIntegrityIngestSettingsPanel.verifyHashesCheckbox.text=Verify existing data source hashes +DataSourceIntegrityIngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings +DataSourceIntegrityIngestSettingsPanel.noteLabel.text=Note that this module will not run on logical files diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED index 4729293fb9..4585d86449 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED @@ -11,7 +11,12 @@ ExtractArchiveWithPasswordAction.progress.text=Unpacking contents of archive: {0 ExtractArchiveWithPasswordAction.prompt.text=Enter Password ExtractArchiveWithPasswordAction.prompt.title=Enter Password OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Embedded File Extraction Ingest Module\n\nThe Embedded File Extraction Ingest Module processes document files (such as doc, docx, ppt, pptx, xls, xlsx) and archive files (such as zip and others archive types supported by the 7zip extractor).\nContents of these files are extracted and the derived files are added back to the current ingest to be processed by the configured ingest modules.\nIf the derived file happens to be an archive file, it will be re-processed by the 7zip extractor - the extractor will process archive files N-levels deep.\n\nThe extracted files are navigable in the directory tree.\n\nThe module is supported on Windows, Linux and Mac operating systems. +OpenIDE-Module-Long-Description=\ + Embedded File Extraction Ingest Module\n\nThe Embedded File Extraction Ingest Module processes document files (such as doc, docx, ppt, pptx, xls, xlsx) and archive files (such as zip and others archive types supported by the 7zip extractor).\n\ + Contents of these files are extracted and the derived files are added back to the current ingest to be processed by the configured ingest modules.\n\ + If the derived file happens to be an archive file, it will be re-processed by the 7zip extractor - the extractor will process archive files N-levels deep.\n\n\ + The extracted files are navigable in the directory tree.\n\n\ + The module is supported on Windows, Linux and Mac operating systems. OpenIDE-Module-Name=Embedded File Extraction OpenIDE-Module-Short-Description=Embedded File Extraction Ingest Module EmbeddedFileExtractorIngestModule.SevenZipContentReadStream.seek.exception.invalidOrigin=Invalid seek origin: {0} @@ -23,7 +28,6 @@ EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg=Possib EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnDetails=Compression ratio is {0}, skipping items in {1}. EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnMsg.zipBomb=Possible ZIP bomb detected: {0} EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnDetails.zipBomb=The archive is {0} levels deep, skipping processing of {1} -EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.unknownPath.msg=Unknown item path in archive: {0}, will use: {1} EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.msg=Not enough disk space to unpack archive item: {0}, {1} EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.details=The archive item is too large to unpack, skipping unpacking this item. EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.msg=Error unpacking {0} diff --git a/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED index 4915d5a124..f9a5a88b1b 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED @@ -2,7 +2,9 @@ CannotRunFileTypeDetection=Cannot run file type detection. ExifParserFileIngestModule.indexError.message=Failed to post EXIF Metadata artifact(s). ExifParserFileIngestModule.userContent.description=EXIF metadata exists for this file. OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Exif metadata ingest module. \n\nThe ingest module analyzes image files, extracts Exif information and posts the Exif data as results. +OpenIDE-Module-Long-Description=\ + Exif metadata ingest module. \n\n\ + The ingest module analyzes image files, extracts Exif information and posts the Exif data as results. OpenIDE-Module-Name=ExifParser OpenIDE-Module-Short-Description=Exif metadata ingest module ExifParserFileIngestModule.moduleName.text=Exif Parser diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED index 5063bd55fa..cfaadf1635 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED @@ -36,27 +36,27 @@ FileExtMismatchSettingsPanel.jLabel1.text=File Types: FileExtMismatchSettingsPanel.newExtButton.text=New Extension FileExtMismatchSettingsPanel.newMimePrompt.message=Add a new MIME file type: FileExtMismatchSettingsPanel.newMimePrompt.title=New MIME -FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.message=MIME type text is empty! +FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.message=MIME type text is empty\! FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.title=Empty type -FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.message=MIME type not supported! +FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.message=MIME type not supported\! FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.title=Type not supported -FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.message=MIME type already exists! +FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.message=MIME type already exists\! FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.title=Type already exists FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.message=MIME type is not detectable by this module. FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.title=Type not detectable -FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.message=No MIME type selected! +FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.message=No MIME type selected\! FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.title=No type selected FileExtMismatchSettingsPanel.newExtPrompt.message=Add an allowed extension: FileExtMismatchSettingsPanel.newExtPrompt.title=New allowed extension -FileExtMismatchSettingsPanel.newExtPrompt.empty.message=Extension text is empty! +FileExtMismatchSettingsPanel.newExtPrompt.empty.message=Extension text is empty\! FileExtMismatchSettingsPanel.newExtPrompt.empty.title=Extension text empty -FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.message=No MIME type selected! +FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.message=No MIME type selected\! FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.title=No MIME type selected -FileExtMismatchSettingsPanel.newExtPrompt.extExists.message=Extension already exists! +FileExtMismatchSettingsPanel.newExtPrompt.extExists.message=Extension already exists\! FileExtMismatchSettingsPanel.newExtPrompt.extExists.title=Extension already exists -FileExtMismatchSettingsPanel.removeExtButton.noneSelected.message=No extension selected! +FileExtMismatchSettingsPanel.removeExtButton.noneSelected.message=No extension selected\! FileExtMismatchSettingsPanel.removeExtButton.noneSelected.title=No extension selected -FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.message=No MIME type selected! +FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.message=No MIME type selected\! FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.title=No MIME type selected FileExtMismatchSettingsPanel.removeTypeButton.toolTipText= FileExtMismatchModuleSettingsPanel.checkAllRadioButton.text=Check all file types diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties-MERGED index ccc55e18b0..ca866a4a13 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/Bundle.properties-MERGED @@ -51,7 +51,6 @@ FileTypeIdGlobalSettingsPanel.JOptionPane.loadFailed.title=Load Failed FileTypeIdGlobalSettingsPanel.loadFileTypes.errorMessage=Failed to load existing file type definitions. FileTypeIdGlobalSettingsPanel.saveFileTypes.errorMessage=Failed to save file type definitions. FileTypeIdGlobalSettingsPanel.newTypeButton.text=New Type -FileTypeIdGlobalSettingsPanel.jLabel2.text=Custom MIME Types: FileTypeIdGlobalSettingsPanel.startUp.fileTypeDetectorInitializationException.msg=Error initializing the file type detector. AddFileTypeSignaturePanel.offsetLabel.text=Byte Offset AddFileTypeSignaturePanel.signatureTextField.text= @@ -60,7 +59,6 @@ AddFileTypeSignaturePanel.signatureLabel.text=Signature AddFileTypeSignaturePanel.hexPrefixLabel.text=0x AddFileTypeSignaturePanel.offsetRelativeToLabel.text=Offset is relative to AddFileTypeSignaturePanel.offsetTextField.text= -FileTypeIdGlobalSettingsPanel.jLabel1.text=Signatures FileTypeIdGlobalSettingsPanel.editTypeButton.text=Edit Type AddFileTypePanel.mimeTypeTextField.text= AddFileTypePanel.mimeTypeLabel.text=MIME Type @@ -72,4 +70,6 @@ AddFileTypePanel.postHitCheckBox.text=Alert as an "Interesting File" when found AddFileTypePanel.setNameLabel.text=Set Name AddFileTypePanel.setNameTextField.text= FileTypeIdGlobalSettingsPanel.ingestRunningWarningLabel.text=Cannot make changes to file type definitions when ingest is running! -FileTypeIdGlobalSettingsPanel.jLabel3.text=Autopsy can automatically detect many file types. Add your custom file types here. +FileTypeIdGlobalSettingsPanel.descriptionLabel.text=Autopsy can automatically detect many file types. Add your custom file types here. +FileTypeIdGlobalSettingsPanel.customTypesLabel.text=Custom MIME Types: +FileTypeIdGlobalSettingsPanel.signaturesLabel.text=Signatures diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java index 3533fb34d8..873f891ad0 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -602,29 +602,22 @@ public class HashDbIngestModule implements FileIngestModule { if ((!knownBadHashSets.isEmpty()) || (!knownHashSets.isEmpty()) || (!noChangeHashSets.isEmpty())) { StringBuilder detailsSb = new StringBuilder(); //details - detailsSb.append(""); //NON-NLS + detailsSb.append( + "
    " + + "" + + "" + + + "" + + "" + + + "\n" + + + "\n
    " + NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.knownBadsFound") + "" + jobTotals.totalKnownBadCount.get() + "
    " + Bundle.HashDbIngestModule_complete_noChangesFound() + "" + jobTotals.totalNoChangeCount.get() + "
    " + NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.totalCalcTime") + + "" + jobTotals.totalCalctime.get() + "
    " + NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.totalLookupTime") + + "" + jobTotals.totalLookuptime.get() + "
    " + - detailsSb.append("
    ") //NON-NLS - .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.knownBadsFound")) - .append("").append(jobTotals.totalKnownBadCount.get()).append("
    ") //NON-NLS - .append(Bundle.HashDbIngestModule_complete_noChangesFound()) - .append("" + jobTotals.totalNoChangeCount.get() + "
    ") //NON-NLS - .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.totalCalcTime")) - .append("").append(jobTotals.totalCalctime.get()).append("
    ") //NON-NLS - .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.totalLookupTime")) - .append("").append(jobTotals.totalLookuptime.get()).append("
    "); //NON-NLS - - detailsSb.append("

    ") //NON-NLS - .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.databasesUsed")) - .append("

    \n
      "); //NON-NLS + "

      " + NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.databasesUsed") + "

      \n
        "); //NON-NLS + Stream.concat(knownBadHashSets.stream(), noChangeHashSets.stream()).forEach((db) -> { detailsSb.append("
      • " + db.getHashSetName() + "
      • \n"); //NON-NLS }); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java index 4045abcda7..55bd974be4 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java @@ -20,12 +20,9 @@ package org.sleuthkit.autopsy.modules.hashdatabase; import java.sql.Connection; import java.sql.DriverManager; -import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import java.util.ArrayList; -import java.util.List; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.HashEntry; diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED index 31a0690b82..3c275ee9cb 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED @@ -83,8 +83,8 @@ FilesSetRulePanel.nameTextField.text= FilesSetRulePanel.ruleNameLabel.text=Rule Name (Optional): FilesSetRulePanel.messages.emptyNameCondition=You must specify a name pattern for this rule. FilesSetRulePanel.messages.invalidNameRegex=The name regular expression is not valid:\n\n{0} -FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, *, ?, ", <, or > unless it is a regular expression. -FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, ", <, or > unless it is a regular expression. +FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, *, ?, \", <, or > unless it is a regular expression. +FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, \", <, or > unless it is a regular expression. FilesSetRulePanel.messages.invalidPathRegex=The path regular expression is not valid:\n\n{0} FilesSetDefsPanel.doFileSetsDialog.duplicateRuleSet.text=Rule set with name {0} already exists. FilesSetRulePanel.pathSeparatorInfoLabel.text=Folder must be in parent path. Use '/' to give consecutive names @@ -109,21 +109,14 @@ FilesSetDefsPanel.ingest.deleteSetButton.text=Delete Filter FilesSetDefsPanel.interesting.jLabel6.text=Set Details FilesSetDefsPanel.ingest.jLabel6.text=Filter Details FilesSetDefsPanel.newRuleButton.text=New Rule -FilesSetDefsPanel.jLabel8.text=File Size: -FilesSetDefsPanel.jLabel7.text=MIME Type: FilesSetDefsPanel.rulePathConditionRegexCheckBox.text=Regex -FilesSetDefsPanel.jLabel4.text=Path Substring: -FilesSetDefsPanel.jLabel1.text=Rule Details FilesSetDefsPanel.dirsRadioButton.text=Directories -FilesSetDefsPanel.jLabel2.text=File Type: FilesSetDefsPanel.deleteRuleButton.text=Delete Rule FilesSetDefsPanel.fileNameRegexCheckbox.text=Substring / Regex FilesSetDefsPanel.ignoreKnownFilesCheckbox.text=Ignore Known Files FilesSetDefsPanel.rulePathConditionTextField.text= FilesSetDefsPanel.fileNameRadioButton.text=Full Name -FilesSetDefsPanel.jLabel5.text=Description: FilesSetDefsPanel.fileNameTextField.text= -FilesSetDefsPanel.jLabel3.text=Name: FilesSetDefsPanel.fileNameExtensionRadioButton.text=Extension Only FilesSetDefsPanel.rulesListLabel.text=Rules: FilesSetDefsPanel.editRuleButton.text=Edit Rule @@ -140,3 +133,10 @@ FilesSetDefsPanel.modifiedDateLabel.text=Modified Within: FilesSetDefsPanel.daysIncludedTextField.text= FilesSetDefsPanel.daysIncludedLabel.text=day(s) FilesSetRulePanel.daysIncludedLabel.text=day(s) +FilesSetDefsPanel.nameLabel.text=Name: +FilesSetDefsPanel.descriptionLabel.text=Description: +FilesSetDefsPanel.fileTypeLabel.text=File Type: +FilesSetDefsPanel.ruleLabel.text=Rule Details +FilesSetDefsPanel.pathLabel.text=Path Substring: +FilesSetDefsPanel.mimeTypeLabel.text=MIME Type: +FilesSetDefsPanel.fileSizeLabel.text=File Size: diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED index 2dc971a40d..87dacfc16c 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED @@ -21,7 +21,7 @@ PhotoRecIngestModule.complete.totalParsetime=Total Parsing Time: PhotoRecIngestModule.complete.photoRecResults=PhotoRec Results PhotoRecIngestModule.NotEnoughDiskSpace.detail.msg=PhotoRec error processing {0} with {1} Not enough space on primary disk to save unallocated space. PhotoRecIngestModule.cancelledByUser=PhotoRec cancelled by user. -PhotoRecIngestModule.error.exitValue=PhotoRec carver returned error exit value = {0} when scanning {1} +PhotoRecIngestModule.error.exitValue=PhotoRec carver returned error exit value \= {0} when scanning {1} PhotoRecIngestModule.error.msg=Error processing {0} with PhotoRec carver. PhotoRecIngestModule.complete.numberOfErrors=Number of Errors while Carving: PhotoRecCarverIngestJobSettingsPanel.detectionSettingsLabel.text=PhotoRec Settings diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/html/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/html/Bundle.properties-MERGED index 0be7595111..32f6867f0c 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/html/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/html/Bundle.properties-MERGED @@ -5,8 +5,8 @@ ReportHTML.getName.text=HTML Report ReportHTML.getDesc.text=A report about results and tagged items in HTML format. ReportHTML.writeIndex.title=for case {0} ReportHTML.writeIndex.noFrames.msg=Your browser is not compatible with our frame setup. -ReportHTML.writeIndex.noFrames.seeNav=Please see the navigation page for artifact links, -ReportHTML.writeIndex.seeSum=and the summary page for a case summary. +ReportHTML.writeIndex.noFrames.seeNav=Please see the navigation page for artifact links, +ReportHTML.writeIndex.seeSum=and the summary page for a case summary. ReportHTML.writeNav.title=Report Navigation ReportHTML.writeNav.h1=Report Navigation ReportHTML.writeNav.summary=Case Summary @@ -16,7 +16,7 @@ ReportHTML.writeSum.caseNumber=Case Number: ReportHTML.writeSum.caseNumImages=Number of Images: ReportHTML.writeSum.examiner=Examiner: ReportHTML.writeSum.title=Case Summary -ReportHTML.writeSum.warningMsg=Warning, this report was run before ingest services completed! +ReportHTML.writeSum.warningMsg=Warning, this report was run before ingest services completed\! # # autopsy/test/scripts/regression.py._html_report_diff() uses reportGenOn.text, caseName, caseNum, # examiner as a regex signature to skip report.html and summary.html diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties-MERGED index fa1a250e44..802b117c35 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/ui/Bundle.properties-MERGED @@ -19,3 +19,4 @@ TranslationContentPanel.ocrLabel.text=OCR: TranslationOptionsPanelController.moduleErr=Module Error TranslationOptionsPanelController.moduleErr.msg=A module caused an error listening to TranslationSettingsPanelController updates. See log to determine which module. Some data could be incomplete. TranslationContentPanel.showLabel.text=Show: +TranslationContentPanel.jSepLarge1.AccessibleContext.accessibleName= diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties-MERGED b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties-MERGED index adb7693b48..823399e0d0 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties-MERGED +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties-MERGED @@ -89,6 +89,10 @@ AutoIngestControlPanel.runningTable.toolTipText=The Running table displays the c AutoIngestControlPanel.SharedConfigurationDisabled=Shared configuration disabled AutoIngestControlPanel.ShowLogFailed.Message=Case log file does not exist AutoIngestControlPanel.ShowLogFailed.Title=Unable to display case log +# {0} - case db status +# {1} - search svc Status +# {2} - coord svc Status +# {3} - msg broker status AutoIngestControlPanel.tbServicesStatusMessage.Message=Case databases {0}, keyword search {1}, coordination {2}, messaging {3} AutoIngestControlPanel.tbServicesStatusMessage.Message.Down=down AutoIngestControlPanel.tbServicesStatusMessage.Message.Unknown=unknown @@ -182,16 +186,22 @@ DeleteCaseTask.progress.acquiringManifestLocks=Acquiring exclusive manifest file DeleteCaseTask.progress.connectingToCoordSvc=Connecting to the coordination service... DeleteCaseTask.progress.deletingCaseDirCoordSvcNode=Deleting case directory znode... DeleteCaseTask.progress.deletingCaseNameCoordSvcNode=Deleting case name znode... +# {0} - data source path DeleteCaseTask.progress.deletingDataSource=Deleting data source {0}... DeleteCaseTask.progress.deletingJobLogLockNode=Deleting case auto ingest log znode... +# {0} - manifest file path DeleteCaseTask.progress.deletingManifest=Deleting manifest file {0}... +# {0} - manifest file path DeleteCaseTask.progress.deletingManifestFileNode=Deleting the manifest file znode for {0}... DeleteCaseTask.progress.deletingResourcesLockNode=Deleting case resources znode... DeleteCaseTask.progress.gettingManifestPaths=Getting manifest file paths... +# {0} - manifest file path DeleteCaseTask.progress.lockingManifest=Locking manifest file {0}... DeleteCaseTask.progress.openingCaseDatabase=Opening the case database... DeleteCaseTask.progress.openingCaseMetadataFile=Opening case metadata file... +# {0} - manifest file path DeleteCaseTask.progress.parsingManifest=Parsing manifest file {0}... +# {0} - manifest file path DeleteCaseTask.progress.releasingManifestLock=Releasing lock on the manifest file {0}... DeleteCaseTask.progress.startMessage=Starting deletion... DeleteOrphanCaseNodesAction.progressDisplayName=Cleanup Case Znodes @@ -207,6 +217,7 @@ DeleteOrphanCaseNodesTask.progress.lookingForOrphanedCaseZnodes=Looking for orph DeleteOrphanCaseNodesTask.progress.startMessage=Starting orphaned case znode cleanup DeleteOrphanManifestNodesAction.progressDisplayName=Cleanup Manifest File Znodes DeleteOrphanManifestNodesTask.progress.connectingToCoordSvc=Connecting to the coordination service +# {0} - node path DeleteOrphanManifestNodesTask.progress.deletingOrphanedManifestNode=Deleting orphaned manifest file znode {0} DeleteOrphanManifestNodesTask.progress.gettingManifestNodes=Querying the coordination service for manifest file znodes DeleteOrphanManifestNodesTask.progress.lookingForOrphanedManifestFileZnodes=Looking for orphaned manifest file znodes @@ -215,6 +226,7 @@ HINT_CasesDashboardTopComponent=This is an adminstrative dashboard for multi-use OpenAutoIngestLogAction.deletedLogErrorMsg=The case auto ingest log has been deleted. OpenAutoIngestLogAction.logOpenFailedErrorMsg=Failed to open case auto ingest log. See application log for details. OpenAutoIngestLogAction.menuItemText=Open Auto Ingest Log File +# {0} - caseErrorMessage OpenCaseAction.errorMsg=Failed to open case: {0} OpenCaseAction.menuItemText=Open OpenIDE-Module-Long-Description=This module contains features that are being developed by Basis Technology and are not part of the default Autopsy distribution. You can enable this module to use the new features. The features should be stable, but their exact behavior and API are subject to change.\n\nWe make no guarantee that the API of this module will not change, so developers should be careful when relying on it. diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties-MERGED b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties-MERGED index 91e2bebd08..337e80b346 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties-MERGED +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties-MERGED @@ -75,6 +75,7 @@ MultiUserTestTool.unableCreatFile=Unable to create a file in case output directo MultiUserTestTool.unableToCheckService=Unable to check Multi User service state: {0} MultiUserTestTool.unableToCreateCase=Unable to create case MultiUserTestTool.unableToInitializeDatabase=Case database was not successfully initialized +MultiUserTestTool.unableToInitializeFilTypeDetector=Unable to initialize File Type Detector MultiUserTestTool.unableToReadDatabase=Unable to read from case database MultiUserTestTool.unableToReadTestFileFromDatabase=Unable to read test file info from case database MultiUserTestTool.unableToRunIngest=Unable to run ingest on test data source diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED index 9aeeabc046..79a4135ce4 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED @@ -36,7 +36,7 @@ KeywordSearchResultFactory.createNodeForKey.noResultsFound.text=No results found KeywordSearchResultFactory.query.exception.msg=Could not perform the query OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Keyword Search ingest module.\n\nThe module indexes files found in the disk image at ingest time.\nIt then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\nThe module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword search bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found. +OpenIDE-Module-Long-Description=Keyword Search ingest module.\n\nThe module indexes files found in the disk image at ingest time.\nIt then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\n\The module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword search bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found. OpenIDE-Module-Name=KeywordSearch OptionsCategory_Name_KeywordSearchOptions=Keyword Search OptionsCategory_Keywords_KeywordSearchOptions=Keyword Search @@ -360,24 +360,24 @@ DropdownListSearchPanel.jSaveSearchResults.text=Save search results GlobalEditListPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. KeywordSearchGlobalLanguageSettingsPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. KeywordSearchGlobalSearchSettingsPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. -ExtractedContentPanel.hitCountLabel.text=- +ExtractedContentPanel.AccessibleContext.accessibleName= +ExtractedContentPanel.jLabel1.text=Text Source: +ExtractedContentPanel.hitNextButton.text= ExtractedContentPanel.hitPreviousButton.text= +ExtractedContentPanel.hitButtonsLabel.text=Match ExtractedContentPanel.hitTotalLabel.text=- ExtractedContentPanel.hitOfLabel.text=of -ExtractedContentPanel.hitNextButton.text= -ExtractedContentPanel.hitButtonsLabel.text=Match +ExtractedContentPanel.hitCountLabel.text=- ExtractedContentPanel.hitLabel.toolTipText= ExtractedContentPanel.hitLabel.text=Matches on page: -ExtractedContentPanel.pageCurLabel.text=- +ExtractedContentPanel.pageNextButton.text= ExtractedContentPanel.pagePreviousButton.actionCommand=pagePreviousButton ExtractedContentPanel.pagePreviousButton.text= -ExtractedContentPanel.pageNextButton.text= -ExtractedContentPanel.pagesLabel.text=Page: -ExtractedContentPanel.pageTotalLabel.text=- ExtractedContentPanel.pageButtonsLabel.text=Page +ExtractedContentPanel.pageTotalLabel.text=- ExtractedContentPanel.pageOfLabel.text=of -ExtractedContentPanel.jLabel1.text=Text Source: -ExtractedContentPanel.AccessibleContext.accessibleName= +ExtractedContentPanel.pageCurLabel.text=- +ExtractedContentPanel.pagesLabel.text=Page: TextZoomPanel.zoomInButton.text= TextZoomPanel.zoomOutButton.text= TextZoomPanel.zoomResetButton.text=Reset diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED index 310602b0f9..26823e1150 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED @@ -5,10 +5,15 @@ ChromeCacheExtract_adding_artifacts_msg=Chrome Cache: Adding %d artifacts for an ChromeCacheExtract_adding_extracted_files_msg=Chrome Cache: Adding %d extracted files for analysis. ChromeCacheExtract_loading_files_msg=Chrome Cache: Loading files from %s. ChromeCacheExtractor.moduleName=ChromeCacheExtractor +# {0} - module name +# {1} - row number +# {2} - table length +# {3} - cache path ChromeCacheExtractor.progressMsg={0}: Extracting cache entry {1} of {2} entries from {3} DataSourceUsage_AndroidMedia=Android Media Card DataSourceUsage_DJU_Drone_DAT=DJI Internal SD Card DataSourceUsage_FlashDrive=Flash Drive +# {0} - OS name DataSourceUsageAnalyzer.customVolume.label=OS Drive ({0}) DataSourceUsageAnalyzer.parentModuleName=Recent Activity Extract.indexError.message=Failed to index artifact for keyword search. @@ -71,7 +76,7 @@ ExtractZone_progress_Msg=Extracting :Zone.Identifer files ExtractZone_Restricted=Restricted Sites Zone ExtractZone_Trusted=Trusted Sites Zone OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\nThe module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web activity (sites visited, stored cookies, book marked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\nThe module currently supports Windows only disk images.\nThe plugin is also fully functional when deployed on Windows version of Autopsy. +OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\n\The module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web activity (sites visited, stored cookies, book marked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\nThe module currently supports Windows only disk images.\nThe plugin is also fully functional when deployed on Windows version of Autopsy. OpenIDE-Module-Name=RecentActivity OpenIDE-Module-Short-Description=Recent Activity finder ingest module Chrome.moduleName=Chrome @@ -202,6 +207,7 @@ Recently_Used_Artifacts_Officedocs=Recently opened according to Office MRU Recently_Used_Artifacts_Winrar=Recently opened according to WinRAR MRU RegRipperFullNotFound=Full version RegRipper executable not found. RegRipperNotFound=Autopsy RegRipper executable not found. +# {0} - file name SearchEngineURLQueryAnalyzer.init.exception.msg=Unable to find {0}. SearchEngineURLQueryAnalyzer.moduleName.text=Search Engine SearchEngineURLQueryAnalyzer.engineName.none=NONE 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 b20ccf5912..b4afb53dd0 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 -#Tue, 12 Nov 2019 17:21:46 -0500 +#Thu, 07 May 2020 12:32:20 -0400 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.13.0 +currentVersion=Autopsy 4.15.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 998d3f715c..1ebd8cc685 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 -#Tue, 12 Nov 2019 17:21:46 -0500 -CTL_MainWindow_Title=Autopsy 4.13.0 -CTL_MainWindow_Title_No_Project=Autopsy 4.13.0 +#Thu, 07 May 2020 12:32:20 -0400 +CTL_MainWindow_Title=Autopsy 4.15.0 +CTL_MainWindow_Title_No_Project=Autopsy 4.15.0 From f6ed6462a2f6be1c7603e71ff9e36e325a1de53e Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 7 May 2020 16:33:27 -0400 Subject: [PATCH 26/81] integrating jsoup --- .../AnnotationsContentViewer.java | 275 ++++++++++-------- 1 file changed, 158 insertions(+), 117 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index c87178bade..907538cc72 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -20,8 +20,14 @@ package org.sleuthkit.autopsy.contentviewers; import java.awt.Component; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.function.Function; import java.util.logging.Level; +import java.util.stream.Collectors; +import javax.swing.JLabel; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringEscapeUtils; @@ -48,6 +54,10 @@ import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.datamodel.BlackboardAttribute; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; + /** * Annotations view of file contents. @@ -77,7 +87,8 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data return; } - StringBuilder html = new StringBuilder(); + Document html = Jsoup.parse(EMPTY_HTML); + Element body = html.getElementsByTag("body").first(); BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class); Content sourceFile = null; @@ -104,20 +115,22 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data } if (artifact != null) { - populateTagData(html, artifact, sourceFile); + populateTagData(body, artifact, sourceFile); } else { - populateTagData(html, sourceFile); + populateTagData(body, sourceFile); } if (sourceFile instanceof AbstractFile) { - populateCentralRepositoryData(html, artifact, (AbstractFile) sourceFile); - populateFileSetData(html, sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT); - populateFileSetData(html, sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); + populateCentralRepositoryData(body, artifact, (AbstractFile) sourceFile); + populateFileSetData(body, sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT); + populateFileSetData(body, sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); } - setText(html.toString()); + jTextPane1.setText(html.html()); jTextPane1.setCaretPosition(0); } + + /** * Populates the html provided with data concerning the source file and @@ -285,9 +298,15 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data * @param sourceFile A selected file, or a source file of the selected * artifact. */ - private void populateCentralRepositoryData(StringBuilder html, BlackboardArtifact artifact, AbstractFile sourceFile) { + @NbBundle.Messages({ + "AnnotationsContentViewer.centralRepositoryEntryDataLabel.case=Case:", + "AnnotationsContentViewer.centralRepositoryEntryDataLabel.type=Type:", + "AnnotationsContentViewer.centralRepositoryEntryDataLabel.comment=Comment:", + "AnnotationsContentViewer.centralRepositoryEntryDataLabel.path=Path:" + }) + private List populateCentralRepositoryData(StringBuilder html, BlackboardArtifact artifact, AbstractFile sourceFile) { if (CentralRepository.isEnabled()) { - startSection(html, "Central Repository Comments"); + //startSection(html, "Central Repository Comments"); List instancesList = new ArrayList<>(); if (artifact != null) { instancesList.addAll(CorrelationAttributeUtil.makeCorrAttrsForCorrelation(artifact)); @@ -338,38 +357,6 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data } } - /** - * Set the text of the text panel. - * - * @param text The text to set to the text panel. - */ - private void setText(String text) { - jTextPane1.setText("" + text + ""); //NON-NLS - } - - /** - * Start a new data section. - * - * @param html The HTML text to add the section to. - * @param sectionName The name of the section. - */ - private void startSection(StringBuilder html, String sectionName) { - html.append("

        ") - .append(sectionName) - .append("


        "); //NON-NLS - } - - /** - * Add a message. - * - * @param html The HTML text to add the message to. - * @param message The message text. - */ - private void addMessage(StringBuilder html, String message) { - html.append("

        ") - .append(message) - .append("


        "); //NON-NLS - } /** * Add a data table containing information about a tag. @@ -390,83 +377,137 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data endTable(html); } - /** - * Add a data table containing information about a correlation attribute - * instance in the Central Repository. - * - * @param html The HTML text to add the table to. - * @param attributeInstance The attribute instance whose information will be - * used to populate the table. - */ - @NbBundle.Messages({ - "AnnotationsContentViewer.centralRepositoryEntryDataLabel.case=Case:", - "AnnotationsContentViewer.centralRepositoryEntryDataLabel.type=Type:", - "AnnotationsContentViewer.centralRepositoryEntryDataLabel.comment=Comment:", - "AnnotationsContentViewer.centralRepositoryEntryDataLabel.path=Path:" - }) - private void addCentralRepositoryEntry(StringBuilder html, CorrelationAttributeInstance attributeInstance) { - startTable(html); - addRow(html, Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_case(), attributeInstance.getCorrelationCase().getDisplayName()); - addRow(html, Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_type(), attributeInstance.getCorrelationType().getDisplayName()); - addRow(html, Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_comment(), formatHtmlString(attributeInstance.getComment())); - addRow(html, Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_path(), attributeInstance.getFilePath()); - endTable(html); + + private static final String EMPTY_HTML = ""; + + private static final int DEFAULT_FONT_SIZE = new JLabel().getFont().getSize(); + private static final int SUBHEADER_FONT_SIZE = DEFAULT_FONT_SIZE * 12 / 11; + private static final int HEADER_FONT_SIZE = DEFAULT_FONT_SIZE * 14 / 11; + + private static final String HEADER_STYLE = "font-size:" + HEADER_FONT_SIZE + "px;font-weight:bold;"; + private static final String SUBHEADER_STYLE = "font-size:" + SUBHEADER_FONT_SIZE + "px;font-weight:bold;"; + private static final String MESSAGE_STYLE = "font-size:" + DEFAULT_FONT_SIZE + "px;font-style:italic;"; + private static final String CONTENT_STYLE = "font-size:" + DEFAULT_FONT_SIZE + "px;"; + + private static final int DEFAULT_TABLE_SPACING = DEFAULT_FONT_SIZE * 2; + private static final int DEFAULT_SECTION_SPACING = DEFAULT_FONT_SIZE; + private static final int DEFAULT_SUBSECTION_SPACING = DEFAULT_FONT_SIZE; + + + private static final List> CENTRAL_REPO_COMMENTS = Arrays.asList( + new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_case(), cai -> cai.getCorrelationCase().getDisplayName()), + new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_type(), cai -> cai.getCorrelationType().getDisplayName()), + new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_comment(), cai -> cai.getComment()), + new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_path(), cai -> cai.getFilePath()) + ); + + private static class ColumnEntry { + private final String columnName; + private final Function valueRetriever; + + ColumnEntry(String columnName, Function valueRetriever) { + this.columnName = columnName; + this.valueRetriever = valueRetriever; + } + + String getColumnName() { + return columnName; + } + + Function getValueRetriever() { + return valueRetriever; + } + + String retrieveValue(T object) { + return valueRetriever.apply(object); + } + } + + private Element appendVerticalEntryTables(Element parent, List items, List> rowHeaders) { + items.stream() + .filter(item -> item != null) + .forEach((item) -> { + List> tableData = rowHeaders.stream() + .map(row -> Arrays.asList(row.getColumnName(), row.retrieveValue(item))) + .collect(Collectors.toList()); + + Element childTable = appendTable(parent, 2, tableData, null); + childTable.attr("style", String.format("margin-bottom: %dpx", DEFAULT_TABLE_SPACING)); + }); + + return parent; + } + + private Element appendEntryTable(Element parent, List items, List> columns) { + int columnNumber = columns.size(); + List columnHeaders = columns.stream().map(c -> c.getColumnName()).collect(Collectors.toList()); + List> rows = items.stream() + .filter(r -> r != null) + .map(r -> { + return columns.stream() + .map(c -> c.retrieveValue(r)) + .collect(Collectors.toList()); + }) + .collect(Collectors.toList()); + + Element table = appendTable(parent, columnNumber, rows, columnHeaders); + table.attr("style", String.format("margin-bottom: %dpx", DEFAULT_TABLE_SPACING)); + return table; + } + + + private Element appendTable(Element parent, int columnNumber, List> content, List columnHeaders) { + Element table = parent.appendElement("table"); + if (columnHeaders != null && !columnHeaders.isEmpty()) { + Element header = parent.appendElement("thead"); + appendRow(header, columnHeaders, columnNumber, true); + } + Element tableBody = table.appendElement("tbody"); + + content.forEach((rowData) -> appendRow(tableBody, rowData, columnNumber, false)); + return table; + } + + // TODO test sanitizing string + private Element appendRow(Element rowParent, List data, int columnNumber, boolean isHeader) { + String cellType = isHeader ? "th" : "td"; + Element row = rowParent.appendElement("tr"); + for (int i = 0; i < columnNumber; i++) { + Element cell = row.appendElement(cellType); + if (data != null && i < data.size()) { + cell.attr("valign", "top"); + cell.attr("style", CONTENT_STYLE); + cell.text(StringUtils.isEmpty(data.get(i)) ? "" : data.get(i)); + } + } + return row; + } + + private Element appendSection(Element parent, String headerText) { + Element parentDiv = parent.appendElement("div"); + parentDiv.attr("style", String.format("margin-bottom: %dpx;", DEFAULT_SECTION_SPACING)); + Element header = parentDiv.appendElement("h1"); + header.text(headerText); + header.attr("style", HEADER_STYLE); + return parentDiv; + } + + private Element appendSubsection(Element parent, String headerText) { + Element parentDiv = parent.appendElement("div"); + parentDiv.attr("style", String.format("margin-bottom: %dpx;", DEFAULT_SUBSECTION_SPACING)); + Element header = parentDiv.appendElement("h2"); + header.text(headerText); + header.attr("style", SUBHEADER_STYLE); + return parentDiv; + } + + private Element appendMessage(Element parent, String message) { + Element messageEl = parent.appendElement("p"); + messageEl.text(message); + messageEl.attr("style", MESSAGE_STYLE); + return messageEl; } - /** - * Start a data table. - * - * @param html The HTML text to add the table to. - */ - private void startTable(StringBuilder html) { - html.append(""); //NON-NLS - } - - /** - * Add a data row to a table. - * - * @param html The HTML text to add the row to. - * @param key The key for the left column of the data row. - * @param value The value for the right column of the data row. - */ - private void addRow(StringBuilder html, String key, String value) { - html.append(""); //NON-NLS - } - - /** - * End a data table. - * - * @param html The HTML text on which to end a table. - */ - private void endTable(StringBuilder html) { - html.append("
        "); //NON-NLS - html.append(key); - html.append(""); //NON-NLS - html.append(value); - html.append("


        "); //NON-NLS - } - - /** - * End a data section. - * - * @param html The HTML text on which to end a section. - */ - private void endSection(StringBuilder html) { - html.append("
        "); //NON-NLS - } - - /** - * Apply escape sequence to special characters. Line feed and carriage - * return character combinations will be converted to HTML line breaks. - * - * @param text The text to format. - * - * @return The formatted text. - */ - private String formatHtmlString(String text) { - String formattedString = StringEscapeUtils.escapeHtml4(text); - return formattedString.replaceAll("(\r\n|\r|\n|\n\r)", "
        "); - } /** * This method is called from within the constructor to initialize the form. @@ -554,6 +595,6 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data @Override public void resetComponent() { - setText(""); + jTextPane1.setText(EMPTY_HTML); } } From 9fbf13649a33de17fe2e9577a4deadb21c029d63 Mon Sep 17 00:00:00 2001 From: apriestman Date: Fri, 8 May 2020 09:37:10 -0400 Subject: [PATCH 27/81] Add max number of images to preload and an exception firewall. --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 47fff7320f..d9d369cb2c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -2060,6 +2060,7 @@ public class Case { private final SleuthkitCase tskCase; private final String caseName; + private final long MAX_IMAGE_THRESHOLD = 100; private final ProgressIndicator progressIndicator; /** @@ -2153,6 +2154,13 @@ public class Case { if (images == null) { return; } + + if (images.size() > MAX_IMAGE_THRESHOLD) { + // If we have a large number of images, don't try to preload anything + logger.log( + Level.INFO, + String.format("Skipping background load of file systems due to large number of images in case (%d)", images.size())); + } checkIfCancelled(); openFileSystems(images); @@ -2160,6 +2168,9 @@ public class Case { logger.log( Level.INFO, String.format("Background operation opening all file systems in %s has been cancelled.", caseName)); + } catch (Exception ex) { + // Exception firewall + logger.log(Level.WARNING, "Error while opening file systems in background", ex); } } From b0373a7e612dacedf170a7b73de5203c4cec0ea6 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 8 May 2020 10:46:27 -0400 Subject: [PATCH 28/81] refactoring --- .../AnnotationsContentViewer.java | 574 +++++++++--------- 1 file changed, 279 insertions(+), 295 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index 907538cc72..bc8ef25642 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -31,7 +31,7 @@ import javax.swing.JLabel; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringEscapeUtils; -import org.openide.util.NbBundle; +import static org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; import org.openide.nodes.Node; import org.openide.util.lookup.ServiceProvider; @@ -58,20 +58,101 @@ import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; - /** * Annotations view of file contents. */ @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives @ServiceProvider(service = DataContentViewer.class, position = 8) -@NbBundle.Messages({ +@Messages({ "AnnotationsContentViewer.title=Annotations", - "AnnotationsContentViewer.toolTip=Displays tags and comments associated with the selected content." + "AnnotationsContentViewer.toolTip=Displays tags and comments associated with the selected content.", + "AnnotationsContentViewer.centralRepositoryEntry.title=Central Repository Comments", + "AnnotationsContentViewer.centralRepositoryEntry.onEmpty=There is no comment data for the selected content in the Central Repository.", + "AnnotationsContentViewer.centralRepositoryEntryDataLabel.case=Case:", + "AnnotationsContentViewer.centralRepositoryEntryDataLabel.type=Type:", + "AnnotationsContentViewer.centralRepositoryEntryDataLabel.comment=Comment:", + "AnnotationsContentViewer.centralRepositoryEntryDataLabel.path=Path:", + "AnnotationsContentViewer.tagEntry.title=Tag Comments", + "AnnotationsContentViewer.tagEntry.onContentEmpty=There are no tags for the selected content.", + "AnnotationsContentViewer.tagEntry.onArtifactEmpty=There are no tags for the selected artifact.", + "AnnotationsContentViewer.tagEntryDataLabel.tag=Tag:", + "AnnotationsContentViewer.tagEntryDataLabel.tagUser=Examiner:", + "AnnotationsContentViewer.tagEntryDataLabel.comment=Comment:", + "AnnotationsContentViewer.fileHitEntry.hashSetHitTitle=Hash Set Hit Comments", + "AnnotationsContentViewer.fileHitEntry.onHashSetHitEmpty=There are no hash set hits for the selected content.", + "AnnotationsContentViewer.fileHitEntry.interestingFileHitTitle=Interesting File Hit Comments", + "AnnotationsContentViewer.fileHitEntry.onInterestingFileHitEmpty=There are no interesting file hits for the selected content.", + "AnnotationsContentViewer.fileHitEntry.setName=Set Name", + "AnnotationsContentViewer.fileHitEntry.comment=Comment", + "AnnotationsContentViewer.sourceFile.title=Source File" }) public class AnnotationsContentViewer extends javax.swing.JPanel implements DataContentViewer { private static final Logger logger = Logger.getLogger(AnnotationsContentViewer.class.getName()); + private static final String EMPTY_HTML = ""; + + private static final int DEFAULT_FONT_SIZE = new JLabel().getFont().getSize(); + private static final int SUBHEADER_FONT_SIZE = DEFAULT_FONT_SIZE * 12 / 11; + private static final int HEADER_FONT_SIZE = DEFAULT_FONT_SIZE * 14 / 11; + + private static final int DEFAULT_SUBSECTION_LEFT_PAD = DEFAULT_FONT_SIZE; + + private static final String HEADER_STYLE = "font-size:" + HEADER_FONT_SIZE + "px;font-weight:bold;"; + private static final String SUBHEADER_STYLE = "font-size:" + SUBHEADER_FONT_SIZE + "px;font-weight:bold;"; + private static final String MESSAGE_STYLE = "font-size:" + DEFAULT_FONT_SIZE + "px;font-style:italic;"; + private static final String CONTENT_STYLE = "font-size:" + DEFAULT_FONT_SIZE + "px;"; + + private static final int DEFAULT_TABLE_SPACING = DEFAULT_FONT_SIZE * 2; + private static final int DEFAULT_SECTION_SPACING = DEFAULT_FONT_SIZE; + private static final int DEFAULT_SUBSECTION_SPACING = DEFAULT_FONT_SIZE; + + private static final List> TAG_COLUMNS = Arrays.asList( + new ColumnEntry<>(Bundle.AnnotationsContentViewer_tagEntryDataLabel_tag(), + (tag) -> (tag.getName() != null) ? tag.getName().getDisplayName() : null), + new ColumnEntry<>(Bundle.AnnotationsContentViewer_tagEntryDataLabel_tagUser(), (tag) -> tag.getUserName()), + new ColumnEntry<>(Bundle.AnnotationsContentViewer_tagEntryDataLabel_comment(), (tag) -> tag.getComment()) + ); + + private static final List> FILESET_HIT_COLUMNS = Arrays.asList( + new ColumnEntry<>(Bundle.AnnotationsContentViewer_fileHitEntry_setName(), + (bba) -> tryGetAttribute(bba, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)), + new ColumnEntry<>(Bundle.AnnotationsContentViewer_fileHitEntry_comment(), + (bba) -> tryGetAttribute(bba, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT)) + ); + + private static final List> CENTRAL_REPO_COMMENTS_COLUMNS = Arrays.asList( + new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_case(), + cai -> (cai.getCorrelationCase() != null) ? cai.getCorrelationCase().getDisplayName() : null), + new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_type(), + cai -> (cai.getCorrelationType() != null) ? cai.getCorrelationType().getDisplayName() : null), + new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_comment(), cai -> cai.getComment()), + new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_path(), cai -> cai.getFilePath()) + ); + + private static class ColumnEntry { + + private final String columnName; + private final Function valueRetriever; + + ColumnEntry(String columnName, Function valueRetriever) { + this.columnName = columnName; + this.valueRetriever = valueRetriever; + } + + String getColumnName() { + return columnName; + } + + Function getValueRetriever() { + return valueRetriever; + } + + String retrieveValue(T object) { + return valueRetriever.apply(object); + } + } + /** * Creates an instance of AnnotationsContentViewer. */ @@ -115,54 +196,121 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data } if (artifact != null) { - populateTagData(body, artifact, sourceFile); + renderArtifact(body, artifact, sourceFile); } else { - populateTagData(body, sourceFile); - } - - if (sourceFile instanceof AbstractFile) { - populateCentralRepositoryData(body, artifact, (AbstractFile) sourceFile); - populateFileSetData(body, sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT); - populateFileSetData(body, sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); + renderAbstractFile(body, sourceFile, false); } jTextPane1.setText(html.html()); jTextPane1.setCaretPosition(0); } - - - /** - * Populates the html provided with data concerning the source file and - * whether it appears in a file set. - * - * @param html The html to append information. - * @param content The source content to check for blackboard artifacts. - * @param artifactType The artifact type to check for. - */ - private void populateFileSetData(StringBuilder html, Content content, BlackboardArtifact.ARTIFACT_TYPE artifactType) { - String artifactTypeName = artifactType.getDisplayName(); + private static void renderArtifact(Element parent, BlackboardArtifact bba, Content sourceContent) { + appendEntries(parent, + Bundle.AnnotationsContentViewer_tagEntry_title(), + Bundle.AnnotationsContentViewer_tagEntry_onArtifactEmpty(), + getTags(bba), TAG_COLUMNS, false, true); + if (sourceContent instanceof AbstractFile) { + AbstractFile sourceFile = (AbstractFile) sourceContent; + + if (CentralRepository.isEnabled()) { + List centralRepoComments = getCentralRepositoryData(bba, sourceFile); + appendEntries(parent, + Bundle.AnnotationsContentViewer_centralRepositoryEntry_title(), + Bundle.AnnotationsContentViewer_centralRepositoryEntry_onEmpty(), + centralRepoComments, CENTRAL_REPO_COMMENTS_COLUMNS, false, true); + } + } + + if (BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() == bba.getArtifactTypeID()) { + appendEntries(parent, + Bundle.AnnotationsContentViewer_fileHitEntry_hashSetHitTitle(), + Bundle.AnnotationsContentViewer_fileHitEntry_onHashSetHitEmpty(), + Arrays.asList(bba), FILESET_HIT_COLUMNS, false, false); + } + + if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == bba.getArtifactTypeID()) { + appendEntries(parent, + Bundle.AnnotationsContentViewer_fileHitEntry_interestingFileHitTitle(), + Bundle.AnnotationsContentViewer_fileHitEntry_onInterestingFileHitEmpty(), + Arrays.asList(bba), FILESET_HIT_COLUMNS, false, false); + } + + Element sourceFileSection = appendSection(parent, Bundle.AnnotationsContentViewer_sourceFile_title()); + renderAbstractFile(sourceFileSection, sourceContent, true); + } + + private static void renderAbstractFile(Element parent, Content sourceContent, boolean isSubheader) { + appendEntries(parent, + Bundle.AnnotationsContentViewer_tagEntry_title(), + Bundle.AnnotationsContentViewer_tagEntry_onContentEmpty(), + getTags(sourceContent), TAG_COLUMNS, isSubheader, true); + + if (sourceContent instanceof AbstractFile) { + AbstractFile sourceFile = (AbstractFile) sourceContent; + + if (CentralRepository.isEnabled()) { + List centralRepoComments = getCentralRepositoryData(null, sourceFile); + appendEntries(parent, + Bundle.AnnotationsContentViewer_centralRepositoryEntry_title(), + Bundle.AnnotationsContentViewer_centralRepositoryEntry_onEmpty(), + centralRepoComments, CENTRAL_REPO_COMMENTS_COLUMNS, isSubheader, true); + } + + appendEntries(parent, + Bundle.AnnotationsContentViewer_fileHitEntry_hashSetHitTitle(), + Bundle.AnnotationsContentViewer_fileHitEntry_onHashSetHitEmpty(), + getFileSetHits(sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT), + FILESET_HIT_COLUMNS, isSubheader, false); + + appendEntries(parent, + Bundle.AnnotationsContentViewer_fileHitEntry_interestingFileHitTitle(), + Bundle.AnnotationsContentViewer_fileHitEntry_onInterestingFileHitEmpty(), + getFileSetHits(sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT), + FILESET_HIT_COLUMNS, isSubheader, false); + } + + } + + private static List getTags(Content sourceContent) { try { SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - - startSection(html, artifactTypeName); - List fileHitInfo = tskCase.getBlackboardArtifacts(artifactType, content.getId()); - if (fileHitInfo.isEmpty()) { - addMessage(html, String.format("There are no %s for the selected content.", artifactTypeName)); - } else { - fileHitInfo.forEach((fileHit) -> { - addFileHitEntry(html, fileHit); - }); - } - endSection(html); + return tskCase.getContentTagsByContent(sourceContent); } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Exception while getting tags from the case database.", ex); //NON-NLS } + return new ArrayList<>(); } + private static List getTags(BlackboardArtifact bba) { + try { + SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return tskCase.getBlackboardArtifactTagsByArtifact(bba); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Exception while getting tags from the case database.", ex); //NON-NLS + } + return new ArrayList<>(); + } + + private static List getFileSetHits(AbstractFile sourceFile, BlackboardArtifact.ARTIFACT_TYPE type) { + try { + SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return tskCase.getBlackboardArtifacts(type, sourceFile.getId()); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Exception while getting file set hits from the case database.", ex); //NON-NLS + } + return new ArrayList<>(); + } + + + /** * Attempts to retrieve the attribute of a particular type from a blackboard * artifact. @@ -172,7 +320,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data * * @return The string value of the attribute or null if not found. */ - private String tryGetAttribute(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE attributeType) { + private static String tryGetAttribute(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE attributeType) { if (artifact == null) { return null; } @@ -191,285 +339,122 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data return attr.getValueString(); } - /** - * Add a data table containing information about an file set hit artifact - * (i.e. hash hit). - * - * @param html The HTML text to add the table to. - * @param tag The blackboard artifact with hash hit information whose - * information will be used to populate the table. - */ - @NbBundle.Messages({ - "AnnotationsContentViewer.addHashHitEntry.hashSet=Hash Set:", - "AnnotationsContentViewer.addHashHitEntry.comment=Comment:" - }) - private void addFileHitEntry(StringBuilder html, BlackboardArtifact artifact) { - startTable(html); - - String hashset = tryGetAttribute(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME); - String comment = tryGetAttribute(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT); - - if (StringUtils.isNotBlank(hashset)) { - addRow(html, Bundle.AnnotationsContentViewer_addHashHitEntry_hashSet(), hashset); - } - - if (StringUtils.isNotBlank(comment)) { - addRow(html, Bundle.AnnotationsContentViewer_tagEntryDataLabel_comment(), comment); - } - - endTable(html); - } - - /** - * Populate the "Selected Item" sections with tag data for the supplied - * content. - * - * @param html The HTML text to update. - * @param content Selected content. - */ - private void populateTagData(StringBuilder html, Content content) { - try { - SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - - startSection(html, "Selected Item"); - List fileTagsList = tskCase.getContentTagsByContent(content); - if (fileTagsList.isEmpty()) { - addMessage(html, "There are no tags for the selected content."); - } else { - for (ContentTag tag : fileTagsList) { - addTagEntry(html, tag); - } - } - endSection(html); - } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Exception while getting tags from the case database.", ex); //NON-NLS - } - } - - /** - * Populate the "Selected Item" and "Source File" sections with tag data for - * a supplied artifact. - * - * @param html The HTML text to update. - * @param artifact A selected artifact. - * @param sourceFile The source content of the selected artifact. - */ - private void populateTagData(StringBuilder html, BlackboardArtifact artifact, Content sourceFile) { - try { - SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - - startSection(html, "Selected Item"); - List artifactTagsList = tskCase.getBlackboardArtifactTagsByArtifact(artifact); - if (artifactTagsList.isEmpty()) { - addMessage(html, "There are no tags for the selected artifact."); - } else { - for (BlackboardArtifactTag tag : artifactTagsList) { - addTagEntry(html, tag); - } - } - endSection(html); - - if (sourceFile != null) { - startSection(html, "Source File"); - List fileTagsList = tskCase.getContentTagsByContent(sourceFile); - if (fileTagsList.isEmpty()) { - addMessage(html, "There are no tags for the source content."); - } else { - for (ContentTag tag : fileTagsList) { - addTagEntry(html, tag); - } - } - endSection(html); - } - } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Exception while getting tags from the case database.", ex); //NON-NLS - } - } - /** * Populate the "Central Repository Comments" section with data. * - * @param html The HTML text to update. * @param artifact A selected artifact (can be null). * @param sourceFile A selected file, or a source file of the selected * artifact. */ - @NbBundle.Messages({ - "AnnotationsContentViewer.centralRepositoryEntryDataLabel.case=Case:", - "AnnotationsContentViewer.centralRepositoryEntryDataLabel.type=Type:", - "AnnotationsContentViewer.centralRepositoryEntryDataLabel.comment=Comment:", - "AnnotationsContentViewer.centralRepositoryEntryDataLabel.path=Path:" - }) - private List populateCentralRepositoryData(StringBuilder html, BlackboardArtifact artifact, AbstractFile sourceFile) { - if (CentralRepository.isEnabled()) { - //startSection(html, "Central Repository Comments"); - List instancesList = new ArrayList<>(); - if (artifact != null) { - instancesList.addAll(CorrelationAttributeUtil.makeCorrAttrsForCorrelation(artifact)); - } - try { - List artifactTypes = CentralRepository.getInstance().getDefinedCorrelationTypes(); - String md5 = sourceFile.getMd5Hash(); - if (md5 != null && !md5.isEmpty() && null != artifactTypes && !artifactTypes.isEmpty()) { - for (CorrelationAttributeInstance.Type attributeType : artifactTypes) { - if (attributeType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) { - CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCase()); - instancesList.add(new CorrelationAttributeInstance( - attributeType, - md5, - correlationCase, - CorrelationDataSource.fromTSKDataSource(correlationCase, sourceFile.getDataSource()), - sourceFile.getParentPath() + sourceFile.getName(), - "", - sourceFile.getKnown(), - sourceFile.getId())); - break; - } + private static List getCentralRepositoryData(BlackboardArtifact artifact, AbstractFile sourceFile) { + List toReturn = new ArrayList<>(); + + List instancesList = new ArrayList<>(); + if (artifact != null) { + instancesList.addAll(CorrelationAttributeUtil.makeCorrAttrsForCorrelation(artifact)); + } + + try { + List artifactTypes = CentralRepository.getInstance().getDefinedCorrelationTypes(); + String md5 = sourceFile.getMd5Hash(); + if (md5 != null && !md5.isEmpty() && null != artifactTypes && !artifactTypes.isEmpty()) { + for (CorrelationAttributeInstance.Type attributeType : artifactTypes) { + if (attributeType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) { + CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCase()); + instancesList.add(new CorrelationAttributeInstance( + attributeType, + md5, + correlationCase, + CorrelationDataSource.fromTSKDataSource(correlationCase, sourceFile.getDataSource()), + sourceFile.getParentPath() + sourceFile.getName(), + "", + sourceFile.getKnown(), + sourceFile.getId())); + break; } } + } - boolean commentDataFound = false; - - for (CorrelationAttributeInstance instance : instancesList) { - List correlatedInstancesList - = CentralRepository.getInstance().getArtifactInstancesByTypeValue(instance.getCorrelationType(), instance.getCorrelationValue()); - for (CorrelationAttributeInstance correlatedInstance : correlatedInstancesList) { - if (correlatedInstance.getComment() != null && correlatedInstance.getComment().isEmpty() == false) { - commentDataFound = true; - addCentralRepositoryEntry(html, correlatedInstance); - } + for (CorrelationAttributeInstance instance : instancesList) { + List correlatedInstancesList + = CentralRepository.getInstance().getArtifactInstancesByTypeValue(instance.getCorrelationType(), instance.getCorrelationValue()); + for (CorrelationAttributeInstance correlatedInstance : correlatedInstancesList) { + if (StringUtils.isNotEmpty(correlatedInstance.getComment())) { + toReturn.add(correlatedInstance); } } - - if (commentDataFound == false) { - addMessage(html, "There is no comment data for the selected content in the Central Repository."); - } - } catch (CentralRepoException | TskCoreException ex) { - logger.log(Level.SEVERE, "Error connecting to the Central Repository database.", ex); // NON-NLS - } catch (CorrelationAttributeNormalizationException ex) { - logger.log(Level.SEVERE, "Error normalizing instance from Central Repository database.", ex); // NON-NLS } - endSection(html); + + } catch (CentralRepoException | TskCoreException ex) { + logger.log(Level.SEVERE, "Error connecting to the Central Repository database.", ex); // NON-NLS + } catch (CorrelationAttributeNormalizationException ex) { + logger.log(Level.SEVERE, "Error normalizing instance from Central Repository database.", ex); // NON-NLS + } + + return toReturn; + } + + + private static void appendEntries(Element parent, String title, String errorMessage, List items, + List> fields, boolean isSubsection, boolean isVerticalTable) { + + Element sectionDiv = (isSubsection) ? appendSubsection(parent, title) : appendSection(parent, title); + + if (items == null || items.isEmpty()) { + appendMessage(sectionDiv, errorMessage); + } else if (isVerticalTable) { + appendVerticalEntryTables(sectionDiv, items, fields); + } else { + appendEntryTable(sectionDiv, items, fields); } } - - /** - * Add a data table containing information about a tag. - * - * @param html The HTML text to add the table to. - * @param tag The tag whose information will be used to populate the table. - */ - @NbBundle.Messages({ - "AnnotationsContentViewer.tagEntryDataLabel.tag=Tag:", - "AnnotationsContentViewer.tagEntryDataLabel.tagUser=Tag User:", - "AnnotationsContentViewer.tagEntryDataLabel.comment=Comment:" - }) - private void addTagEntry(StringBuilder html, Tag tag) { - startTable(html); - addRow(html, Bundle.AnnotationsContentViewer_tagEntryDataLabel_tag(), tag.getName().getDisplayName()); - addRow(html, Bundle.AnnotationsContentViewer_tagEntryDataLabel_tagUser(), tag.getUserName()); - addRow(html, Bundle.AnnotationsContentViewer_tagEntryDataLabel_comment(), formatHtmlString(tag.getComment())); - endTable(html); - } - - - private static final String EMPTY_HTML = ""; - - private static final int DEFAULT_FONT_SIZE = new JLabel().getFont().getSize(); - private static final int SUBHEADER_FONT_SIZE = DEFAULT_FONT_SIZE * 12 / 11; - private static final int HEADER_FONT_SIZE = DEFAULT_FONT_SIZE * 14 / 11; - - private static final String HEADER_STYLE = "font-size:" + HEADER_FONT_SIZE + "px;font-weight:bold;"; - private static final String SUBHEADER_STYLE = "font-size:" + SUBHEADER_FONT_SIZE + "px;font-weight:bold;"; - private static final String MESSAGE_STYLE = "font-size:" + DEFAULT_FONT_SIZE + "px;font-style:italic;"; - private static final String CONTENT_STYLE = "font-size:" + DEFAULT_FONT_SIZE + "px;"; - - private static final int DEFAULT_TABLE_SPACING = DEFAULT_FONT_SIZE * 2; - private static final int DEFAULT_SECTION_SPACING = DEFAULT_FONT_SIZE; - private static final int DEFAULT_SUBSECTION_SPACING = DEFAULT_FONT_SIZE; - - - private static final List> CENTRAL_REPO_COMMENTS = Arrays.asList( - new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_case(), cai -> cai.getCorrelationCase().getDisplayName()), - new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_type(), cai -> cai.getCorrelationType().getDisplayName()), - new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_comment(), cai -> cai.getComment()), - new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_path(), cai -> cai.getFilePath()) - ); - - private static class ColumnEntry { - private final String columnName; - private final Function valueRetriever; - - ColumnEntry(String columnName, Function valueRetriever) { - this.columnName = columnName; - this.valueRetriever = valueRetriever; - } - - String getColumnName() { - return columnName; - } - - Function getValueRetriever() { - return valueRetriever; - } - - String retrieveValue(T object) { - return valueRetriever.apply(object); - } - } - - private Element appendVerticalEntryTables(Element parent, List items, List> rowHeaders) { + private static Element appendVerticalEntryTables(Element parent, List items, List> rowHeaders) { items.stream() - .filter(item -> item != null) - .forEach((item) -> { - List> tableData = rowHeaders.stream() - .map(row -> Arrays.asList(row.getColumnName(), row.retrieveValue(item))) - .collect(Collectors.toList()); - - Element childTable = appendTable(parent, 2, tableData, null); - childTable.attr("style", String.format("margin-bottom: %dpx", DEFAULT_TABLE_SPACING)); - }); - + .filter(item -> item != null) + .forEach((item) -> { + List> tableData = rowHeaders.stream() + .map(row -> Arrays.asList(row.getColumnName(), row.retrieveValue(item))) + .collect(Collectors.toList()); + + Element childTable = appendTable(parent, 2, tableData, null); + childTable.attr("style", String.format("margin-bottom: %dpx", DEFAULT_TABLE_SPACING)); + }); + return parent; } - - private Element appendEntryTable(Element parent, List items, List> columns) { + + private static Element appendEntryTable(Element parent, List items, List> columns) { int columnNumber = columns.size(); List columnHeaders = columns.stream().map(c -> c.getColumnName()).collect(Collectors.toList()); List> rows = items.stream() - .filter(r -> r != null) - .map(r -> { - return columns.stream() - .map(c -> c.retrieveValue(r)) - .collect(Collectors.toList()); - }) - .collect(Collectors.toList()); - + .filter(r -> r != null) + .map(r -> { + return columns.stream() + .map(c -> c.retrieveValue(r)) + .collect(Collectors.toList()); + }) + .collect(Collectors.toList()); + Element table = appendTable(parent, columnNumber, rows, columnHeaders); table.attr("style", String.format("margin-bottom: %dpx", DEFAULT_TABLE_SPACING)); return table; } - - - private Element appendTable(Element parent, int columnNumber, List> content, List columnHeaders) { + + private static Element appendTable(Element parent, int columnNumber, List> content, List columnHeaders) { Element table = parent.appendElement("table"); if (columnHeaders != null && !columnHeaders.isEmpty()) { Element header = parent.appendElement("thead"); - appendRow(header, columnHeaders, columnNumber, true); + appendRow(header, columnHeaders, columnNumber, true); } Element tableBody = table.appendElement("tbody"); - + content.forEach((rowData) -> appendRow(tableBody, rowData, columnNumber, false)); return table; } - + // TODO test sanitizing string - private Element appendRow(Element rowParent, List data, int columnNumber, boolean isHeader) { + private static Element appendRow(Element rowParent, List data, int columnNumber, boolean isHeader) { String cellType = isHeader ? "th" : "td"; Element row = rowParent.appendElement("tr"); for (int i = 0; i < columnNumber; i++) { @@ -482,33 +467,32 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data } return row; } - - private Element appendSection(Element parent, String headerText) { - Element parentDiv = parent.appendElement("div"); - parentDiv.attr("style", String.format("margin-bottom: %dpx;", DEFAULT_SECTION_SPACING)); - Element header = parentDiv.appendElement("h1"); + + private static Element appendSection(Element parent, String headerText) { + Element sectionDiv = parent.appendElement("div"); + sectionDiv.attr("style", String.format("margin-bottom: %dpx;", DEFAULT_SECTION_SPACING)); + Element header = sectionDiv.appendElement("h1"); header.text(headerText); header.attr("style", HEADER_STYLE); - return parentDiv; + return sectionDiv; } - - private Element appendSubsection(Element parent, String headerText) { - Element parentDiv = parent.appendElement("div"); - parentDiv.attr("style", String.format("margin-bottom: %dpx;", DEFAULT_SUBSECTION_SPACING)); - Element header = parentDiv.appendElement("h2"); + + private static Element appendSubsection(Element parent, String headerText) { + Element subsectionDiv = parent.appendElement("div"); + subsectionDiv.attr("style", String.format("margin-bottom: %dpx; padding-left: %dpx;", DEFAULT_SUBSECTION_SPACING, DEFAULT_SUBSECTION_LEFT_PAD)); + Element header = subsectionDiv.appendElement("h2"); header.text(headerText); header.attr("style", SUBHEADER_STYLE); - return parentDiv; + return subsectionDiv; } - - private Element appendMessage(Element parent, String message) { + + private static Element appendMessage(Element parent, String message) { Element messageEl = parent.appendElement("p"); messageEl.text(message); messageEl.attr("style", MESSAGE_STYLE); return messageEl; } - /** * 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 From 278cfd0817d8bc2ed43655d3898654c76515e0da Mon Sep 17 00:00:00 2001 From: apriestman Date: Fri, 8 May 2020 11:29:42 -0400 Subject: [PATCH 29/81] Use new version of getImageFileSystems. Stop trying to read if a read fails. --- .../org/sleuthkit/autopsy/casemodule/Case.java | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index d9d369cb2c..9ce6b62094 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -2118,28 +2118,18 @@ public class Case { * event that the operation is * cancelled prior to completion. */ - private void openFileSystems(List images) throws InterruptedException { + private void openFileSystems(List images) throws TskCoreException, InterruptedException { byte[] tempBuff = new byte[512]; - + for (Image image : images) { String imageStr = image.getName(); progressIndicator.progress(Bundle.Case_openFileSystems_openingImage(imageStr)); - Collection fileSystems = this.tskCase.getFileSystems(image); + Collection fileSystems = this.tskCase.getImageFileSystems(image); checkIfCancelled(); for (FileSystem fileSystem : fileSystems) { - try { - fileSystem.read(tempBuff, 0, 512); - } catch (TskCoreException ex) { - String fileSysStr = fileSystem.getName(); - - logger.log( - Level.WARNING, - String.format("Could not open filesystem: %s in image: %s for case: %s.", fileSysStr, imageStr, caseName), - ex); - } - + fileSystem.read(tempBuff, 0, 512); checkIfCancelled(); } From 474b314d4a202ab5dfc8b8e5c0e930c946651c23 Mon Sep 17 00:00:00 2001 From: apriestman Date: Fri, 8 May 2020 11:39:25 -0400 Subject: [PATCH 30/81] Forgot to return if number of images is over the threshold --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 9ce6b62094..0147f31750 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -2150,6 +2150,7 @@ public class Case { logger.log( Level.INFO, String.format("Skipping background load of file systems due to large number of images in case (%d)", images.size())); + return; } checkIfCancelled(); From 526e5333fae5cc763eaa226aaf306afa7a14eeed Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 8 May 2020 13:28:39 -0400 Subject: [PATCH 31/81] Removed need for PV tags to have CAT prefix --- .../imagegallery/actions/CategorizeAction.java | 11 ----------- .../imagegallery/datamodel/CategoryManager.java | 4 +--- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 13703f417b..6eaddeef9d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -82,7 +82,6 @@ public class CategorizeAction extends Action { this.tagName = tagName; setGraphic(getGraphic(tagName)); setEventHandler(actionEvent -> addCatToFiles(selectedFileIDs)); - setAccelerator(new KeyCodeCombination(KeyCode.getKeyCode(getCategoryNumberFromTagName(tagName)))); } static public Menu getCategoriesMenu(ImageGalleryController controller) { @@ -94,16 +93,6 @@ public class CategorizeAction extends Action { controller.queueDBTask(new CategorizeDrawableFileTask(ids, tagName, createUndo)); } - private String getCategoryNumberFromTagName(TagName tagName) { - String displayName = tagName.getDisplayName(); - if (displayName.contains("CAT")) { - String[] split = displayName.split(":"); - split = split[0].split("-"); - return split[1]; - } - return ""; - } - /** * Instances of this class implement a context menu user interface for * selecting a category diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 5eaf8b4ad7..a77c57b763 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -62,9 +62,7 @@ public class CategoryManager { private static final Logger LOGGER = Logger.getLogger(CategoryManager.class.getName()); /** - * the DrawableDB that backs the category counts cache. The counts are - * initialized from this, and the counting of CAT-0 is always delegated to - * this db. + * the DrawableDB that backs the category counts cache. */ private final DrawableDB drawableDb; From 00833708444f5abd1414eadf881a6ae7a46698f0 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 8 May 2020 14:04:09 -0400 Subject: [PATCH 32/81] Missed CategoryManager chagne --- .../autopsy/imagegallery/datamodel/CategoryManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index a77c57b763..491b10b650 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -38,7 +38,6 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent.DeletedContentTagInfo; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; From 5251ea50ae77abd550fd35c5824988e30745b6af Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 8 May 2020 14:28:41 -0400 Subject: [PATCH 33/81] Fixed getNotableTagDisplayName --- .../casemodule/services/TagsManager.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 49388d619e..7355a8db03 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -146,6 +146,12 @@ public class TagsManager implements Closeable { return tagDisplayNames; } + /** + * Gets the set of display names of notable (TskData.FileKnown.BAD) tag types. + * If a case is not open the list will only include only the user defined + * custom tags. Otherwise the list will include all notable tags. + * @return + */ public static List getNotableTagDisplayNames() { List tagDisplayNames = new ArrayList<>(); for (TagNameDefinition tagDef : TagNameDefinition.getTagNameDefinitions()) { @@ -153,6 +159,22 @@ public class TagsManager implements Closeable { tagDisplayNames.add(tagDef.getDisplayName()); } } + + try { + TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager(); + for (TagName tagName : tagsManager.getAllTagNames()) { + if(tagName.getKnownStatus() == TskData.FileKnown.BAD && + !tagDisplayNames.contains(tagName.getDisplayName())) { + tagDisplayNames.add(tagName.getDisplayName()); + } + } + } catch (NoCurrentCaseException ignored) { + /* + * No current case, nothing more to add to the set. + */ + } catch(TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Faile to get list of TagNams from tagsManager."); + } return tagDisplayNames; } From 0932bf5d68cecb23730eced453032d0caca68f52 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 8 May 2020 14:45:32 -0400 Subject: [PATCH 34/81] Fixed tag warnings --- .../modules/portablecase/PortableCaseReportModule.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java index 046331ca9f..8c88f29f53 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java @@ -65,6 +65,7 @@ import org.sleuthkit.datamodel.Pool; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TaggingManager.ContentTagChange; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskDataException; import org.sleuthkit.datamodel.TskData; @@ -740,13 +741,13 @@ public class PortableCaseReportModule implements ReportModule { if (! oldTagNameToNewTagName.containsKey(tag.getName())) { throw new TskCoreException("TagName map is missing entry for ID " + tag.getName().getId() + " with display name " + tag.getName().getDisplayName()); // NON-NLS } - ContentTag newContentTag = portableSkCase.addContentTag(newIdToContent.get(newFileId), oldTagNameToNewTagName.get(tag.getName()), tag.getComment(), tag.getBeginByteOffset(), tag.getEndByteOffset()); + ContentTagChange newContentTag = portableSkCase.getTaggingManager().addContentTag(newIdToContent.get(newFileId), oldTagNameToNewTagName.get(tag.getName()), tag.getComment(), tag.getBeginByteOffset(), tag.getEndByteOffset()); // Get the image tag data associated with this tag (empty string if there is none) // and save it if present String appData = getImageTagDataForContentTag(tag); if (! appData.isEmpty()) { - addImageTagToPortableCase(newContentTag, appData); + addImageTagToPortableCase(newContentTag.getAddedTag(), appData); } } } @@ -847,7 +848,7 @@ public class PortableCaseReportModule implements ReportModule { if (! oldTagNameToNewTagName.containsKey(tag.getName())) { throw new TskCoreException("TagName map is missing entry for ID " + tag.getName().getId() + " with display name " + tag.getName().getDisplayName()); // NON-NLS } - portableSkCase.addBlackboardArtifactTag(newArtifact, oldTagNameToNewTagName.get(tag.getName()), tag.getComment()); + portableSkCase.getTaggingManager().addArtifactTag(newArtifact, oldTagNameToNewTagName.get(tag.getName()), tag.getComment()); } } From 341f15e8ae3f2941c45762d6dfe0089d6f540550 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Fri, 8 May 2020 14:53:52 -0400 Subject: [PATCH 35/81] Interim checkpoint commit. --- .../contentviewers/ArtifactContentViewer.java | 57 + .../autopsy/contentviewers/Bundle.properties | 15 +- .../contentviewers/Bundle_ja.properties | 9 + .../DefaultArtifactContentViewer.form | 266 +++++ .../DefaultArtifactContentViewer.java | 983 ++++++++++++++++++ .../DummyArtifactContentViewer.form | 85 ++ .../DummyArtifactContentViewer.java | 108 ++ .../autopsy/corecomponents/Bundle.properties | 1 + .../DataContentViewerArtifact.form | 54 +- .../DataContentViewerArtifact.java | 48 +- 10 files changed, 1618 insertions(+), 8 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/ArtifactContentViewer.java create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.form create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ArtifactContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ArtifactContentViewer.java new file mode 100644 index 0000000000..4e3dae286b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ArtifactContentViewer.java @@ -0,0 +1,57 @@ +/* + * 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.contentviewers; + +import java.awt.Component; +import org.sleuthkit.datamodel.BlackboardArtifact; + +/** + * Common interface implemented by artifact viewers. + * + * An artifact viewer displays the artifact in a custom + * layout panel suitable for the artifact type. + * + */ +public interface ArtifactContentViewer { + + /** + * Called to display the contents of the given artifact. + * + * @param artifact the node which is used to obtain and display the + * artifacts. + */ + void setArtifact(BlackboardArtifact artifact); + + /** + * Returns the panel. + * + * @return display panel. + */ + Component getComponent(); + + /** + * Checks whether the given artifact is supported by the viewer. + * + * @param artifact Artifact to check. + * + * @return True if the node can be displayed / processed, else false + */ + boolean isSupported(BlackboardArtifact artifact); + +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index ebc9a58e1a..1064a8e354 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -953,4 +953,17 @@ manager.properties.lafError =\ manager.properties.brokenProperty = Broken default property {0} value: {1} -manager.properties.missingProperty = Missing default property {0} value: {1} \ No newline at end of file +manager.properties.missingProperty = Missing default property {0} value: {1} +DefaultArtifactContentViewer.copyMenuItem.text=Copy +DefaultArtifactContentViewer.prevPageButton.text= +DefaultArtifactContentViewer.pageLabel2.text=Result +DefaultArtifactContentViewer.nextPageButton.text= +DefaultArtifactContentViewer.pageLabel.text=Result: +DefaultArtifactContentViewer.currentPageLabel.text=1 +DefaultArtifactContentViewer.ofLabel.text=of +DefaultArtifactContentViewer.totalPageLabel.text=100 +DefaultArtifactContentViewer.selectAllMenuItem.text=Select All +DummyArtifactContentViewer.jLabel1.text=Artifact Type: +DummyArtifactContentViewer.artifactTypeTextField.text=jTextField1 +DummyArtifactContentViewer.jLabel2.text=Artifact Id: +DummyArtifactContentViewer.artifactIdTextField.text=jTextField1 diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle_ja.properties index f7b7844e60..31e821797d 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle_ja.properties @@ -164,3 +164,12 @@ MediaViewImagePanel.tagsMenu.text_1=\u30bf\u30b0\u30e1\u30cb\u30e5\u30fc SQLiteViewer.readTable.errorText=\u6b21\u306e\u30c6\u30fc\u30d6\u30eb\u306e\u884c\u3092\u53d6\u5f97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {0} # {0} - tableName SQLiteViewer.selectTable.errorText=\u6b21\u306e\u30c6\u30fc\u30d6\u30eb\u306e\u884c\u30ab\u30a6\u30f3\u30c8\u3092\u53d6\u5f97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {0} +DefaultArtifactContentViewer.prevPageButton.text= +DefaultArtifactContentViewer.pageLabel2.text=\u7d50\u679c +DefaultArtifactContentViewer.nextPageButton.text= +DefaultArtifactContentViewer.pageLabel.text=\u7d50\u679c: +DefaultArtifactContentViewer.currentPageLabel.text=1 +DefaultArtifactContentViewer.ofLabel.text=/ +DefaultArtifactContentViewer.totalPageLabel.text=100 +DefaultArtifactContentViewer.selectAllMenuItem.text=\u3059\u3079\u3066\u3092\u9078\u629e +DefaultArtifactContentViewer.copyMenuItem.text=\u30b3\u30d4\u30fc diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form new file mode 100644 index 0000000000..08d2fc0205 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.form @@ -0,0 +1,266 @@ + + +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java new file mode 100644 index 0000000000..b72320c8b9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java @@ -0,0 +1,983 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-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.contentviewers; + +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.datatransfer.StringSelection; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import javax.swing.JMenuItem; +import javax.swing.JTextArea; +import javax.swing.SwingWorker; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.TableColumnModelEvent; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumn; +import javax.swing.event.TableColumnModelListener; +import javax.swing.text.View; +import org.apache.commons.lang.StringUtils; +import org.openide.nodes.Node; +import org.openide.util.Lookup; +import org.openide.util.NbBundle; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskException; +import org.netbeans.swing.etable.ETable; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonArray; +import java.util.Map; + +/** + * Instances of this class display the BlackboardArtifacts associated with the + * Content represented by a Node. Each BlackboardArtifact is rendered displayed + * in a JTable representation of its BlackboardAttributes. + */ +@ServiceProvider(service = DataContentViewer.class, position = 11) +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives +public class DefaultArtifactContentViewer extends javax.swing.JPanel implements DataContentViewer { + + @NbBundle.Messages({ + "DataContentViewerArtifact.attrsTableHeader.type=Type", + "DataContentViewerArtifact.attrsTableHeader.value=Value", + "DataContentViewerArtifact.attrsTableHeader.sources=Source(s)", + "DataContentViewerArtifact.failedToGetSourcePath.message=Failed to get source file path from case database", + "DataContentViewerArtifact.failedToGetAttributes.message=Failed to get some or all attributes from case database" + }) + private final static Logger logger = Logger.getLogger(DefaultArtifactContentViewer.class.getName()); + private final static String WAIT_TEXT = NbBundle.getMessage(DefaultArtifactContentViewer.class, "DataContentViewerArtifact.waitText"); + private final static String ERROR_TEXT = NbBundle.getMessage(DefaultArtifactContentViewer.class, "DataContentViewerArtifact.errorText"); + private Node currentNode; // @@@ Remove this when the redundant setNode() calls problem is fixed. + private int currentPage = 1; + private final Object lock = new Object(); + private List artifactTableContents; // Accessed by multiple threads, use getArtifactContents() and setArtifactContents() + SwingWorker currentTask; // Accessed by multiple threads, use startNewTask() + private static final String[] COLUMN_HEADERS = { + Bundle.DataContentViewerArtifact_attrsTableHeader_type(), + Bundle.DataContentViewerArtifact_attrsTableHeader_value(), + Bundle.DataContentViewerArtifact_attrsTableHeader_sources()}; + private static final int[] COLUMN_WIDTHS = {100, 800, 100}; + private static final int CELL_BOTTOM_MARGIN = 5; + private static final int CELL_RIGHT_MARGIN = 1; + + public DefaultArtifactContentViewer() { + initResultsTable(); + initComponents(); + resultsTableScrollPane.setViewportView(resultsTable); + customizeComponents(); + resetComponents(); + resultsTable.setDefaultRenderer(Object.class, new MultiLineTableCellRenderer()); + } + + private void initResultsTable() { + resultsTable = new ETable(); + resultsTable.setModel(new javax.swing.table.DefaultTableModel() { + private static final long serialVersionUID = 1L; + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + }); + resultsTable.setCellSelectionEnabled(true); + resultsTable.getTableHeader().setReorderingAllowed(false); + resultsTable.setColumnHidingAllowed(false); + resultsTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION); + resultsTable.getColumnModel().addColumnModelListener(new TableColumnModelListener() { + + @Override + public void columnAdded(TableColumnModelEvent e) { + } + + @Override + public void columnRemoved(TableColumnModelEvent e) { + } + + @Override + public void columnMoved(TableColumnModelEvent e) { + + } + + @Override + public void columnMarginChanged(ChangeEvent e) { + updateRowHeights(); //When the user changes column width we may need to resize row height + } + + @Override + public void columnSelectionChanged(ListSelectionEvent e) { + } + }); + resultsTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_NEXT_COLUMN); + + } + + /** + * Sets the row heights to the heights of the content in their Value column. + */ + private void updateRowHeights() { + int valueColIndex = -1; + for (int col = 0; col < resultsTable.getColumnCount(); col++) { + if (resultsTable.getColumnName(col).equals(COLUMN_HEADERS[1])) { + valueColIndex = col; + } + } + if (valueColIndex != -1) { + for (int row = 0; row < resultsTable.getRowCount(); row++) { + Component comp = resultsTable.prepareRenderer( + resultsTable.getCellRenderer(row, valueColIndex), row, valueColIndex); + final int rowHeight; + if (comp instanceof JTextArea) { + final JTextArea tc = (JTextArea) comp; + final View rootView = tc.getUI().getRootView(tc); + java.awt.Insets i = tc.getInsets(); + rootView.setSize(resultsTable.getColumnModel().getColumn(valueColIndex) + .getWidth() - (i.left + i.right +CELL_RIGHT_MARGIN), //current width minus borders + Integer.MAX_VALUE); + rowHeight = (int) rootView.getPreferredSpan(View.Y_AXIS); + } else { + rowHeight = comp.getPreferredSize().height; + } + if (rowHeight > 0) { + resultsTable.setRowHeight(row, rowHeight + CELL_BOTTOM_MARGIN); + } + } + } + } + + /** + * Update the column widths so that the Value column has most of the space. + */ + private void updateColumnSizes() { + Enumeration columns = resultsTable.getColumnModel().getColumns(); + while (columns.hasMoreElements()) { + TableColumn col = columns.nextElement(); + if (col.getHeaderValue().equals(COLUMN_HEADERS[0])) { + col.setPreferredWidth(COLUMN_WIDTHS[0]); + } else if (col.getHeaderValue().equals(COLUMN_HEADERS[1])) { + col.setPreferredWidth(COLUMN_WIDTHS[1]); + } else if (col.getHeaderValue().equals(COLUMN_HEADERS[2])) { + col.setPreferredWidth(COLUMN_WIDTHS[2]); + } + } + } + + /** + * 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() { + java.awt.GridBagConstraints gridBagConstraints; + + rightClickMenu = new javax.swing.JPopupMenu(); + copyMenuItem = new javax.swing.JMenuItem(); + selectAllMenuItem = new javax.swing.JMenuItem(); + jScrollPane1 = new javax.swing.JScrollPane(); + jPanel1 = new javax.swing.JPanel(); + totalPageLabel = new javax.swing.JLabel(); + ofLabel = new javax.swing.JLabel(); + currentPageLabel = new javax.swing.JLabel(); + pageLabel = new javax.swing.JLabel(); + nextPageButton = new javax.swing.JButton(); + pageLabel2 = new javax.swing.JLabel(); + prevPageButton = new javax.swing.JButton(); + artifactLabel = new javax.swing.JLabel(); + filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); + resultsTableScrollPane = new javax.swing.JScrollPane(); + + copyMenuItem.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.copyMenuItem.text")); // NOI18N + rightClickMenu.add(copyMenuItem); + + selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.selectAllMenuItem.text")); // NOI18N + rightClickMenu.add(selectAllMenuItem); + + setPreferredSize(new java.awt.Dimension(100, 58)); + + jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); + + jPanel1.setPreferredSize(new java.awt.Dimension(620, 58)); + jPanel1.setLayout(new java.awt.GridBagLayout()); + + totalPageLabel.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.totalPageLabel.text")); // NOI18N + totalPageLabel.setMaximumSize(new java.awt.Dimension(40, 16)); + totalPageLabel.setPreferredSize(new java.awt.Dimension(25, 16)); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 3; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0); + jPanel1.add(totalPageLabel, gridBagConstraints); + + ofLabel.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.ofLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 2; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0); + jPanel1.add(ofLabel, gridBagConstraints); + + currentPageLabel.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.currentPageLabel.text")); // NOI18N + currentPageLabel.setMaximumSize(new java.awt.Dimension(38, 14)); + currentPageLabel.setMinimumSize(new java.awt.Dimension(18, 14)); + currentPageLabel.setPreferredSize(new java.awt.Dimension(20, 14)); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(4, 7, 0, 0); + jPanel1.add(currentPageLabel, gridBagConstraints); + + pageLabel.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.pageLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(3, 12, 0, 0); + jPanel1.add(pageLabel, gridBagConstraints); + + nextPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N + nextPageButton.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.nextPageButton.text")); // NOI18N + nextPageButton.setBorderPainted(false); + nextPageButton.setContentAreaFilled(false); + nextPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N + nextPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0)); + nextPageButton.setPreferredSize(new java.awt.Dimension(23, 23)); + nextPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N + nextPageButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + nextPageButtonActionPerformed(evt); + } + }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 6; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 35, 0); + jPanel1.add(nextPageButton, gridBagConstraints); + + pageLabel2.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.pageLabel2.text")); // NOI18N + pageLabel2.setMaximumSize(new java.awt.Dimension(29, 14)); + pageLabel2.setMinimumSize(new java.awt.Dimension(29, 14)); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 4; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(3, 41, 0, 0); + jPanel1.add(pageLabel2, gridBagConstraints); + + prevPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N + prevPageButton.setText(org.openide.util.NbBundle.getMessage(DefaultArtifactContentViewer.class, "DefaultArtifactContentViewer.prevPageButton.text")); // NOI18N + prevPageButton.setBorderPainted(false); + prevPageButton.setContentAreaFilled(false); + prevPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N + prevPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0)); + prevPageButton.setPreferredSize(new java.awt.Dimension(23, 23)); + prevPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N + prevPageButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + prevPageButtonActionPerformed(evt); + } + }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 5; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(0, 5, 35, 0); + jPanel1.add(prevPageButton, gridBagConstraints); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 8; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; + gridBagConstraints.insets = new java.awt.Insets(3, 0, 0, 8); + jPanel1.add(artifactLabel, gridBagConstraints); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 7; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.weightx = 0.1; + jPanel1.add(filler1, gridBagConstraints); + + jScrollPane1.setViewportView(jPanel1); + + resultsTableScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); + resultsTableScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); + resultsTableScrollPane.setPreferredSize(new java.awt.Dimension(620, 34)); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1) + .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed + currentPage = currentPage + 1; + currentPageLabel.setText(Integer.toString(currentPage)); + artifactLabel.setText(artifactTableContents.get(currentPage - 1).getArtifactDisplayName()); + startNewTask(new SelectedArtifactChangedTask(currentPage)); + }//GEN-LAST:event_nextPageButtonActionPerformed + + private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed + currentPage = currentPage - 1; + currentPageLabel.setText(Integer.toString(currentPage)); + artifactLabel.setText(artifactTableContents.get(currentPage - 1).getArtifactDisplayName()); + startNewTask(new SelectedArtifactChangedTask(currentPage)); + }//GEN-LAST:event_prevPageButtonActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel artifactLabel; + private javax.swing.JMenuItem copyMenuItem; + private javax.swing.JLabel currentPageLabel; + private javax.swing.Box.Filler filler1; + private javax.swing.JPanel jPanel1; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JButton nextPageButton; + private javax.swing.JLabel ofLabel; + private javax.swing.JLabel pageLabel; + private javax.swing.JLabel pageLabel2; + private javax.swing.JButton prevPageButton; + private javax.swing.JScrollPane resultsTableScrollPane; + private javax.swing.JPopupMenu rightClickMenu; + private javax.swing.JMenuItem selectAllMenuItem; + private javax.swing.JLabel totalPageLabel; + // End of variables declaration//GEN-END:variables + private ETable resultsTable; + + private void customizeComponents() { + resultsTable.setComponentPopupMenu(rightClickMenu); + ActionListener actList = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + JMenuItem jmi = (JMenuItem) e.getSource(); + if (jmi.equals(copyMenuItem)) { + StringBuilder selectedText = new StringBuilder(512); + for (int row : resultsTable.getSelectedRows()) { + for (int col : resultsTable.getSelectedColumns()) { + selectedText.append((String) resultsTable.getValueAt(row, col)); + selectedText.append("\t"); + } + //if its the last row selected don't add a new line + if (row != resultsTable.getSelectedRows()[resultsTable.getSelectedRows().length - 1]) { + selectedText.append(System.lineSeparator()); + } + } + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(selectedText.toString()), null); + } else if (jmi.equals(selectAllMenuItem)) { + resultsTable.selectAll(); + } + } + }; + copyMenuItem.addActionListener(actList); + + selectAllMenuItem.addActionListener(actList); + } + + /** + * Resets the components to an empty view state. + */ + private void resetComponents() { + currentPage = 1; + currentPageLabel.setText(""); + artifactLabel.setText(""); + totalPageLabel.setText(""); + ((DefaultTableModel) resultsTable.getModel()).setRowCount(0); + prevPageButton.setEnabled(false); + nextPageButton.setEnabled(false); + currentNode = null; + } + + @Override + public void setNode(Node selectedNode) { + if (currentNode == selectedNode) { + return; + } + currentNode = selectedNode; + + // Make sure there is a node. Null might be passed to reset the viewer. + if (selectedNode == null) { + return; + } + + // Make sure the node is of the correct type. + Lookup lookup = selectedNode.getLookup(); + Content content = lookup.lookup(Content.class); + if (content == null) { + return; + } + + startNewTask(new SelectedNodeChangedTask(selectedNode)); + } + + @Override + public String getTitle() { + return NbBundle.getMessage(this.getClass(), "DataContentViewerArtifact.title"); + } + + @Override + public String getToolTip() { + return NbBundle.getMessage(this.getClass(), "DataContentViewerArtifact.toolTip"); + } + + @Override + public DataContentViewer createInstance() { + return new DefaultArtifactContentViewer(); + } + + @Override + public Component getComponent() { + return this; + } + + @Override + public void resetComponent() { + resetComponents(); + } + + @Override + public boolean isSupported(Node node) { + if (node == null) { + return false; + } + + for (Content content : node.getLookup().lookupAll(Content.class)) { + if ( (content != null) && (!(content instanceof BlackboardArtifact)) ){ + try { + return content.getAllArtifactsCount() > 0; + } catch (TskException ex) { + logger.log(Level.SEVERE, "Couldn't get count of BlackboardArtifacts for content", ex); //NON-NLS + } + } + } + return false; + } + + @Override + public int isPreferred(Node node) { + BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class); + // low priority if node doesn't have an artifact (meaning it was found from normal directory + // browsing, or if the artifact is something that means the user really wants to see the original + // file and not more details about the artifact + if ((artifact == null) + || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) + || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) + || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()) + || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID()) + || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) + || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID())) { + return 3; + } else { + return 6; + } + } + + /** + * This class is a container to hold the data necessary for each of the + * result pages associated with file or artifact beivng viewed. + */ + private class ResultsTableArtifact { + + private final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private String[][] rowData = null; + private final String artifactDisplayName; + private final Content content; + + ResultsTableArtifact(BlackboardArtifact artifact, Content content) { + artifactDisplayName = artifact.getDisplayName(); + this.content = content; + addRows(artifact); + } + + ResultsTableArtifact(String errorMsg) { + artifactDisplayName = errorMsg; + rowData = new String[1][3]; + rowData[0] = new String[]{"", errorMsg, ""}; + content = null; + } + + private String[][] getRows() { + return rowData; + } + + private void addRows(BlackboardArtifact artifact) { + List rowsToAdd = new ArrayList<>(); + try { + /* + * Add rows for each attribute. + */ + for (BlackboardAttribute attr : artifact.getAttributes()) { + /* + * Attribute value column. + */ + String value = ""; + switch (attr.getAttributeType().getValueType()) { + case STRING: + case INTEGER: + case LONG: + case DOUBLE: + case BYTE: + default: + value = attr.getDisplayString(); + break; + // Use Autopsy date formatting settings, not TSK defaults + case DATETIME: + value = epochTimeToString(attr.getValueLong()); + break; + case JSON: + // Get the attribute's JSON value and convert to indented multiline display string + String jsonVal = attr.getValueString(); + JsonParser parser = new JsonParser(); + JsonObject json = parser.parse(jsonVal).getAsJsonObject(); + + value = toJsonDisplayString(json, ""); + break; + } + /* + * Attribute sources column. + */ + String sources = StringUtils.join(attr.getSources(), ", "); + rowsToAdd.add(new String[]{attr.getAttributeType().getDisplayName(), value, sources}); + } + /* + * Add a row for the source content path. + */ + String path = ""; + try { + if (null != content) { + path = content.getUniquePath(); + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error getting source content path for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex); + path = Bundle.DataContentViewerArtifact_failedToGetSourcePath_message(); + } + rowsToAdd.add(new String[]{"Source File Path", path, ""}); + /* + * Add a row for the artifact id. + */ + rowsToAdd.add(new String[]{"Artifact ID", Long.toString(artifact.getArtifactID()), ""}); + } catch (TskCoreException ex) { + rowsToAdd.add(new String[]{"", Bundle.DataContentViewerArtifact_failedToGetAttributes_message(), ""}); + } + rowData = rowsToAdd.toArray(new String[0][0]); + } + + /** + * @return the artifactDisplayName + */ + String getArtifactDisplayName() { + return artifactDisplayName; + } + + private static final String INDENT_RIGHT = " "; + private static final String NEW_LINE = "\n"; + + /** + * Recursively converts a JSON element into an indented multi-line + * display string. + * + * @param element JSON element to convert + * @param startIndent Starting indentation for the element. + * + * @return A multi-line display string. + */ + private String toJsonDisplayString(JsonElement element, String startIndent) { + + StringBuilder sb = new StringBuilder(""); + JsonObject obj = element.getAsJsonObject(); + + for (Map.Entry entry : obj.entrySet()) { + appendJsonElementToString(entry.getKey(), entry.getValue(), startIndent, sb ); + } + + String returnString = sb.toString(); + if (startIndent.length() == 0 && returnString.startsWith(NEW_LINE)) { + returnString = returnString.substring(NEW_LINE.length()); + } + return returnString; + } + + + /** + * Converts the given JSON element into string and appends to the given string builder. + * + * @param jsonKey + * @param jsonElement + * @param startIndent Starting indentation for the element. + * @param sb String builder to append to. + */ + private void appendJsonElementToString(String jsonKey, JsonElement jsonElement, String startIndent, StringBuilder sb) { + if (jsonElement.isJsonArray()) { + JsonArray jsonArray = jsonElement.getAsJsonArray(); + if (jsonArray.size() > 0) { + int count = 1; + sb.append(NEW_LINE).append(String.format("%s%s", startIndent, jsonKey)); + for (JsonElement arrayMember : jsonArray) { + sb.append(NEW_LINE).append(String.format("%s%d", startIndent.concat(INDENT_RIGHT), count)); + sb.append(toJsonDisplayString(arrayMember, startIndent.concat(INDENT_RIGHT).concat(INDENT_RIGHT))); + count++; + } + } + } else if (jsonElement.isJsonObject()) { + sb.append(NEW_LINE).append(String.format("%s%s %s", startIndent, jsonKey, toJsonDisplayString(jsonElement.getAsJsonObject(), startIndent + INDENT_RIGHT))); + } else if (jsonElement.isJsonPrimitive()) { + String attributeName = jsonKey; + String attributeValue; + if (attributeName.toUpperCase().contains("DATETIME")) { + attributeValue = epochTimeToString(Long.parseLong(jsonElement.getAsString())); + } else { + attributeValue = jsonElement.getAsString(); + } + sb.append(NEW_LINE).append(String.format("%s%s = %s", startIndent, attributeName, attributeValue)); + } else if (jsonElement.isJsonNull()) { + sb.append(NEW_LINE).append(String.format("%s%s = null", startIndent, jsonKey)); + } + } + + /** + * Converts epoch time to readable string. + * + * @param epochTime epoch time value to be converted to string. + * @return String with human readable time. + */ + private String epochTimeToString(long epochTime) { + String dateTimeString = "0000-00-00 00:00:00"; + if (null != content && 0 != epochTime) { + dateFormatter.setTimeZone(ContentUtils.getTimeZone(content)); + dateTimeString = dateFormatter.format(new java.util.Date(epochTime * 1000)); + } + return dateTimeString; + } + + } + + /** + * Instances of this class are simple containers for view update information + * generated by a background thread. + */ + private class ViewUpdate { + + int numberOfPages; + int currentPage; + ResultsTableArtifact tableContents; + + ViewUpdate(int numberOfPages, int currentPage, ResultsTableArtifact contents) { + this.currentPage = currentPage; + this.numberOfPages = numberOfPages; + this.tableContents = contents; + } + + ViewUpdate(int numberOfPages, int currentPage, String errorMsg) { + this.currentPage = currentPage; + this.numberOfPages = numberOfPages; + this.tableContents = new ResultsTableArtifact(errorMsg); + } + } + + /** + * Called from queued SwingWorker done() methods on the EDT thread, so + * doesn't need to be synchronized. + * + * @param viewUpdate A simple container for display update information from + * a background thread. + */ + private void updateView(ViewUpdate viewUpdate) { + this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + nextPageButton.setEnabled(viewUpdate.currentPage < viewUpdate.numberOfPages); + prevPageButton.setEnabled(viewUpdate.currentPage > 1); + currentPage = viewUpdate.currentPage; + totalPageLabel.setText(Integer.toString(viewUpdate.numberOfPages)); + currentPageLabel.setText(Integer.toString(currentPage)); + artifactLabel.setText(viewUpdate.tableContents.getArtifactDisplayName()); + DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel()); + tModel.setDataVector(viewUpdate.tableContents.getRows(), COLUMN_HEADERS); + updateColumnSizes(); + updateRowHeights(); + resultsTable.clearSelection(); + + this.setCursor(null); + } + + /** + * Start a new task on its own background thread, canceling the previous + * task. + * + * @param task A new SwingWorker object to execute as a background thread. + */ + private synchronized void startNewTask(SwingWorker task) { + String[][] waitRow = new String[1][3]; + waitRow[0] = new String[]{"", WAIT_TEXT, ""}; + DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel()); + tModel.setDataVector(waitRow, COLUMN_HEADERS); + updateColumnSizes(); + updateRowHeights(); + resultsTable.clearSelection(); + // The output of the previous task is no longer relevant. + if (currentTask != null) { + // This call sets a cancellation flag. It does not terminate the background thread running the task. + // The task must check the cancellation flag and react appropriately. + currentTask.cancel(false); + } + + // Start the new task. + currentTask = task; + currentTask.execute(); + } + + /** + * Populate the cache of artifact represented as ResultsTableArtifacts. + * + * @param artifactList A list of ResultsTableArtifact representations of + * artifacts. + */ + private void setArtifactContents(List artifactList) { + synchronized (lock) { + this.artifactTableContents = artifactList; + } + } + + /** + * Retrieve the cache of artifact represented as ResultsTableArtifacts. + * + * @return A list of ResultsTableArtifact representations of artifacts. + */ + private List getArtifactContents() { + synchronized (lock) { + return artifactTableContents; + } + } + + /** + * Instances of this class use a background thread to generate a ViewUpdate + * when a node is selected, changing the set of blackboard artifacts + * ("results") to be displayed. + */ + private class SelectedNodeChangedTask extends SwingWorker { + + private final Node selectedNode; + + SelectedNodeChangedTask(Node selectedNode) { + this.selectedNode = selectedNode; + } + + @Override + protected ViewUpdate doInBackground() { + // Get the lookup for the node for access to its underlying content and + // blackboard artifact, if any. + Lookup lookup = selectedNode.getLookup(); + + // Get the content. We may get BlackboardArtifacts, ignore those here. + ArrayList artifacts = new ArrayList<>(); + Collection contents = lookup.lookupAll(Content.class); + if (contents.isEmpty()) { + return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT); + } + Content underlyingContent = null; + for (Content content : contents) { + if ( (content != null) && (!(content instanceof BlackboardArtifact)) ) { + // Get all of the blackboard artifacts associated with the content. These are what this + // viewer displays. + try { + artifacts = content.getAllArtifacts(); + underlyingContent = content; + break; + } catch (TskException ex) { + logger.log(Level.SEVERE, "Couldn't get artifacts", ex); //NON-NLS + return new ViewUpdate(getArtifactContents().size(), currentPage, ERROR_TEXT); + } + } + } + + if (isCancelled()) { + return null; + } + + // Build the new artifact contents cache. + ArrayList artifactContents = new ArrayList<>(); + for (BlackboardArtifact artifact : artifacts) { + artifactContents.add(new ResultsTableArtifact(artifact, underlyingContent)); + } + + // If the node has an underlying blackboard artifact, show it. If not, + // show the first artifact. + int index = 0; + BlackboardArtifact artifact = lookup.lookup(BlackboardArtifact.class); + if (artifact != null) { + index = artifacts.indexOf(artifact); + if (index == -1) { + index = 0; + } else { + // if the artifact has an ASSOCIATED ARTIFACT, then we display the associated artifact instead + try { + for (BlackboardAttribute attr : artifact.getAttributes()) { + if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) { + long assocArtifactId = attr.getValueLong(); + int assocArtifactIndex = -1; + for (BlackboardArtifact art : artifacts) { + if (assocArtifactId == art.getArtifactID()) { + assocArtifactIndex = artifacts.indexOf(art); + break; + } + } + if (assocArtifactIndex >= 0) { + index = assocArtifactIndex; + } + break; + } + } + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Couldn't get associated artifact to display in Content Viewer.", ex); //NON-NLS + } + } + + } + + if (isCancelled()) { + return null; + } + + // Add one to the index of the artifact content for the corresponding page index. + ViewUpdate viewUpdate = new ViewUpdate(artifactContents.size(), index + 1, artifactContents.get(index)); + + // It may take a considerable amount of time to fetch the attributes of the selected artifact + if (isCancelled()) { + return null; + } + + // Update the artifact contents cache. + setArtifactContents(artifactContents); + + return viewUpdate; + } + + @Override + protected void done() { + if (!isCancelled()) { + try { + ViewUpdate viewUpdate = get(); + if (viewUpdate != null) { + updateView(viewUpdate); + } + } catch (InterruptedException | ExecutionException ex) { + logger.log(Level.WARNING, "Artifact display task unexpectedly interrupted or failed", ex); //NON-NLS + } + } + } + } + + /** + * Instances of this class use a background thread to generate a ViewUpdate + * when the user pages the view to look at another blackboard artifact + * ("result"). + */ + private class SelectedArtifactChangedTask extends SwingWorker { + + private final int pageIndex; + + SelectedArtifactChangedTask(final int pageIndex) { + this.pageIndex = pageIndex; + } + + @Override + protected ViewUpdate doInBackground() { + // Get the artifact content to display from the cache. Note that one must be subtracted from the + // page index to get the corresponding artifact content index. + List artifactContents = getArtifactContents(); + ResultsTableArtifact artifactContent = artifactContents.get(pageIndex - 1); + + // It may take a considerable amount of time to fetch the attributes of the selected artifact so check for cancellation. + if (isCancelled()) { + return null; + } + + return new ViewUpdate(artifactContents.size(), pageIndex, artifactContent); + } + + @Override + protected void done() { + if (!isCancelled()) { + try { + ViewUpdate viewUpdate = get(); + if (viewUpdate != null) { + updateView(viewUpdate); + } + } catch (InterruptedException | ExecutionException ex) { + logger.log(Level.WARNING, "Artifact display task unexpectedly interrupted or failed", ex); //NON-NLS + } + } + } + } + + /** + * TableCellRenderer for displaying multiline text. + */ + private class MultiLineTableCellRenderer implements javax.swing.table.TableCellRenderer { + + @Override + public Component getTableCellRendererComponent(javax.swing.JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + javax.swing.JTextArea jtex = new javax.swing.JTextArea(); + if (value instanceof String) { + jtex.setText((String) value); + jtex.setLineWrap(true); + jtex.setWrapStyleWord(false); + } + //cell backgroud color when selected + if (isSelected) { + jtex.setBackground(javax.swing.UIManager.getColor("Table.selectionBackground")); + } else { + jtex.setBackground(javax.swing.UIManager.getColor("Table.background")); + } + return jtex; + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.form new file mode 100644 index 0000000000..b7cef5505b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.form @@ -0,0 +1,85 @@ + + +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.java new file mode 100644 index 0000000000..edc793f98b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DummyArtifactContentViewer.java @@ -0,0 +1,108 @@ +/* + * 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.contentviewers; + +import java.awt.Component; +import org.sleuthkit.datamodel.BlackboardArtifact; + +/** + * + * @author raman + */ +public class DummyArtifactContentViewer extends javax.swing.JPanel implements ArtifactContentViewer { + + /** + * Creates new form DummyArtifactContentViewer + */ + public DummyArtifactContentViewer() { + initComponents(); + } + + /** + * 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() { + + jLabel1 = new javax.swing.JLabel(); + artifactTypeTextField = new javax.swing.JTextField(); + jLabel2 = new javax.swing.JLabel(); + artifactIdTextField = new javax.swing.JTextField(); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(DummyArtifactContentViewer.class, "DummyArtifactContentViewer.jLabel1.text")); // NOI18N + + artifactTypeTextField.setText(org.openide.util.NbBundle.getMessage(DummyArtifactContentViewer.class, "DummyArtifactContentViewer.artifactTypeTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(DummyArtifactContentViewer.class, "DummyArtifactContentViewer.jLabel2.text")); // NOI18N + + artifactIdTextField.setText(org.openide.util.NbBundle.getMessage(DummyArtifactContentViewer.class, "DummyArtifactContentViewer.artifactIdTextField.text")); // NOI18N + artifactIdTextField.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + artifactIdTextFieldActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel1) + .addComponent(jLabel2)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(artifactTypeTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 133, Short.MAX_VALUE) + .addComponent(artifactIdTextField)) + .addContainerGap(165, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(16, 16, 16) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel1) + .addComponent(artifactTypeTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel2) + .addComponent(artifactIdTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(218, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void artifactIdTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_artifactIdTextFieldActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_artifactIdTextFieldActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JTextField artifactIdTextField; + private javax.swing.JTextField artifactTypeTextField; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + // End of variables declaration//GEN-END:variables + + @Override + public void setArtifact(BlackboardArtifact artifact) { + artifactTypeTextField.setText(artifact.getArtifactTypeName()); + artifactIdTextField.setText(String.format("%d", artifact.getId())); + } + + @Override + public Component getComponent() { + return this; + } + + @Override + public boolean isSupported(BlackboardArtifact artifact) { + return true; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 4571bcc3df..4eb87c3496 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -218,3 +218,4 @@ DataResultViewerTable.exportCSVButton.text=Save Table as CSV ViewPreferencesPanel.scoColumnsCheckbox.text=S(core), C(omments), and O(ccurences) ViewPreferencesPanel.scoColumnsWrapAroundText.text=to reduce loading times ViewPreferencesPanel.scoColumnsLabel.text=Do not add columns for: +DataContentViewerArtifact.jLabel1.text=Artifact Content View diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form index 5827ce617f..52207ebf35 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form @@ -1,6 +1,6 @@ -
        + @@ -45,8 +45,14 @@ - - + + + + + + + + @@ -54,7 +60,11 @@ - + + + + + @@ -262,5 +272,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java index 78ccd6e4ec..a5779005a8 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java @@ -61,6 +61,8 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonArray; import java.util.Map; +import org.sleuthkit.autopsy.contentviewers.ArtifactContentViewer; +import org.sleuthkit.autopsy.contentviewers.DummyArtifactContentViewer; /** * Instances of this class display the BlackboardArtifacts associated with the @@ -219,6 +221,8 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat artifactLabel = new javax.swing.JLabel(); filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); resultsTableScrollPane = new javax.swing.JScrollPane(); + jLabel1 = new javax.swing.JLabel(); + artifactContentPanel = new javax.swing.JPanel(); copyMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.copyMenuItem.text")); // NOI18N rightClickMenu.add(copyMenuItem); @@ -345,19 +349,32 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat resultsTableScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); resultsTableScrollPane.setPreferredSize(new java.awt.Dimension(620, 34)); + jLabel1.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.jLabel1.text")); // NOI18N + + artifactContentPanel.setLayout(new javax.swing.OverlayLayout(artifactContentPanel)); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1) - .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 476, Short.MAX_VALUE) + .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 476, Short.MAX_VALUE) + .addComponent(artifactContentPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGap(166, 166, 166) + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 129, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(artifactContentPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 134, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -376,10 +393,12 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat }//GEN-LAST:event_prevPageButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel artifactContentPanel; private javax.swing.JLabel artifactLabel; private javax.swing.JMenuItem copyMenuItem; private javax.swing.JLabel currentPageLabel; private javax.swing.Box.Filler filler1; + private javax.swing.JLabel jLabel1; private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JButton nextPageButton; @@ -521,6 +540,11 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat } } + private ArtifactContentViewer getArtifactViewer(BlackboardArtifact artifact) { + + return new DummyArtifactContentViewer(); + + } /** * This class is a container to hold the data necessary for each of the * result pages associated with file or artifact beivng viewed. @@ -531,10 +555,12 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat private String[][] rowData = null; private final String artifactDisplayName; private final Content content; + private final BlackboardArtifact artifact; ResultsTableArtifact(BlackboardArtifact artifact, Content content) { artifactDisplayName = artifact.getDisplayName(); this.content = content; + this.artifact = artifact; addRows(artifact); } @@ -543,12 +569,17 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat rowData = new String[1][3]; rowData[0] = new String[]{"", errorMsg, ""}; content = null; + artifact = null; } private String[][] getRows() { return rowData; } + BlackboardArtifact getArtifact() { + return this.artifact; + } + private void addRows(BlackboardArtifact artifact) { List rowsToAdd = new ArrayList<>(); try { @@ -618,6 +649,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat return artifactDisplayName; } + private static final String INDENT_RIGHT = " "; private static final String NEW_LINE = "\n"; @@ -745,7 +777,17 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat updateRowHeights(); resultsTable.clearSelection(); + BlackboardArtifact artifact = viewUpdate.tableContents.getArtifact(); + ArtifactContentViewer viewer = this.getArtifactViewer(artifact); + viewer.setArtifact(artifact); + + artifactContentPanel.removeAll(); + artifactContentPanel.add(viewer.getComponent()); + artifactContentPanel.revalidate(); + this.setCursor(null); + + this.revalidate(); } /** From 474a1cbede89ce273ca395a756860bab9eeed421 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 8 May 2020 15:41:34 -0400 Subject: [PATCH 36/81] finishing comments and some rough edges --- .../AnnotationsContentViewer.java | 387 ++++++++++++------ 1 file changed, 260 insertions(+), 127 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index bc8ef25642..7884f1a630 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -21,15 +21,14 @@ package org.sleuthkit.autopsy.contentviewers; import java.awt.Component; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.function.Function; import java.util.logging.Level; import java.util.stream.Collectors; import javax.swing.JLabel; +import javax.swing.text.EditorKit; +import javax.swing.text.html.HTMLEditorKit; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang3.StringEscapeUtils; import static org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; @@ -72,7 +71,7 @@ import org.jsoup.nodes.Element; "AnnotationsContentViewer.centralRepositoryEntryDataLabel.type=Type:", "AnnotationsContentViewer.centralRepositoryEntryDataLabel.comment=Comment:", "AnnotationsContentViewer.centralRepositoryEntryDataLabel.path=Path:", - "AnnotationsContentViewer.tagEntry.title=Tag Comments", + "AnnotationsContentViewer.tagEntry.title=Tags", "AnnotationsContentViewer.tagEntry.onContentEmpty=There are no tags for the selected content.", "AnnotationsContentViewer.tagEntry.onArtifactEmpty=There are no tags for the selected artifact.", "AnnotationsContentViewer.tagEntryDataLabel.tag=Tag:", @@ -88,60 +87,18 @@ import org.jsoup.nodes.Element; }) public class AnnotationsContentViewer extends javax.swing.JPanel implements DataContentViewer { - private static final Logger logger = Logger.getLogger(AnnotationsContentViewer.class.getName()); + private static class ItemEntry { - private static final String EMPTY_HTML = ""; - - private static final int DEFAULT_FONT_SIZE = new JLabel().getFont().getSize(); - private static final int SUBHEADER_FONT_SIZE = DEFAULT_FONT_SIZE * 12 / 11; - private static final int HEADER_FONT_SIZE = DEFAULT_FONT_SIZE * 14 / 11; - - private static final int DEFAULT_SUBSECTION_LEFT_PAD = DEFAULT_FONT_SIZE; - - private static final String HEADER_STYLE = "font-size:" + HEADER_FONT_SIZE + "px;font-weight:bold;"; - private static final String SUBHEADER_STYLE = "font-size:" + SUBHEADER_FONT_SIZE + "px;font-weight:bold;"; - private static final String MESSAGE_STYLE = "font-size:" + DEFAULT_FONT_SIZE + "px;font-style:italic;"; - private static final String CONTENT_STYLE = "font-size:" + DEFAULT_FONT_SIZE + "px;"; - - private static final int DEFAULT_TABLE_SPACING = DEFAULT_FONT_SIZE * 2; - private static final int DEFAULT_SECTION_SPACING = DEFAULT_FONT_SIZE; - private static final int DEFAULT_SUBSECTION_SPACING = DEFAULT_FONT_SIZE; - - private static final List> TAG_COLUMNS = Arrays.asList( - new ColumnEntry<>(Bundle.AnnotationsContentViewer_tagEntryDataLabel_tag(), - (tag) -> (tag.getName() != null) ? tag.getName().getDisplayName() : null), - new ColumnEntry<>(Bundle.AnnotationsContentViewer_tagEntryDataLabel_tagUser(), (tag) -> tag.getUserName()), - new ColumnEntry<>(Bundle.AnnotationsContentViewer_tagEntryDataLabel_comment(), (tag) -> tag.getComment()) - ); - - private static final List> FILESET_HIT_COLUMNS = Arrays.asList( - new ColumnEntry<>(Bundle.AnnotationsContentViewer_fileHitEntry_setName(), - (bba) -> tryGetAttribute(bba, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)), - new ColumnEntry<>(Bundle.AnnotationsContentViewer_fileHitEntry_comment(), - (bba) -> tryGetAttribute(bba, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT)) - ); - - private static final List> CENTRAL_REPO_COMMENTS_COLUMNS = Arrays.asList( - new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_case(), - cai -> (cai.getCorrelationCase() != null) ? cai.getCorrelationCase().getDisplayName() : null), - new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_type(), - cai -> (cai.getCorrelationType() != null) ? cai.getCorrelationType().getDisplayName() : null), - new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_comment(), cai -> cai.getComment()), - new ColumnEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_path(), cai -> cai.getFilePath()) - ); - - private static class ColumnEntry { - - private final String columnName; + private final String itemName; private final Function valueRetriever; - ColumnEntry(String columnName, Function valueRetriever) { - this.columnName = columnName; + ItemEntry(String itemName, Function valueRetriever) { + this.itemName = itemName; this.valueRetriever = valueRetriever; } - String getColumnName() { - return columnName; + String getItemName() { + return itemName; } Function getValueRetriever() { @@ -153,12 +110,140 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data } } + private static class SectionConfig { + + private final String title; + private final String onEmpty; + private final List> attributes; + private final boolean isVerticalTable; + + SectionConfig(String title, String onEmpty, List> attributes, boolean isVerticalTable) { + this.title = title; + this.onEmpty = onEmpty; + this.attributes = attributes; + this.isVerticalTable = isVerticalTable; + } + + String getTitle() { + return title; + } + + String getOnEmpty() { + return onEmpty; + } + + List> getAttributes() { + return attributes; + } + + boolean isIsVerticalTable() { + return isVerticalTable; + } + } + + private static final Logger logger = Logger.getLogger(AnnotationsContentViewer.class.getName()); + + private static final String EMPTY_HTML = ""; + + private static final int DEFAULT_FONT_SIZE = new JLabel().getFont().getSize(); + + // how big the subheader should be + private static final int SUBHEADER_FONT_SIZE = DEFAULT_FONT_SIZE * 12 / 11; + + // how big the header should be + private static final int HEADER_FONT_SIZE = DEFAULT_FONT_SIZE * 14 / 11; + + // the subsection indent + private static final int DEFAULT_SUBSECTION_LEFT_PAD = DEFAULT_FONT_SIZE; + + // spacing occurring after an item + private static final int DEFAULT_TABLE_SPACING = DEFAULT_FONT_SIZE; + private static final int DEFAULT_SECTION_SPACING = DEFAULT_FONT_SIZE * 2; + private static final int DEFAULT_SUBSECTION_SPACING = DEFAULT_FONT_SIZE / 2; + private static final int CELL_SPACING = DEFAULT_FONT_SIZE / 2; + + // html stylesheet classnames for components + private static final String MESSAGE_CLASSNAME = "message"; + private static final String SUBSECTION_CLASSNAME = "subsection"; + private static final String SUBHEADER_CLASSNAME = "subheader"; + private static final String SECTION_CLASSNAME = "section"; + private static final String HEADER_CLASSNAME = "header"; + private static final String ENTRY_TABLE_CLASSNAME = "entry-table"; + private static final String VERTICAL_TABLE_CLASSNAME = "vertical-table"; + + // additional styling for components + private static final String STYLE_SHEET_RULE + = String.format(" .%s { font-size: %dpx;font-style:italic; margin: 0px; padding: 0px; } ", MESSAGE_CLASSNAME, DEFAULT_FONT_SIZE) + + String.format(" .%s {font-size:%dpx;font-weight:bold; margin: 0px; margin-top: %dpx; padding: 0px; } ", SUBHEADER_CLASSNAME, SUBHEADER_FONT_SIZE, DEFAULT_SUBSECTION_SPACING) + + String.format(" .%s { font-size:%dpx;font-weight:bold; margin: 0px; padding: 0px; } ", HEADER_CLASSNAME, HEADER_FONT_SIZE) + + String.format(" td { vertical-align: top; font-size:%dpx; text-align: left; margin: 0px; padding: 0px %dpx 0px 0px;} ", DEFAULT_FONT_SIZE, CELL_SPACING) + + String.format(" th { vertical-align: top; text-align: left; margin: 0px; padding: 0px %dpx 0px 0px} ", DEFAULT_FONT_SIZE, CELL_SPACING) + + String.format(" .%s { margin: %dpx 0px; padding-left: %dpx; } ", SUBSECTION_CLASSNAME, DEFAULT_SUBSECTION_SPACING, DEFAULT_SUBSECTION_LEFT_PAD) + + String.format(" .%s { margin-bottom: %dpx; } ", SECTION_CLASSNAME, DEFAULT_SECTION_SPACING); + + // describing table values for a tag + private static final List> TAG_ENTRIES = Arrays.asList( + new ItemEntry<>(Bundle.AnnotationsContentViewer_tagEntryDataLabel_tag(), + (tag) -> (tag.getName() != null) ? tag.getName().getDisplayName() : null), + new ItemEntry<>(Bundle.AnnotationsContentViewer_tagEntryDataLabel_tagUser(), (tag) -> tag.getUserName()), + new ItemEntry<>(Bundle.AnnotationsContentViewer_tagEntryDataLabel_comment(), (tag) -> tag.getComment()) + ); + + private static final SectionConfig ARTIFACT_TAG_CONFIG = new SectionConfig<>( + Bundle.AnnotationsContentViewer_tagEntry_title(), + Bundle.AnnotationsContentViewer_tagEntry_onArtifactEmpty(), + TAG_ENTRIES, true); + + private static final SectionConfig CONTENT_TAG_CONFIG = new SectionConfig<>( + Bundle.AnnotationsContentViewer_tagEntry_title(), + Bundle.AnnotationsContentViewer_tagEntry_onContentEmpty(), + TAG_ENTRIES, true); + + // file set attributes and table configurations + private static final List> FILESET_HIT_ENTRIES = Arrays.asList( + new ItemEntry<>(Bundle.AnnotationsContentViewer_fileHitEntry_setName(), + (bba) -> tryGetAttribute(bba, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)), + new ItemEntry<>(Bundle.AnnotationsContentViewer_fileHitEntry_comment(), + (bba) -> tryGetAttribute(bba, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT)) + ); + + private static final SectionConfig INTERESTING_FILE_CONFIG = new SectionConfig<>( + Bundle.AnnotationsContentViewer_fileHitEntry_interestingFileHitTitle(), + Bundle.AnnotationsContentViewer_fileHitEntry_onInterestingFileHitEmpty(), + FILESET_HIT_ENTRIES, false); + + private static final SectionConfig HASHSET_CONFIG = new SectionConfig<>( + Bundle.AnnotationsContentViewer_fileHitEntry_hashSetHitTitle(), + Bundle.AnnotationsContentViewer_fileHitEntry_onHashSetHitEmpty(), + FILESET_HIT_ENTRIES, false); + + // central repository attributes and table configuration + private static final List> CR_COMMENTS_ENTRIES = Arrays.asList( + new ItemEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_case(), + cai -> (cai.getCorrelationCase() != null) ? cai.getCorrelationCase().getDisplayName() : null), + new ItemEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_type(), + cai -> (cai.getCorrelationType() != null) ? cai.getCorrelationType().getDisplayName() : null), + new ItemEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_comment(), cai -> cai.getComment()), + new ItemEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_path(), cai -> cai.getFilePath()) + ); + + private static final SectionConfig CR_COMMENTS_CONFIG = new SectionConfig<>( + Bundle.AnnotationsContentViewer_centralRepositoryEntry_title(), + Bundle.AnnotationsContentViewer_centralRepositoryEntry_onEmpty(), + CR_COMMENTS_ENTRIES, true); + /** * Creates an instance of AnnotationsContentViewer. */ public AnnotationsContentViewer() { initComponents(); Utilities.configureTextPaneAsHtml(jTextPane1); + // get html editor kit and apply additional style rules + EditorKit editorKit = jTextPane1.getEditorKit(); + if (editorKit instanceof HTMLEditorKit) { + HTMLEditorKit htmlKit = (HTMLEditorKit) editorKit; + htmlKit.getStyleSheet().addRule(STYLE_SHEET_RULE); + } } @Override @@ -198,81 +283,79 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data if (artifact != null) { renderArtifact(body, artifact, sourceFile); } else { - renderAbstractFile(body, sourceFile, false); + renderContent(body, sourceFile, false); } jTextPane1.setText(html.html()); jTextPane1.setCaretPosition(0); } + /** + * Renders annotations for an artifact. + * + * @param parent The html element to render content int. + * @param bba The blackboard artifact to render. + * @param sourceContent The content from which the blackboard artifact + * comes. + */ private static void renderArtifact(Element parent, BlackboardArtifact bba, Content sourceContent) { - appendEntries(parent, - Bundle.AnnotationsContentViewer_tagEntry_title(), - Bundle.AnnotationsContentViewer_tagEntry_onArtifactEmpty(), - getTags(bba), TAG_COLUMNS, false, true); + appendEntries(parent, ARTIFACT_TAG_CONFIG, getTags(bba), false); - if (sourceContent instanceof AbstractFile) { + if (sourceContent instanceof AbstractFile && CentralRepository.isEnabled()) { AbstractFile sourceFile = (AbstractFile) sourceContent; - - if (CentralRepository.isEnabled()) { - List centralRepoComments = getCentralRepositoryData(bba, sourceFile); - appendEntries(parent, - Bundle.AnnotationsContentViewer_centralRepositoryEntry_title(), - Bundle.AnnotationsContentViewer_centralRepositoryEntry_onEmpty(), - centralRepoComments, CENTRAL_REPO_COMMENTS_COLUMNS, false, true); - } + List centralRepoComments = getCentralRepositoryData(bba, sourceFile); + appendEntries(parent, CR_COMMENTS_CONFIG, centralRepoComments, false); } if (BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() == bba.getArtifactTypeID()) { - appendEntries(parent, - Bundle.AnnotationsContentViewer_fileHitEntry_hashSetHitTitle(), - Bundle.AnnotationsContentViewer_fileHitEntry_onHashSetHitEmpty(), - Arrays.asList(bba), FILESET_HIT_COLUMNS, false, false); + appendEntries(parent, HASHSET_CONFIG, Arrays.asList(bba), false); } if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == bba.getArtifactTypeID()) { - appendEntries(parent, - Bundle.AnnotationsContentViewer_fileHitEntry_interestingFileHitTitle(), - Bundle.AnnotationsContentViewer_fileHitEntry_onInterestingFileHitEmpty(), - Arrays.asList(bba), FILESET_HIT_COLUMNS, false, false); + appendEntries(parent, INTERESTING_FILE_CONFIG, Arrays.asList(bba), false); } Element sourceFileSection = appendSection(parent, Bundle.AnnotationsContentViewer_sourceFile_title()); - renderAbstractFile(sourceFileSection, sourceContent, true); + renderContent(sourceFileSection, sourceContent, true); } - private static void renderAbstractFile(Element parent, Content sourceContent, boolean isSubheader) { - appendEntries(parent, - Bundle.AnnotationsContentViewer_tagEntry_title(), - Bundle.AnnotationsContentViewer_tagEntry_onContentEmpty(), - getTags(sourceContent), TAG_COLUMNS, isSubheader, true); + /** + * Renders annotations for a content item. + * + * @param parent The parent within which to render. + * @param sourceContent The content for which annotations will be gathered. + * @param isSubheader True if this section should be rendered as a + * subheader as opposed to a top-level header. + */ + private static void renderContent(Element parent, Content sourceContent, boolean isSubheader) { + appendEntries(parent, CONTENT_TAG_CONFIG, getTags(sourceContent), isSubheader); if (sourceContent instanceof AbstractFile) { AbstractFile sourceFile = (AbstractFile) sourceContent; if (CentralRepository.isEnabled()) { List centralRepoComments = getCentralRepositoryData(null, sourceFile); - appendEntries(parent, - Bundle.AnnotationsContentViewer_centralRepositoryEntry_title(), - Bundle.AnnotationsContentViewer_centralRepositoryEntry_onEmpty(), - centralRepoComments, CENTRAL_REPO_COMMENTS_COLUMNS, isSubheader, true); + appendEntries(parent, CR_COMMENTS_CONFIG, centralRepoComments, isSubheader); } - appendEntries(parent, - Bundle.AnnotationsContentViewer_fileHitEntry_hashSetHitTitle(), - Bundle.AnnotationsContentViewer_fileHitEntry_onHashSetHitEmpty(), - getFileSetHits(sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT), - FILESET_HIT_COLUMNS, isSubheader, false); + appendEntries(parent, HASHSET_CONFIG, + getFileSetHits(sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT), + isSubheader); - appendEntries(parent, - Bundle.AnnotationsContentViewer_fileHitEntry_interestingFileHitTitle(), - Bundle.AnnotationsContentViewer_fileHitEntry_onInterestingFileHitEmpty(), - getFileSetHits(sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT), - FILESET_HIT_COLUMNS, isSubheader, false); + appendEntries(parent, INTERESTING_FILE_CONFIG, + getFileSetHits(sourceFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT), + isSubheader); } } + /** + * Retrieves tags associated with a content item. + * + * @param sourceContent The content for which to gather content. + * + * @return The Tags associated with this item. + */ private static List getTags(Content sourceContent) { try { SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); @@ -285,6 +368,12 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data return new ArrayList<>(); } + /** + *Retrieves tags for blackboard artifact tags. + * @param bba The blackboard artifact for which to retrieve tags. + * + * @return The found tags. + */ private static List getTags(BlackboardArtifact bba) { try { SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); @@ -297,6 +386,12 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data return new ArrayList<>(); } + /** + * Retrieves the blackboard artifacts for a source file matching a certain type. + * @param sourceFile The source file for which to fetch artifacts. + * @param type The type of blackboard artifact to fetch. + * @return The artifacts found matching this type. + */ private static List getFileSetHits(AbstractFile sourceFile, BlackboardArtifact.ARTIFACT_TYPE type) { try { SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); @@ -309,8 +404,6 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data return new ArrayList<>(); } - - /** * Attempts to retrieve the attribute of a particular type from a blackboard * artifact. @@ -340,11 +433,12 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data } /** - * Populate the "Central Repository Comments" section with data. + * Gets the "Central Repository Comments" section with data. * * @param artifact A selected artifact (can be null). * @param sourceFile A selected file, or a source file of the selected * artifact. + * @return The Correlation Attribute Instances associated with the artifact and/or sourcefile. */ private static List getCentralRepositoryData(BlackboardArtifact artifact, AbstractFile sourceFile) { List toReturn = new ArrayList<>(); @@ -393,40 +487,73 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data return toReturn; } - - - private static void appendEntries(Element parent, String title, String errorMessage, List items, - List> fields, boolean isSubsection, boolean isVerticalTable) { - Element sectionDiv = (isSubsection) ? appendSubsection(parent, title) : appendSection(parent, title); + /** + * Append entries to the parent element in the annotations viewer. Entries will be formatted as a table + * in the format specified in the SectionConfig. + * @param The item type. + * @param parent The parent element for which the entries will be attached. + * @param config The display configuration for this entry type (i.e. table type, name, if data is not present). + * @param items The items to display. + * @param isSubsection Whether or not this should be displayed as a subsection. If not displayed as a top-level section. + */ + private static void appendEntries(Element parent, SectionConfig config, List items, + boolean isSubsection) { + + Element sectionDiv = (isSubsection) ? appendSubsection(parent, config.getTitle()) : appendSection(parent, config.getTitle()); if (items == null || items.isEmpty()) { - appendMessage(sectionDiv, errorMessage); - } else if (isVerticalTable) { - appendVerticalEntryTables(sectionDiv, items, fields); + appendMessage(sectionDiv, config.getOnEmpty()); + } else if (config.isIsVerticalTable()) { + appendVerticalEntryTables(sectionDiv, items, config.getAttributes()); } else { - appendEntryTable(sectionDiv, items, fields); + appendEntryTable(sectionDiv, items, config.getAttributes()); } } - private static Element appendVerticalEntryTables(Element parent, List items, List> rowHeaders) { - items.stream() - .filter(item -> item != null) - .forEach((item) -> { - List> tableData = rowHeaders.stream() - .map(row -> Arrays.asList(row.getColumnName(), row.retrieveValue(item))) - .collect(Collectors.toList()); + /** + * Appends a table where items are displayed in rows of key-value pairs. + * @param + * @param parent The parent to append the table. + * @param items The items to process into a series of tables. + * @param rowHeaders The keys and the means to process items in order to get key-value pairs. + * @return The parent element provided as parameter. + */ + private static Element appendVerticalEntryTables(Element parent, List items, List> rowHeaders) { + boolean isFirst = true; + for (T item : items) { + if (item == null) { + continue; + } - Element childTable = appendTable(parent, 2, tableData, null); - childTable.attr("style", String.format("margin-bottom: %dpx", DEFAULT_TABLE_SPACING)); - }); + List> tableData = rowHeaders.stream() + .map(row -> Arrays.asList(row.getItemName(), row.retrieveValue(item))) + .collect(Collectors.toList()); + + Element childTable = appendTable(parent, 2, tableData, null); + childTable.attr("class", VERTICAL_TABLE_CLASSNAME); + + if (isFirst) { + isFirst = false; + } else { + childTable.attr("style", String.format("margin-top: %dpx;", DEFAULT_TABLE_SPACING)); + } + } return parent; } - private static Element appendEntryTable(Element parent, List items, List> columns) { + /** + * Appends a table with column headers to the parent element. + * @param The item type. + * @param parent The element that will have this table appended to it. + * @param items The items to place as a row in this table. + * @param columns The columns for this table and the means to process each data item to retrieve a cell. + * @return The generated table element. + */ + private static Element appendEntryTable(Element parent, List items, List> columns) { int columnNumber = columns.size(); - List columnHeaders = columns.stream().map(c -> c.getColumnName()).collect(Collectors.toList()); + List columnHeaders = columns.stream().map(c -> c.getItemName()).collect(Collectors.toList()); List> rows = items.stream() .filter(r -> r != null) .map(r -> { @@ -437,14 +564,22 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data .collect(Collectors.toList()); Element table = appendTable(parent, columnNumber, rows, columnHeaders); - table.attr("style", String.format("margin-bottom: %dpx", DEFAULT_TABLE_SPACING)); + table.attr("class", ENTRY_TABLE_CLASSNAME); return table; } + /** + * Appends a generic table to the parent element. + * @param parent The parent element that will have a table appended to it. + * @param columnNumber The number of columns to append. + * @param content The content in content.get(row).get(column) format. + * @param columnHeaders The column headers or null if no column headers should be created. + * @return + */ private static Element appendTable(Element parent, int columnNumber, List> content, List columnHeaders) { Element table = parent.appendElement("table"); if (columnHeaders != null && !columnHeaders.isEmpty()) { - Element header = parent.appendElement("thead"); + Element header = table.appendElement("thead"); appendRow(header, columnHeaders, columnNumber, true); } Element tableBody = table.appendElement("tbody"); @@ -460,8 +595,6 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data for (int i = 0; i < columnNumber; i++) { Element cell = row.appendElement(cellType); if (data != null && i < data.size()) { - cell.attr("valign", "top"); - cell.attr("style", CONTENT_STYLE); cell.text(StringUtils.isEmpty(data.get(i)) ? "" : data.get(i)); } } @@ -470,26 +603,26 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data private static Element appendSection(Element parent, String headerText) { Element sectionDiv = parent.appendElement("div"); - sectionDiv.attr("style", String.format("margin-bottom: %dpx;", DEFAULT_SECTION_SPACING)); + sectionDiv.attr("class", SECTION_CLASSNAME); Element header = sectionDiv.appendElement("h1"); header.text(headerText); - header.attr("style", HEADER_STYLE); + header.attr("class", HEADER_CLASSNAME); return sectionDiv; } private static Element appendSubsection(Element parent, String headerText) { Element subsectionDiv = parent.appendElement("div"); - subsectionDiv.attr("style", String.format("margin-bottom: %dpx; padding-left: %dpx;", DEFAULT_SUBSECTION_SPACING, DEFAULT_SUBSECTION_LEFT_PAD)); + subsectionDiv.attr("class", SUBSECTION_CLASSNAME); Element header = subsectionDiv.appendElement("h2"); header.text(headerText); - header.attr("style", SUBHEADER_STYLE); + header.attr("class", SUBHEADER_CLASSNAME); return subsectionDiv; } private static Element appendMessage(Element parent, String message) { Element messageEl = parent.appendElement("p"); messageEl.text(message); - messageEl.attr("style", MESSAGE_STYLE); + messageEl.attr("class", MESSAGE_CLASSNAME); return messageEl; } From 6356a72591c2be46ca7b73302c9c3b885ae5e0f9 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 8 May 2020 16:02:40 -0400 Subject: [PATCH 37/81] commenting --- .../AnnotationsContentViewer.java | 140 ++++++++++++++---- .../contentviewers/Bundle.properties-MERGED | 14 +- 2 files changed, 122 insertions(+), 32 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index 7884f1a630..464574d977 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -81,12 +81,17 @@ import org.jsoup.nodes.Element; "AnnotationsContentViewer.fileHitEntry.onHashSetHitEmpty=There are no hash set hits for the selected content.", "AnnotationsContentViewer.fileHitEntry.interestingFileHitTitle=Interesting File Hit Comments", "AnnotationsContentViewer.fileHitEntry.onInterestingFileHitEmpty=There are no interesting file hits for the selected content.", - "AnnotationsContentViewer.fileHitEntry.setName=Set Name", - "AnnotationsContentViewer.fileHitEntry.comment=Comment", + "AnnotationsContentViewer.fileHitEntry.setName=Set Name:", + "AnnotationsContentViewer.fileHitEntry.comment=Comment:", "AnnotationsContentViewer.sourceFile.title=Source File" }) public class AnnotationsContentViewer extends javax.swing.JPanel implements DataContentViewer { + /** + * Describes a key value pair for an item of type T where the key is the field name to display and + * the value is retrieved from item of type T using a provided Function. + * @param The item type. + */ private static class ItemEntry { private final String itemName; @@ -110,6 +115,10 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data } } + /** + * Describes a section that will be appended to the annotations view panel. + * @param The item type for items to display. + */ private static class SectionConfig { private final String title; @@ -124,18 +133,32 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data this.isVerticalTable = isVerticalTable; } + /** + * @return The title for the section. + */ String getTitle() { return title; } + /** + * @return The message to display if no items provided. + */ String getOnEmpty() { return onEmpty; } + /** + * @return Describes key-value pairs on the object to display to the user. + */ List> getAttributes() { return attributes; } + /** + * @return If the table should be shown as a series of key-value pairs as rows. Otherwise, + * data is shown in a table where the column headers are the keys and each row represents one + * item to display. + */ boolean isIsVerticalTable() { return isVerticalTable; } @@ -210,19 +233,17 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data private static final SectionConfig INTERESTING_FILE_CONFIG = new SectionConfig<>( Bundle.AnnotationsContentViewer_fileHitEntry_interestingFileHitTitle(), Bundle.AnnotationsContentViewer_fileHitEntry_onInterestingFileHitEmpty(), - FILESET_HIT_ENTRIES, false); + FILESET_HIT_ENTRIES, true); private static final SectionConfig HASHSET_CONFIG = new SectionConfig<>( Bundle.AnnotationsContentViewer_fileHitEntry_hashSetHitTitle(), Bundle.AnnotationsContentViewer_fileHitEntry_onHashSetHitEmpty(), - FILESET_HIT_ENTRIES, false); + FILESET_HIT_ENTRIES, true); // central repository attributes and table configuration private static final List> CR_COMMENTS_ENTRIES = Arrays.asList( new ItemEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_case(), cai -> (cai.getCorrelationCase() != null) ? cai.getCorrelationCase().getDisplayName() : null), - new ItemEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_type(), - cai -> (cai.getCorrelationType() != null) ? cai.getCorrelationType().getDisplayName() : null), new ItemEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_comment(), cai -> cai.getComment()), new ItemEntry<>(Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_path(), cai -> cai.getFilePath()) ); @@ -369,8 +390,9 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data } /** - *Retrieves tags for blackboard artifact tags. - * @param bba The blackboard artifact for which to retrieve tags. + * Retrieves tags for blackboard artifact tags. + * + * @param bba The blackboard artifact for which to retrieve tags. * * @return The found tags. */ @@ -387,9 +409,12 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data } /** - * Retrieves the blackboard artifacts for a source file matching a certain type. + * Retrieves the blackboard artifacts for a source file matching a certain + * type. + * * @param sourceFile The source file for which to fetch artifacts. - * @param type The type of blackboard artifact to fetch. + * @param type The type of blackboard artifact to fetch. + * * @return The artifacts found matching this type. */ private static List getFileSetHits(AbstractFile sourceFile, BlackboardArtifact.ARTIFACT_TYPE type) { @@ -438,7 +463,9 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data * @param artifact A selected artifact (can be null). * @param sourceFile A selected file, or a source file of the selected * artifact. - * @return The Correlation Attribute Instances associated with the artifact and/or sourcefile. + * + * @return The Correlation Attribute Instances associated with the artifact + * and/or sourcefile. */ private static List getCentralRepositoryData(BlackboardArtifact artifact, AbstractFile sourceFile) { List toReturn = new ArrayList<>(); @@ -489,13 +516,18 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data } /** - * Append entries to the parent element in the annotations viewer. Entries will be formatted as a table - * in the format specified in the SectionConfig. - * @param The item type. - * @param parent The parent element for which the entries will be attached. - * @param config The display configuration for this entry type (i.e. table type, name, if data is not present). - * @param items The items to display. - * @param isSubsection Whether or not this should be displayed as a subsection. If not displayed as a top-level section. + * Append entries to the parent element in the annotations viewer. Entries + * will be formatted as a table in the format specified in the + * SectionConfig. + * + * @param The item type. + * @param parent The parent element for which the entries will be + * attached. + * @param config The display configuration for this entry type (i.e. + * table type, name, if data is not present). + * @param items The items to display. + * @param isSubsection Whether or not this should be displayed as a + * subsection. If not displayed as a top-level section. */ private static void appendEntries(Element parent, SectionConfig config, List items, boolean isSubsection) { @@ -513,10 +545,13 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data /** * Appends a table where items are displayed in rows of key-value pairs. + * * @param - * @param parent The parent to append the table. - * @param items The items to process into a series of tables. - * @param rowHeaders The keys and the means to process items in order to get key-value pairs. + * @param parent The parent to append the table. + * @param items The items to process into a series of tables. + * @param rowHeaders The keys and the means to process items in order to get + * key-value pairs. + * * @return The parent element provided as parameter. */ private static Element appendVerticalEntryTables(Element parent, List items, List> rowHeaders) { @@ -545,10 +580,13 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data /** * Appends a table with column headers to the parent element. - * @param The item type. - * @param parent The element that will have this table appended to it. - * @param items The items to place as a row in this table. - * @param columns The columns for this table and the means to process each data item to retrieve a cell. + * + * @param The item type. + * @param parent The element that will have this table appended to it. + * @param items The items to place as a row in this table. + * @param columns The columns for this table and the means to process each + * data item to retrieve a cell. + * * @return The generated table element. */ private static Element appendEntryTable(Element parent, List items, List> columns) { @@ -570,11 +608,15 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data /** * Appends a generic table to the parent element. - * @param parent The parent element that will have a table appended to it. - * @param columnNumber The number of columns to append. - * @param content The content in content.get(row).get(column) format. - * @param columnHeaders The column headers or null if no column headers should be created. - * @return + * + * @param parent The parent element that will have a table appended + * to it. + * @param columnNumber The number of columns to append. + * @param content The content in content.get(row).get(column) format. + * @param columnHeaders The column headers or null if no column headers + * should be created. + * + * @return The created table. */ private static Element appendTable(Element parent, int columnNumber, List> content, List columnHeaders) { Element table = parent.appendElement("table"); @@ -588,7 +630,17 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data return table; } - // TODO test sanitizing string + /** + * Appends a row to the parent element (should be thead or tbody). + * + * @param rowParent The parent table element. + * @param data The data to place in columns within the table. + * @param columnNumber The number of columns to append. + * @param isHeader Whether or not this should have header cells ('th') + * instead of regular cells ('td'). + * + * @return The row created. + */ private static Element appendRow(Element rowParent, List data, int columnNumber, boolean isHeader) { String cellType = isHeader ? "th" : "td"; Element row = rowParent.appendElement("tr"); @@ -601,6 +653,14 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data return row; } + /** + * Appends a new section with a section header to the parent element. + * + * @param parent The element to append this section to. + * @param headerText The text for the section. + * + * @return The div for the new section. + */ private static Element appendSection(Element parent, String headerText) { Element sectionDiv = parent.appendElement("div"); sectionDiv.attr("class", SECTION_CLASSNAME); @@ -610,6 +670,14 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data return sectionDiv; } + /** + * Appends a new subsection with a subsection header to the parent element. + * + * @param parent The element to append this subsection to. + * @param headerText The text for the subsection. + * + * @return The div for the new subsection. + */ private static Element appendSubsection(Element parent, String headerText) { Element subsectionDiv = parent.appendElement("div"); subsectionDiv.attr("class", SUBSECTION_CLASSNAME); @@ -619,6 +687,16 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data return subsectionDiv; } + /** + * Appends a message to the parent element. This is typically used in the + * event that no data exists for a certain type. + * + * @param parent The parent element that will have this message appended to + * it. + * @param message The message to append. + * + * @return The paragraph element for the new message. + */ private static Element appendMessage(Element parent, String message) { Element messageEl = parent.appendElement("p"); messageEl.text(message); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED index fd9d2d345e..893d2f705a 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties-MERGED @@ -15,13 +15,25 @@ # governing permissions and limitations under the License. # +AnnotationsContentViewer.centralRepositoryEntry.onEmpty=There is no comment data for the selected content in the Central Repository. +AnnotationsContentViewer.centralRepositoryEntry.title=Central Repository Comments AnnotationsContentViewer.centralRepositoryEntryDataLabel.case=Case: AnnotationsContentViewer.centralRepositoryEntryDataLabel.comment=Comment: AnnotationsContentViewer.centralRepositoryEntryDataLabel.path=Path: AnnotationsContentViewer.centralRepositoryEntryDataLabel.type=Type: +AnnotationsContentViewer.fileHitEntry.comment=Comment: +AnnotationsContentViewer.fileHitEntry.hashSetHitTitle=Hash Set Hit Comments +AnnotationsContentViewer.fileHitEntry.interestingFileHitTitle=Interesting File Hit Comments +AnnotationsContentViewer.fileHitEntry.onHashSetHitEmpty=There are no hash set hits for the selected content. +AnnotationsContentViewer.fileHitEntry.onInterestingFileHitEmpty=There are no interesting file hits for the selected content. +AnnotationsContentViewer.fileHitEntry.setName=Set Name: +AnnotationsContentViewer.sourceFile.title=Source File +AnnotationsContentViewer.tagEntry.onArtifactEmpty=There are no tags for the selected artifact. +AnnotationsContentViewer.tagEntry.onContentEmpty=There are no tags for the selected content. +AnnotationsContentViewer.tagEntry.title=Tags AnnotationsContentViewer.tagEntryDataLabel.comment=Comment: AnnotationsContentViewer.tagEntryDataLabel.tag=Tag: -AnnotationsContentViewer.tagEntryDataLabel.tagUser=Tag User: +AnnotationsContentViewer.tagEntryDataLabel.tagUser=Examiner: AnnotationsContentViewer.title=Annotations AnnotationsContentViewer.toolTip=Displays tags and comments associated with the selected content. ApplicationContentViewer.title=Application From f5ec04548b5a20f100cba26e1b364e8a9ae06c0b Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Fri, 8 May 2020 16:23:42 -0400 Subject: [PATCH 38/81] Interim commit - DefaultArtifactContentViewer now implements ArtifactContentViewer, though it does nothing with the artifact yet. --- .../DefaultArtifactContentViewer.java | 95 +++---------------- 1 file changed, 14 insertions(+), 81 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java index b72320c8b9..3b6515a8ca 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/DefaultArtifactContentViewer.java @@ -45,12 +45,9 @@ import org.apache.commons.lang.StringUtils; import org.openide.nodes.Node; import org.openide.util.Lookup; import org.openide.util.NbBundle; -import org.openide.util.lookup.ServiceProvider; -import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; @@ -63,13 +60,12 @@ import com.google.gson.JsonArray; import java.util.Map; /** - * Instances of this class display the BlackboardArtifacts associated with the - * Content represented by a Node. Each BlackboardArtifact is rendered displayed - * in a JTable representation of its BlackboardAttributes. + * This class displays a Blackboard artifact as a table listing all the + * attribute names and values. */ -@ServiceProvider(service = DataContentViewer.class, position = 11) + @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives -public class DefaultArtifactContentViewer extends javax.swing.JPanel implements DataContentViewer { +public class DefaultArtifactContentViewer extends javax.swing.JPanel implements ArtifactContentViewer { @NbBundle.Messages({ "DataContentViewerArtifact.attrsTableHeader.type=Type", @@ -81,11 +77,16 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements private final static Logger logger = Logger.getLogger(DefaultArtifactContentViewer.class.getName()); private final static String WAIT_TEXT = NbBundle.getMessage(DefaultArtifactContentViewer.class, "DataContentViewerArtifact.waitText"); private final static String ERROR_TEXT = NbBundle.getMessage(DefaultArtifactContentViewer.class, "DataContentViewerArtifact.errorText"); + + private static final long serialVersionUID = 1L; + private Node currentNode; // @@@ Remove this when the redundant setNode() calls problem is fixed. private int currentPage = 1; private final Object lock = new Object(); + private List artifactTableContents; // Accessed by multiple threads, use getArtifactContents() and setArtifactContents() SwingWorker currentTask; // Accessed by multiple threads, use startNewTask() + private static final String[] COLUMN_HEADERS = { Bundle.DataContentViewerArtifact_attrsTableHeader_type(), Bundle.DataContentViewerArtifact_attrsTableHeader_value(), @@ -437,88 +438,20 @@ public class DefaultArtifactContentViewer extends javax.swing.JPanel implements currentNode = null; } - @Override - public void setNode(Node selectedNode) { - if (currentNode == selectedNode) { - return; - } - currentNode = selectedNode; - - // Make sure there is a node. Null might be passed to reset the viewer. - if (selectedNode == null) { - return; - } - - // Make sure the node is of the correct type. - Lookup lookup = selectedNode.getLookup(); - Content content = lookup.lookup(Content.class); - if (content == null) { - return; - } - - startNewTask(new SelectedNodeChangedTask(selectedNode)); - } - - @Override - public String getTitle() { - return NbBundle.getMessage(this.getClass(), "DataContentViewerArtifact.title"); - } - - @Override - public String getToolTip() { - return NbBundle.getMessage(this.getClass(), "DataContentViewerArtifact.toolTip"); - } - - @Override - public DataContentViewer createInstance() { - return new DefaultArtifactContentViewer(); - } - @Override public Component getComponent() { return this; } @Override - public void resetComponent() { - resetComponents(); + public void setArtifact(BlackboardArtifact artifact) { + // RAMAN TBD: ****************** IMPLMENT THIS. ********************** + } @Override - public boolean isSupported(Node node) { - if (node == null) { - return false; - } - - for (Content content : node.getLookup().lookupAll(Content.class)) { - if ( (content != null) && (!(content instanceof BlackboardArtifact)) ){ - try { - return content.getAllArtifactsCount() > 0; - } catch (TskException ex) { - logger.log(Level.SEVERE, "Couldn't get count of BlackboardArtifacts for content", ex); //NON-NLS - } - } - } - return false; - } - - @Override - public int isPreferred(Node node) { - BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class); - // low priority if node doesn't have an artifact (meaning it was found from normal directory - // browsing, or if the artifact is something that means the user really wants to see the original - // file and not more details about the artifact - if ((artifact == null) - || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) - || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) - || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()) - || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID()) - || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) - || (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID())) { - return 3; - } else { - return 6; - } + public boolean isSupported(BlackboardArtifact artifact) { + return true; } /** From 3925645114b1aa1e156df07b8eba25f1a01bac3b Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Sun, 10 May 2020 15:56:45 -0400 Subject: [PATCH 39/81] Fixed IG button typo --- .../autopsy/imagegallery/gui/drawableviews/GroupPane.fxml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml index 5dcd725381..d01cea5c08 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml @@ -61,7 +61,7 @@ -