diff --git a/Core/manifest.mf b/Core/manifest.mf index e3a95f497e..eabc8f026b 100644 --- a/Core/manifest.mf +++ b/Core/manifest.mf @@ -2,7 +2,7 @@ Manifest-Version: 1.0 OpenIDE-Module: org.sleuthkit.autopsy.core/10 OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml -OpenIDE-Module-Implementation-Version: 25 +OpenIDE-Module-Implementation-Version: 26 OpenIDE-Module-Requires: org.openide.windows.WindowManager AutoUpdate-Show-In-Client: true AutoUpdate-Essential-Module: true diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index 4df5159bd6..2406271416 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -63,7 +63,7 @@ file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-tran file.reference.fontbox-2.0.8.jar=release/modules/ext/fontbox-2.0.8.jar file.reference.pdfbox-2.0.8.jar=release/modules/ext/pdfbox-2.0.8.jar file.reference.pdfbox-tools-2.0.8.jar=release/modules/ext/pdfbox-tools-2.0.8.jar -file.reference.sleuthkit-postgresql-4.6.4.jar=release/modules/ext/sleuthkit-postgresql-4.6.4.jar +file.reference.sleuthkit-postgresql-4.6.5.jar=release/modules/ext/sleuthkit-postgresql-4.6.5.jar file.reference.tagsoup-1.2.1.jar=release/modules/ext/tagsoup-1.2.1.jar file.reference.tika-core-1.17.jar=release/modules/ext/tika-core-1.17.jar file.reference.tika-parsers-1.17.jar=release/modules/ext/tika-parsers-1.17.jar @@ -84,5 +84,5 @@ nbm.homepage=http://www.sleuthkit.org/ nbm.module.author=Brian Carrier nbm.needs.restart=true source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar -spec.version.base=10.13 +spec.version.base=10.14 diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 0e8b544024..3e146e0a53 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -339,7 +339,7 @@ org.sleuthkit.autopsy.progress org.sleuthkit.autopsy.report org.sleuthkit.autopsy.textextractors - org.sleuthkit.autopsy.textextractors.extractionconfigs + org.sleuthkit.autopsy.textextractors.configs org.sleuthkit.autopsy.texttranslation org.sleuthkit.datamodel @@ -500,8 +500,8 @@ release/modules/ext/isoparser-1.1.18.jar - ext/sleuthkit-postgresql-4.6.4.jar - release/modules/ext/sleuthkit-postgresql-4.6.4.jar + ext/sleuthkit-postgresql-4.6.5.jar + release/modules/ext/sleuthkit-postgresql-4.6.5.jar ext/vorbis-java-core-0.8.jar diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesFilterChildren.java b/Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesFilterChildren.java similarity index 91% rename from Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesFilterChildren.java rename to Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesFilterChildren.java index abe37bb15e..6573ac7e47 100755 --- a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesFilterChildren.java +++ b/Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesFilterChildren.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.othercasessearch; +package org.sleuthkit.autopsy.allcasessearch; import org.openide.nodes.Children; import org.openide.nodes.FilterNode; @@ -27,7 +27,7 @@ import org.sleuthkit.autopsy.corecomponents.TableFilterNode; * A Children implementation for a * CorrelationPropertyFilterNode. */ -final class OtherCasesFilterChildren extends FilterNode.Children { +final class AllCasesFilterChildren extends FilterNode.Children { /** * Create a new Children instance. @@ -41,7 +41,7 @@ final class OtherCasesFilterChildren extends FilterNode.Children { static Children createInstance(Node wrappedNode, boolean createChildren) { if (createChildren) { - return new OtherCasesFilterChildren(wrappedNode); + return new AllCasesFilterChildren(wrappedNode); } else { return Children.LEAF; } @@ -53,7 +53,7 @@ final class OtherCasesFilterChildren extends FilterNode.Children { * * @param wrappedNode The node wrapped by CorrelationPropertyFilterNode. */ - OtherCasesFilterChildren(Node wrappedNode) { + AllCasesFilterChildren(Node wrappedNode) { super(wrappedNode); } diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchAction.java b/Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchAction.java similarity index 75% rename from Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchAction.java rename to Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchAction.java index 45986ccd4a..f04eebabdc 100755 --- a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchAction.java +++ b/Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchAction.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.othercasessearch; +package org.sleuthkit.autopsy.allcasessearch; import java.awt.event.ActionEvent; import org.openide.awt.ActionID; @@ -27,16 +27,15 @@ import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; -import org.sleuthkit.autopsy.othercasessearch.Bundle; /** * Action for accessing the Search Other Cases dialog. */ -@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.othercasessearch.OtherCasesSearchAction") -@ActionRegistration(displayName = "#CTL_OtherCasesSearchAction=Search Other Cases", lazy = false) +@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.allcasessearch.AllCasesSearchAction") +@ActionRegistration(displayName = "#CTL_OtherCasesSearchAction=Search All Cases", lazy = false) @ActionReference(path = "Menu/Tools", position = 201) -@NbBundle.Messages({"CTL_OtherCasesSearchAction=Search Other Cases"}) -public class OtherCasesSearchAction extends CallableSystemAction { +@NbBundle.Messages({"CTL_AllCasesSearchAction=Search All Cases"}) +public class AllCasesSearchAction extends CallableSystemAction { @Override public boolean isEnabled() { @@ -50,15 +49,15 @@ public class OtherCasesSearchAction extends CallableSystemAction { @Override public void performAction() { - OtherCasesSearchDialog dialog = new OtherCasesSearchDialog(); + AllCasesSearchDialog dialog = new AllCasesSearchDialog(); dialog.display(); } @NbBundle.Messages({ - "OtherCasesSearchAction.getName.text=Search Other Cases"}) + "AllCasesSearchAction.getName.text=Search All Cases"}) @Override public String getName() { - return Bundle.OtherCasesSearchAction_getName_text(); + return Bundle.AllCasesSearchAction_getName_text(); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchChildren.java b/Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchChildren.java similarity index 82% rename from Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchChildren.java rename to Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchChildren.java index eea55a6518..14ebd32d9c 100755 --- a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchChildren.java +++ b/Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchChildren.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.othercasessearch; +package org.sleuthkit.autopsy.allcasessearch; import java.util.List; import org.openide.nodes.Children; @@ -27,15 +27,15 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeIns * Creates CorrelationAttributeInstanceNodes from a collection of * CorrelationAttributeInstances. */ -class OtherCasesSearchChildren extends Children.Keys { +class AllCasesSearchChildren extends Children.Keys { /** - * Create an instance of OtherCasesSearchChildren. + * Create an instance of AllCasesSearchChildren. * * @param lazy Lazy load? * @param fileList List of CorrelationAttributeInstances. */ - OtherCasesSearchChildren(boolean lazy, List instances) { + AllCasesSearchChildren(boolean lazy, List instances) { super(lazy); this.setKeys(instances); } diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.form b/Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchDialog.form similarity index 80% rename from Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.form rename to Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchDialog.form index 30995524b2..f378613c11 100755 --- a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.form +++ b/Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchDialog.form @@ -81,14 +81,14 @@ - + - + @@ -98,15 +98,15 @@ - + - + - + @@ -129,7 +129,7 @@ - + @@ -139,14 +139,14 @@ - + - + @@ -154,7 +154,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java b/Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchDialog.java similarity index 73% rename from Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java rename to Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchDialog.java index e7f2ae16b5..814b696ce3 100755 --- a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java +++ b/Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchDialog.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.othercasessearch; +package org.sleuthkit.autopsy.allcasessearch; import java.awt.Color; import java.awt.event.ItemEvent; @@ -48,31 +48,31 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.EmptyNode; @Messages({ - "OtherCasesSearchDialog.dialogTitle.text=Search Other Cases", - "OtherCasesSearchDialog.resultsTitle.text=Other Cases", - "OtherCasesSearchDialog.resultsDescription.text=Other Cases Search", - "OtherCasesSearchDialog.emptyNode.text=No results found.", - "OtherCasesSearchDialog.validation.invalidHash=The supplied value is not a valid MD5 hash.", - "OtherCasesSearchDialog.validation.invalidEmail=The supplied value is not a valid e-mail address.", - "OtherCasesSearchDialog.validation.invalidDomain=The supplied value is not a valid domain.", - "OtherCasesSearchDialog.validation.invalidPhone=The supplied value is not a valid phone number.", - "OtherCasesSearchDialog.validation.invalidSsid=The supplied value is not a valid wireless network.", - "OtherCasesSearchDialog.validation.invalidMac=The supplied value is not a valid MAC address.", - "OtherCasesSearchDialog.validation.invalidImei=The supplied value is not a valid IMEI number.", - "OtherCasesSearchDialog.validation.invalidImsi=The supplied value is not a valid IMSI number.", - "OtherCasesSearchDialog.validation.invalidIccid=The supplied value is not a valid ICCID number.", - "OtherCasesSearchDialog.validation.genericMessage=The supplied value is not valid.", + "AllCasesSearchDialog.dialogTitle.text=Search All Cases", + "AllCasesSearchDialog.resultsTitle.text=All Cases", + "AllCasesSearchDialog.resultsDescription.text=All Cases Search", + "AllCasesSearchDialog.emptyNode.text=No results found.", + "AllCasesSearchDialog.validation.invalidHash=The supplied value is not a valid MD5 hash.", + "AllCasesSearchDialog.validation.invalidEmail=The supplied value is not a valid e-mail address.", + "AllCasesSearchDialog.validation.invalidDomain=The supplied value is not a valid domain.", + "AllCasesSearchDialog.validation.invalidPhone=The supplied value is not a valid phone number.", + "AllCasesSearchDialog.validation.invalidSsid=The supplied value is not a valid wireless network.", + "AllCasesSearchDialog.validation.invalidMac=The supplied value is not a valid MAC address.", + "AllCasesSearchDialog.validation.invalidImei=The supplied value is not a valid IMEI number.", + "AllCasesSearchDialog.validation.invalidImsi=The supplied value is not a valid IMSI number.", + "AllCasesSearchDialog.validation.invalidIccid=The supplied value is not a valid ICCID number.", + "AllCasesSearchDialog.validation.genericMessage=The supplied value is not valid.", "# {0} - number of cases", - "OtherCasesSearchDialog.caseLabel.text=The current Central Repository contains {0} case(s)." + "AllCasesSearchDialog.caseLabel.text=The current Central Repository contains {0} case(s)." }) /** - * The Search Other Cases dialog allows users to search for specific types of + * The Search All Cases dialog allows users to search for specific types of * correlation properties in the Central Repository. */ @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives -final class OtherCasesSearchDialog extends javax.swing.JDialog { +final class AllCasesSearchDialog extends javax.swing.JDialog { - private static final Logger logger = Logger.getLogger(OtherCasesSearchDialog.class.getName()); + private static final Logger logger = Logger.getLogger(AllCasesSearchDialog.class.getName()); private static final long serialVersionUID = 1L; private final List correlationTypes; @@ -82,8 +82,8 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { /** * Creates a new instance of the Search Other Cases dialog. */ - OtherCasesSearchDialog() { - super((JFrame) WindowManager.getDefault().getMainWindow(), Bundle.OtherCasesSearchDialog_dialogTitle_text(), true); + AllCasesSearchDialog() { + super((JFrame) WindowManager.getDefault().getMainWindow(), Bundle.AllCasesSearchDialog_dialogTitle_text(), true); this.correlationTypes = new ArrayList<>(); initComponents(); customizeComponents(); @@ -122,20 +122,20 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { Collection viewers = new ArrayList<>(1); viewers.add(table); - OtherCasesSearchNode searchNode = new OtherCasesSearchNode(correlationInstances); + AllCasesSearchNode searchNode = new AllCasesSearchNode(correlationInstances); TableFilterNode tableFilterNode = new TableFilterNode(searchNode, true, searchNode.getName()); String resultsText = String.format("%s (%s; \"%s\")", - Bundle.OtherCasesSearchDialog_resultsTitle_text(), type.getDisplayName(), value); + Bundle.AllCasesSearchDialog_resultsTitle_text(), type.getDisplayName(), value); final TopComponent searchResultWin; if (correlationInstances.isEmpty()) { Node emptyNode = new TableFilterNode( - new EmptyNode(Bundle.OtherCasesSearchDialog_emptyNode_text()), true); + new EmptyNode(Bundle.AllCasesSearchDialog_emptyNode_text()), true); searchResultWin = DataResultTopComponent.createInstance( - resultsText, Bundle.OtherCasesSearchDialog_resultsDescription_text(), emptyNode, 0); + resultsText, Bundle.AllCasesSearchDialog_resultsDescription_text(), emptyNode, 0); } else { searchResultWin = DataResultTopComponent.createInstance( - resultsText, Bundle.OtherCasesSearchDialog_resultsDescription_text(), tableFilterNode, correlationInstances.size(), viewers); + resultsText, Bundle.AllCasesSearchDialog_resultsDescription_text(), tableFilterNode, correlationInstances.size(), viewers); } searchResultWin.requestActive(); // make it the active top component } catch (ExecutionException | InterruptedException ex) { @@ -166,16 +166,16 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setResizable(false); - org.openide.awt.Mnemonics.setLocalizedText(correlationValueLabel, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.correlationValueLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(correlationValueLabel, org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, "AllCasesSearchDialog.correlationValueLabel.text")); // NOI18N - correlationValueTextField.setText(org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.correlationValueTextField.text")); // NOI18N + correlationValueTextField.setText(org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, "AllCasesSearchDialog.correlationValueTextField.text")); // NOI18N correlationValueTextField.addKeyListener(new java.awt.event.KeyAdapter() { public void keyReleased(java.awt.event.KeyEvent evt) { valueFieldKeyReleaseListener(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.searchButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, "AllCasesSearchDialog.searchButton.text")); // NOI18N searchButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { searchButtonActionPerformed(evt); @@ -188,15 +188,15 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { } }); - org.openide.awt.Mnemonics.setLocalizedText(correlationTypeLabel, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.correlationTypeLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(correlationTypeLabel, org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, "AllCasesSearchDialog.correlationTypeLabel.text")); // NOI18N errorLabel.setForeground(new java.awt.Color(255, 0, 0)); - org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.errorLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, "AllCasesSearchDialog.errorLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.descriptionLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, "AllCasesSearchDialog.descriptionLabel.text")); // NOI18N casesLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); - org.openide.awt.Mnemonics.setLocalizedText(casesLabel, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.casesLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(casesLabel, org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, "AllCasesSearchDialog.casesLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); @@ -243,8 +243,8 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { .addContainerGap()) ); - searchButton.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.searchButton.AccessibleContext.accessibleName")); // NOI18N - searchButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.searchButton.AccessibleContext.accessibleDescription")); // NOI18N + searchButton.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, "AllCasesSearchDialog.searchButton.AccessibleContext.accessibleName")); // NOI18N + searchButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(AllCasesSearchDialog.class, "AllCasesSearchDialog.searchButton.AccessibleContext.accessibleDescription")); // NOI18N pack(); }// //GEN-END:initComponents @@ -260,34 +260,34 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { String validationMessage; switch (correlationType.getId()) { case CorrelationAttributeInstance.FILES_TYPE_ID: - validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidHash(); + validationMessage = Bundle.AllCasesSearchDialog_validation_invalidHash(); break; case CorrelationAttributeInstance.DOMAIN_TYPE_ID: - validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidDomain(); + validationMessage = Bundle.AllCasesSearchDialog_validation_invalidDomain(); break; case CorrelationAttributeInstance.EMAIL_TYPE_ID: - validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidEmail(); + validationMessage = Bundle.AllCasesSearchDialog_validation_invalidEmail(); break; case CorrelationAttributeInstance.PHONE_TYPE_ID: - validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidPhone(); + validationMessage = Bundle.AllCasesSearchDialog_validation_invalidPhone(); break; case CorrelationAttributeInstance.SSID_TYPE_ID: - validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidSsid(); + validationMessage = Bundle.AllCasesSearchDialog_validation_invalidSsid(); break; case CorrelationAttributeInstance.MAC_TYPE_ID: - validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidMac(); + validationMessage = Bundle.AllCasesSearchDialog_validation_invalidMac(); break; case CorrelationAttributeInstance.IMEI_TYPE_ID: - validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidImei(); + validationMessage = Bundle.AllCasesSearchDialog_validation_invalidImei(); break; case CorrelationAttributeInstance.IMSI_TYPE_ID: - validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidImsi(); + validationMessage = Bundle.AllCasesSearchDialog_validation_invalidImsi(); break; case CorrelationAttributeInstance.ICCID_TYPE_ID: - validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidIccid(); + validationMessage = Bundle.AllCasesSearchDialog_validation_invalidIccid(); break; default: - validationMessage = Bundle.OtherCasesSearchDialog_validation_genericMessage(); + validationMessage = Bundle.AllCasesSearchDialog_validation_genericMessage(); break; } @@ -340,7 +340,7 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { correlationTypes.clear(); correlationTypes.addAll(dbManager.getDefinedCorrelationTypes()); int numberOfCases = dbManager.getCases().size(); - casesLabel.setText(Bundle.OtherCasesSearchDialog_caseLabel_text(numberOfCases)); + casesLabel.setText(Bundle.AllCasesSearchDialog_caseLabel_text(numberOfCases)); } catch (EamDbException ex) { logger.log(Level.SEVERE, "Unable to connect to the Central Repository database.", ex); } @@ -385,16 +385,16 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { } @Messages({ - "OtherCasesSearchDialog.correlationValueTextField.filesExample=Example: \"f0e1d2c3b4a5968778695a4b3c2d1e0f\"", - "OtherCasesSearchDialog.correlationValueTextField.domainExample=Example: \"domain.com\"", - "OtherCasesSearchDialog.correlationValueTextField.emailExample=Example: \"user@host.com\"", - "OtherCasesSearchDialog.correlationValueTextField.phoneExample=Example: \"(800)123-4567\"", - "OtherCasesSearchDialog.correlationValueTextField.usbExample=Example: \"4&1234567&0\"", - "OtherCasesSearchDialog.correlationValueTextField.ssidExample=Example: \"WirelessNetwork-5G\"", - "OtherCasesSearchDialog.correlationValueTextField.macExample=Example: \"0C-14-F2-01-AF-45\"", - "OtherCasesSearchDialog.correlationValueTextField.imeiExample=Example: \"351756061523999\"", - "OtherCasesSearchDialog.correlationValueTextField.imsiExample=Example: \"310150123456789\"", - "OtherCasesSearchDialog.correlationValueTextField.iccidExample=Example: \"89 91 19 1299 99 329451 0\"" + "AllCasesSearchDialog.correlationValueTextField.filesExample=Example: \"f0e1d2c3b4a5968778695a4b3c2d1e0f\"", + "AllCasesSearchDialog.correlationValueTextField.domainExample=Example: \"domain.com\"", + "AllCasesSearchDialog.correlationValueTextField.emailExample=Example: \"user@host.com\"", + "AllCasesSearchDialog.correlationValueTextField.phoneExample=Example: \"(800)123-4567\"", + "AllCasesSearchDialog.correlationValueTextField.usbExample=Example: \"4&1234567&0\"", + "AllCasesSearchDialog.correlationValueTextField.ssidExample=Example: \"WirelessNetwork-5G\"", + "AllCasesSearchDialog.correlationValueTextField.macExample=Example: \"0C-14-F2-01-AF-45\"", + "AllCasesSearchDialog.correlationValueTextField.imeiExample=Example: \"351756061523999\"", + "AllCasesSearchDialog.correlationValueTextField.imsiExample=Example: \"310150123456789\"", + "AllCasesSearchDialog.correlationValueTextField.iccidExample=Example: \"89 91 19 1299 99 329451 0\"" }) /** * Update the text prompt of the name text field based on the input type @@ -407,34 +407,34 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { String text; switch (selectedCorrelationType.getId()) { case CorrelationAttributeInstance.FILES_TYPE_ID: - text = Bundle.OtherCasesSearchDialog_correlationValueTextField_filesExample(); + text = Bundle.AllCasesSearchDialog_correlationValueTextField_filesExample(); break; case CorrelationAttributeInstance.DOMAIN_TYPE_ID: - text = Bundle.OtherCasesSearchDialog_correlationValueTextField_domainExample(); + text = Bundle.AllCasesSearchDialog_correlationValueTextField_domainExample(); break; case CorrelationAttributeInstance.EMAIL_TYPE_ID: - text = Bundle.OtherCasesSearchDialog_correlationValueTextField_emailExample(); + text = Bundle.AllCasesSearchDialog_correlationValueTextField_emailExample(); break; case CorrelationAttributeInstance.PHONE_TYPE_ID: - text = Bundle.OtherCasesSearchDialog_correlationValueTextField_phoneExample(); + text = Bundle.AllCasesSearchDialog_correlationValueTextField_phoneExample(); break; case CorrelationAttributeInstance.USBID_TYPE_ID: - text = Bundle.OtherCasesSearchDialog_correlationValueTextField_usbExample(); + text = Bundle.AllCasesSearchDialog_correlationValueTextField_usbExample(); break; case CorrelationAttributeInstance.SSID_TYPE_ID: - text = Bundle.OtherCasesSearchDialog_correlationValueTextField_ssidExample(); + text = Bundle.AllCasesSearchDialog_correlationValueTextField_ssidExample(); break; case CorrelationAttributeInstance.MAC_TYPE_ID: - text = Bundle.OtherCasesSearchDialog_correlationValueTextField_macExample(); + text = Bundle.AllCasesSearchDialog_correlationValueTextField_macExample(); break; case CorrelationAttributeInstance.IMEI_TYPE_ID: - text = Bundle.OtherCasesSearchDialog_correlationValueTextField_imeiExample(); + text = Bundle.AllCasesSearchDialog_correlationValueTextField_imeiExample(); break; case CorrelationAttributeInstance.IMSI_TYPE_ID: - text = Bundle.OtherCasesSearchDialog_correlationValueTextField_imsiExample(); + text = Bundle.AllCasesSearchDialog_correlationValueTextField_imsiExample(); break; case CorrelationAttributeInstance.ICCID_TYPE_ID: - text = Bundle.OtherCasesSearchDialog_correlationValueTextField_iccidExample(); + text = Bundle.AllCasesSearchDialog_correlationValueTextField_iccidExample(); break; default: text = ""; diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchNode.java b/Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchNode.java similarity index 70% rename from Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchNode.java rename to Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchNode.java index ff9c3a6d80..edf3ff6adf 100755 --- a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchNode.java +++ b/Core/src/org/sleuthkit/autopsy/allcasessearch/AllCasesSearchNode.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.othercasessearch; +package org.sleuthkit.autopsy.allcasessearch; import java.util.List; import org.openide.nodes.AbstractNode; @@ -24,24 +24,24 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; /** - * Parent node to OtherCasesSearchChildren. + * Parent node to AllCasesSearchChildren. */ -class OtherCasesSearchNode extends AbstractNode { +class AllCasesSearchNode extends AbstractNode { /** - * Create an instance of OtherCasesSearchNode. + * Create an instance of AllCasesSearchNode. * * @param keys The list of CorrelationAttributeInstances. */ - OtherCasesSearchNode(List keys) { - super(new OtherCasesSearchChildren(true, keys)); + AllCasesSearchNode(List keys) { + super(new AllCasesSearchChildren(true, keys)); } @Messages({ - "OtherCasesSearchNode.getName.text=Other Cases Search" + "AllCasesSearchNode.getName.text=Other Cases Search" }) @Override public String getName() { - return Bundle.OtherCasesSearchNode_getName_text(); + return Bundle.AllCasesSearchNode_getName_text(); } } diff --git a/Core/src/org/sleuthkit/autopsy/allcasessearch/Bundle.properties b/Core/src/org/sleuthkit/autopsy/allcasessearch/Bundle.properties new file mode 100755 index 0000000000..e1a434785b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/allcasessearch/Bundle.properties @@ -0,0 +1,10 @@ + +AllCasesSearchDialog.descriptionLabel.text=Search the Central Repository for correlation properties with a specified value. The search is case insensitive. +AllCasesSearchDialog.errorLabel.text=\ +AllCasesSearchDialog.correlationTypeLabel.text=Correlation Property Type: +AllCasesSearchDialog.searchButton.AccessibleContext.accessibleDescription= +AllCasesSearchDialog.searchButton.AccessibleContext.accessibleName=Search +AllCasesSearchDialog.searchButton.text=Search +AllCasesSearchDialog.correlationValueTextField.text= +AllCasesSearchDialog.correlationValueLabel.text=Correlation Property Value: +AllCasesSearchDialog.casesLabel.text=\ diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/CorrelationAttributeInstanceNode.java b/Core/src/org/sleuthkit/autopsy/allcasessearch/CorrelationAttributeInstanceNode.java similarity index 96% rename from Core/src/org/sleuthkit/autopsy/othercasessearch/CorrelationAttributeInstanceNode.java rename to Core/src/org/sleuthkit/autopsy/allcasessearch/CorrelationAttributeInstanceNode.java index f3248d293b..7c77b753d8 100755 --- a/Core/src/org/sleuthkit/autopsy/othercasessearch/CorrelationAttributeInstanceNode.java +++ b/Core/src/org/sleuthkit/autopsy/allcasessearch/CorrelationAttributeInstanceNode.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.othercasessearch; +package org.sleuthkit.autopsy.allcasessearch; import java.io.File; import java.util.ArrayList; @@ -29,13 +29,12 @@ import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource; -import org.sleuthkit.autopsy.othercasessearch.Bundle; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; import org.sleuthkit.autopsy.datamodel.NodeProperty; /** - * Used by the Other Cases Search feature to encapsulate instances of a given + * Used by the All Cases Search feature to encapsulate instances of a given * search match. */ public final class CorrelationAttributeInstanceNode extends DisplayableItemNode { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index a413abd846..bd8257175e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -232,10 +232,12 @@ LocalDiskSelectionDialog.okButton.text=OK LocalDiskPanel.localDiskLabel.text=Local Disk: LocalDiskPanel.imageWriterErrorLabel.text=Error Label LocalDiskSelectionDialog.title=Select Local Disk -ImageFilePanel.md5HashLabel.text=MD5 hash: -ImageFilePanel.sha1HashLabel.text=SHA-1 hash: -ImageFilePanel.sha256HashLabel.text=SHA-256 hash: +ImageFilePanel.md5HashLabel.text=MD5: +ImageFilePanel.sha1HashLabel.text=SHA-1: +ImageFilePanel.sha256HashLabel.text=SHA-256: ImageFilePanel.sha256HashTextField.text= ImageFilePanel.sha1HashTextField.text= ImageFilePanel.md5HashTextField.text= ImageFilePanel.errorLabel.text=Error Label +ImageFilePanel.hashValuesNoteLabel.text=NOTE: These values will not be validated when the data source is added. +ImageFilePanel.hashValuesLabel.text=Hash Values (optional): diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 7f4ee150c1..eaaa8f9926 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -1120,12 +1120,7 @@ public class Case { /* * Enable the case-specific actions. */ - - //Deny ability to add a data source if the special admin access file is present. - File denyAddDataSourcePermissions = new File(PlatformUtil.getUserConfigDirectory(), "_ndsp"); - if(!denyAddDataSourcePermissions.exists()) { - CallableSystemAction.get(AddImageAction.class).setEnabled(true); - } + CallableSystemAction.get(AddImageAction.class).setEnabled(true); CallableSystemAction.get(CaseCloseAction.class).setEnabled(true); CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true); CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java b/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java index 5758d5d8b5..f99a643900 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java @@ -46,6 +46,7 @@ import org.sleuthkit.autopsy.events.AutopsyEventPublisher; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent; import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisStartedEvent; +import org.sleuthkit.datamodel.Content; /** * A collaboration monitor listens to local events and translates them into @@ -231,9 +232,12 @@ final class CollaborationMonitor { * @param event A data source analysis started event. */ synchronized void addDataSourceAnalysisTask(DataSourceAnalysisStartedEvent event) { - String status = NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.analyzingDataSourceStatus.msg", hostName, event.getDataSource().getName()); - jobIdsTodataSourceAnalysisTasks.put(event.getDataSourceIngestJobId(), new Task(++nextTaskId, status)); - eventPublisher.publishRemotely(new CollaborationEvent(hostName, getCurrentTasks())); + Content dataSource = event.getDataSource(); + if (dataSource != null) { + String status = NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.analyzingDataSourceStatus.msg", hostName, dataSource.getName()); + jobIdsTodataSourceAnalysisTasks.put(event.getDataSourceIngestJobId(), new Task(++nextTaskId, status)); + eventPublisher.publishRemotely(new CollaborationEvent(hostName, getCurrentTasks())); + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form index 8e17a6a606..2274ccb9a7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form @@ -32,29 +32,45 @@ - - - - - + + - - - - - - - - - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -79,6 +95,8 @@ + + @@ -95,8 +113,10 @@ + + - + @@ -186,6 +206,7 @@ + @@ -193,6 +214,7 @@ + @@ -200,6 +222,7 @@ + @@ -207,6 +230,7 @@ + @@ -214,6 +238,7 @@ + @@ -221,6 +246,23 @@ + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index d9b68ece9d..7be73d92d2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -156,6 +156,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener { md5HashTextField = new javax.swing.JTextField(); sha1HashLabel = new javax.swing.JLabel(); md5HashLabel = new javax.swing.JLabel(); + hashValuesLabel = new javax.swing.JLabel(); + hashValuesNoteLabel = new javax.swing.JLabel(); setMinimumSize(new java.awt.Dimension(0, 65)); setPreferredSize(new java.awt.Dimension(403, 65)); @@ -184,16 +186,28 @@ public class ImageFilePanel extends JPanel implements DocumentListener { org.openide.awt.Mnemonics.setLocalizedText(sectorSizeLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sectorSizeLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(sha256HashLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sha256HashLabel.text")); // NOI18N + sha256HashLabel.setEnabled(false); sha256HashTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sha256HashTextField.text")); // NOI18N + sha256HashTextField.setEnabled(false); sha1HashTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sha1HashTextField.text")); // NOI18N + sha1HashTextField.setEnabled(false); md5HashTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.md5HashTextField.text")); // NOI18N + md5HashTextField.setEnabled(false); org.openide.awt.Mnemonics.setLocalizedText(sha1HashLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.sha1HashLabel.text")); // NOI18N + sha1HashLabel.setEnabled(false); org.openide.awt.Mnemonics.setLocalizedText(md5HashLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.md5HashLabel.text")); // NOI18N + md5HashLabel.setEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(hashValuesLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.hashValuesLabel.text")); // NOI18N + hashValuesLabel.setEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(hashValuesNoteLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.hashValuesNoteLabel.text")); // NOI18N + hashValuesNoteLabel.setEnabled(false); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -206,25 +220,36 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addGap(2, 2, 2)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(sha256HashLabel) - .addComponent(sha1HashLabel) - .addComponent(md5HashLabel) - .addComponent(sectorSizeLabel) - .addComponent(timeZoneLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(sha256HashTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 455, Short.MAX_VALUE) - .addComponent(sha1HashTextField) - .addComponent(md5HashTextField) - .addComponent(sectorSizeComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(timeZoneComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(pathLabel) + .addComponent(noFatOrphansCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 262, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(0, 368, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(pathLabel) .addComponent(errorLabel) - .addComponent(noFatOrphansCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 262, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(0, 325, Short.MAX_VALUE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addGroup(layout.createSequentialGroup() + .addComponent(timeZoneLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(sectorSizeLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(sectorSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(md5HashLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(md5HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(sha1HashLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(sha1HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(sha256HashLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(sha256HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 455, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(hashValuesNoteLabel) + .addComponent(hashValuesLabel)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -244,6 +269,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(sectorSizeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(sectorSizeLabel)) + .addGap(39, 39, 39) + .addComponent(hashValuesLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(md5HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -257,8 +284,10 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addComponent(sha256HashTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(sha256HashLabel)) .addGap(18, 18, 18) + .addComponent(hashValuesNoteLabel) + .addGap(18, 18, 18) .addComponent(errorLabel) - .addContainerGap(23, Short.MAX_VALUE)) + .addContainerGap(51, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -286,6 +315,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { } } } + setContentPath(path); } @@ -295,6 +325,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton browseButton; private javax.swing.JLabel errorLabel; + private javax.swing.JLabel hashValuesLabel; + private javax.swing.JLabel hashValuesNoteLabel; private javax.swing.JLabel md5HashLabel; private javax.swing.JTextField md5HashTextField; private javax.swing.JCheckBox noFatOrphansCheckbox; @@ -310,6 +342,25 @@ public class ImageFilePanel extends JPanel implements DocumentListener { private javax.swing.JLabel timeZoneLabel; // End of variables declaration//GEN-END:variables + /** + * Enable or disable all of the hash values components. + * + * @param enabled Enable components if true; otherwise disable. + */ + private void setHashValuesComponentsEnabled(boolean enabled) { + hashValuesLabel.setEnabled(enabled); + hashValuesNoteLabel.setEnabled(enabled); + + md5HashLabel.setEnabled(enabled); + md5HashTextField.setEnabled(enabled); + + sha1HashLabel.setEnabled(enabled); + sha1HashTextField.setEnabled(enabled); + + sha256HashLabel.setEnabled(enabled); + sha256HashTextField.setEnabled(enabled); + } + /** * Get the path of the user selected image. * @@ -383,7 +434,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { errorLabel.setVisible(false); String path = getContentPaths(); - if (StringUtils.isBlank(path) || (!(new File(path).isFile() || DriveUtils.isPhysicalDrive(path) || DriveUtils.isPartition(path)))) { + if (!isImagePathValid()) { return false; } @@ -412,6 +463,16 @@ public class ImageFilePanel extends JPanel implements DocumentListener { return true; } + + private boolean isImagePathValid() { + String path = getContentPaths(); + + if (StringUtils.isBlank(path) || (!(new File(path).isFile() || DriveUtils.isPhysicalDrive(path) || DriveUtils.isPartition(path)))) { + return false; + } + + return true; + } public void storeSettings() { String imagePathName = getContentPaths(); @@ -446,13 +507,19 @@ public class ImageFilePanel extends JPanel implements DocumentListener { /** * Update functions are called by the pathTextField which has this set as * it's DocumentEventListener. Each update function fires a property change - * to be caught by the parent panel. - * + * to be caught by the parent panel. Additionally, the hash values will be + * enabled or disabled depending on the pathTextField input. */ @NbBundle.Messages({"ImageFilePanel.moduleErr=Module Error", "ImageFilePanel.moduleErr.msg=A module caused an error listening to ImageFilePanel updates." + " See log to determine which module. Some data could be incomplete.\n"}) private void updateHelper() { + if (isImagePathValid() && !getContentPaths().toLowerCase().endsWith(".e01")) { + setHashValuesComponentsEnabled(true); + } else { + setHashValuesComponentsEnabled(false); + } + firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java index 894603fe02..4ad7e54464 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java @@ -22,7 +22,6 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Arrays; import java.util.List; -import java.util.ArrayList; import java.util.logging.Level; import java.io.File; import javax.swing.JFileChooser; @@ -261,7 +260,7 @@ class MissingImageDialog extends javax.swing.JDialog { this.dispose(); } catch (TskCoreException ex) { lbWarning.setText(NbBundle.getMessage(this.getClass(), "MissingImageDialog.ErrorSettingImage")); - logger.log(Level.WARNING, "Error setting image paths", ex); //NON-NLS + logger.log(Level.SEVERE, "Error setting image paths", ex); //NON-NLS } }//GEN-LAST:event_selectButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableCellRenderer.java index 699c8755f1..9ba05589ce 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableCellRenderer.java @@ -49,7 +49,7 @@ public class DataContentViewerOtherCasesTableCellRenderer implements TableCellRe foreground = Color.WHITE; background = Color.BLUE; } else { - String known_status = (String) table.getModel().getValueAt(row, + String known_status = (String) table.getModel().getValueAt(table.convertRowIndexToModel(row), table.getColumn(DataContentViewerOtherCasesTableModel.TableColumns.KNOWN.columnName()).getModelIndex()); if (known_status.equals(TskData.FileKnown.BAD.getName())) { foreground = Color.WHITE; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index c61e19f79e..27c6407b5d 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -58,8 +58,8 @@ abstract class AbstractSqlEamDb implements EamDb { private final static Logger logger = Logger.getLogger(AbstractSqlEamDb.class.getName()); static final String SCHEMA_MAJOR_VERSION_KEY = "SCHEMA_VERSION"; static final String SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION"; - static final String CREATED_SCHEMA_MAJOR_VERSION_KEY = "CREATED_SCHEMA_MAJOR_VERSION"; - static final String CREATED_SCHEMA_MINOR_VERSION_KEY = "CREATED_SCHEMA_MINOR_VERSION"; + static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_VERSION"; + static final String CREATION_SCHEMA_MINOR_VERSION_KEY = "CREATION_SCHEMA_MINOR_VERSION"; static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION = new CaseDbSchemaVersionNumber(1, 2); protected final List defaultCorrelationTypes; @@ -3184,27 +3184,41 @@ abstract class AbstractSqlEamDb implements EamDb { statement = conn.createStatement(); int minorVersion = 0; - resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='SCHEMA_MINOR_VERSION'"); + String minorVersionStr = null; + resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + AbstractSqlEamDb.SCHEMA_MINOR_VERSION_KEY + "'"); if (resultSet.next()) { - String minorVersionStr = resultSet.getString("value"); + minorVersionStr = resultSet.getString("value"); try { minorVersion = Integer.parseInt(minorVersionStr); } catch (NumberFormatException ex) { throw new EamDbException("Bad value for schema minor version (" + minorVersionStr + ") - database is corrupt", ex); } + } else { + throw new EamDbException("Failed to read schema minor version from db_info table"); } int majorVersion = 0; - resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='SCHEMA_VERSION'"); + String majorVersionStr = null; + resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + AbstractSqlEamDb.SCHEMA_MAJOR_VERSION_KEY + "'"); if (resultSet.next()) { - String majorVersionStr = resultSet.getString("value"); + majorVersionStr = resultSet.getString("value"); try { majorVersion = Integer.parseInt(majorVersionStr); } catch (NumberFormatException ex) { throw new EamDbException("Bad value for schema version (" + majorVersionStr + ") - database is corrupt", ex); } + } else { + throw new EamDbException("Failed to read schema major version from db_info table"); } + /* + * IMPORTANT: The code that follows had a bug in it prior to Autopsy + * 4.10.0. The consequence of the bug is that the schema version + * number is always reset to 1.0 or 1.1 if a Central Repository is + * opened by an Autopsy 4.9.1 or earlier client. To cope with this, + * there is an effort in updates to 1.2 and greater to not retry + * schema updates that may already have been done once. + */ CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(majorVersion, minorVersion); if (dbSchemaVersion.equals(CURRENT_DB_SCHEMA_VERSION)) { logger.log(Level.INFO, "Central Repository is up to date"); @@ -3215,7 +3229,11 @@ abstract class AbstractSqlEamDb implements EamDb { return; } - // Update from 1.0 to 1.1 + EamDbPlatformEnum selectedPlatform = EamDbPlatformEnum.getSelectedPlatform(); + + /* + * Update to 1.1 + */ if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) { statement.execute("ALTER TABLE reference_sets ADD COLUMN known_status INTEGER;"); //NON-NLS statement.execute("ALTER TABLE reference_sets ADD COLUMN read_only BOOLEAN;"); //NON-NLS @@ -3226,9 +3244,11 @@ abstract class AbstractSqlEamDb implements EamDb { // regardless of whether this succeeds. EamDbUtil.insertDefaultOrganization(conn); } - //Update to 1.2 + + /* + * Update to 1.2 + */ if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) { - EamDbPlatformEnum selectedPlatform = EamDbPlatformEnum.getSelectedPlatform(); final String addIntegerColumnTemplate = "ALTER TABLE %s ADD COLUMN %s INTEGER;"; //NON-NLS final String addSsidTableTemplate; final String addCaseIdIndexTemplate; @@ -3362,26 +3382,50 @@ abstract class AbstractSqlEamDb implements EamDb { } /* - * Put values into the db_info table indicating that the - * creation schema version is not known. + * Drop the db_info table and add it back in with the name + * column having a UNIQUE constraint. The name column could now + * be used as the primary key, but the essentially useless id + * column is retained for the sake of backwards compatibility. + * Note that the creation schema version number is set to 0.0 + * to indicate that it is unknown. */ - statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATED_SCHEMA_MAJOR_VERSION_KEY + "', '0')"); - statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATED_SCHEMA_MINOR_VERSION_KEY + "', '0')"); - - } - if (!updateSchemaVersion(conn)) { - throw new EamDbException("Error updating schema version"); + String creationMajorVer; + resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + AbstractSqlEamDb.CREATION_SCHEMA_MAJOR_VERSION_KEY + "'"); + if (resultSet.next()) { + creationMajorVer = resultSet.getString("value"); + } else { + creationMajorVer = "0"; + } + String creationMinorVer; + resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + AbstractSqlEamDb.CREATION_SCHEMA_MINOR_VERSION_KEY + "'"); + if (resultSet.next()) { + creationMinorVer = resultSet.getString("value"); + } else { + creationMinorVer = "0"; + } + statement.execute("DROP TABLE db_info"); + if (selectedPlatform == EamDbPlatformEnum.POSTGRESQL) { + statement.execute("CREATE TABLE db_info (id SERIAL, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)"); + } else { + statement.execute("CREATE TABLE db_info (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)"); + } + statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.SCHEMA_MAJOR_VERSION_KEY + "','" + majorVersionStr + "')"); + statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.SCHEMA_MINOR_VERSION_KEY + "','" + minorVersionStr + "')"); + statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATION_SCHEMA_MAJOR_VERSION_KEY + "','" + creationMajorVer + "')"); + statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATION_SCHEMA_MINOR_VERSION_KEY + "','" + creationMinorVer + "')"); } + updateSchemaVersion(conn); conn.commit(); - logger.log(Level.INFO, "Central Repository upgraded to version " + CURRENT_DB_SCHEMA_VERSION); + logger.log(Level.INFO, String.format("Central Repository schema updated to version %s", CURRENT_DB_SCHEMA_VERSION)); + } catch (SQLException | EamDbException ex) { try { if (conn != null) { conn.rollback(); } } catch (SQLException ex2) { - logger.log(Level.SEVERE, "Database rollback failed", ex2); + logger.log(Level.SEVERE, String.format("Central Repository rollback of failed schema update to %s failed", CURRENT_DB_SCHEMA_VERSION), ex2); } throw ex; } finally { diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java index 3ee0a40d85..8c137472e2 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java @@ -27,6 +27,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Content; @@ -76,85 +77,62 @@ public class EamArtifactUtil { artifactForInstance = artifact; } if (artifactForInstance != null) { - switch (BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactForInstance.getArtifactTypeID())) { - case TSK_KEYWORD_HIT: { - BlackboardAttribute setNameAttr = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); - if (setNameAttr != null - && EamArtifactUtil.getEmailAddressAttrString().equals(setNameAttr.getValueString())) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID); - } - break; + int artifactTypeID = artifactForInstance.getArtifactTypeID(); + if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { + BlackboardAttribute setNameAttr = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); + if (setNameAttr != null + && EamArtifactUtil.getEmailAddressAttrString().equals(setNameAttr.getValueString())) { + addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID); } - case TSK_WEB_BOOKMARK: - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID); - break; - case TSK_WEB_COOKIE: - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID); - break; - case TSK_WEB_DOWNLOAD: - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID); - break; - case TSK_WEB_HISTORY: - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID); - break; - case TSK_CONTACT: - //generates the same correlation attrs as tsk_message - case TSK_CALLLOG: - //generates the same correlation attrs as tsk_message - case TSK_MESSAGE: { - String value = null; - if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) { - value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString(); - } else if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) { - value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString(); - } else if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) { - value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString(); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() + || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() + || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() + || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID()) { + addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID() + || artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() + || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) { + + String value = null; + if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) { + value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString(); + } else if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) { + value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString(); + } else if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) { + value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString(); + } + // Remove all non-numeric symbols to semi-normalize phone numbers, preserving leading "+" character + if (value != null) { + String newValue = value.replaceAll("\\D", ""); + if (value.startsWith("+")) { + newValue = "+" + newValue; } - // Remove all non-numeric symbols to semi-normalize phone numbers, preserving leading "+" character - if (value != null) { - String newValue = value.replaceAll("\\D", ""); - if (value.startsWith("+")) { - newValue = "+" + newValue; - } - value = newValue; - // Only add the correlation attribute if the resulting phone number large enough to be of use - // (these 3-5 digit numbers can be valid, but are not useful for correlation) - if (value.length() > 5) { - CorrelationAttributeInstance inst = makeCorrelationAttributeInstanceUsingTypeValue(artifactForInstance, EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value); - if (inst != null) { - eamArtifacts.add(inst); - } + value = newValue; + // Only add the correlation attribute if the resulting phone number large enough to be of use + // (these 3-5 digit numbers can be valid, but are not useful for correlation) + if (value.length() > 5) { + CorrelationAttributeInstance inst = makeCorrelationAttributeInstanceUsingTypeValue(artifactForInstance, EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value); + if (inst != null) { + eamArtifacts.add(inst); } } - break; } - case TSK_DEVICE_ATTACHED: - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID); - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); - break; - case TSK_WIFI_NETWORK: - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID); - break; - case TSK_WIFI_NETWORK_ADAPTER: - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); - break; - case TSK_BLUETOOTH_PAIRING: - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); - break; - case TSK_BLUETOOTH_ADAPTER: - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); - break; - case TSK_DEVICE_INFO: - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID); - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); - break; - case TSK_SIM_ATTACHED: - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); - break; - default: - break; + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) { + addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID); + addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) { + addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID() + || artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() + || artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()) { + addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) { + addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID); + addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); + addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) { + addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); + addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); } } } catch (EamDbException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java old mode 100644 new mode 100755 diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java index 3129d1222e..6e629b52e2 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java @@ -126,42 +126,17 @@ public class EamDbUtil { } /** - * Store the schema version into the db_info table. - * - * This should be called immediately following the database schema being - * loaded. + * Writes the current schema version into the database. * * @param conn Open connection to use. * - * @return true on success, else false + * @throws SQLException If there is an error doing the update. */ - static boolean updateSchemaVersion(Connection conn) { - - Statement statement; - ResultSet resultSet; - try { - statement = conn.createStatement(); - resultSet = statement.executeQuery("SELECT id FROM db_info WHERE name='SCHEMA_VERSION'"); - if (resultSet.next()) { - int id = resultSet.getInt("id"); - statement.execute("UPDATE db_info SET value=" + CURRENT_DB_SCHEMA_VERSION.getMajor() + " WHERE id=" + id); - } else { - statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')"); - } - - resultSet = statement.executeQuery("SELECT id FROM db_info WHERE name='SCHEMA_MINOR_VERSION'"); - if (resultSet.next()) { - int id = resultSet.getInt("id"); - statement.execute("UPDATE db_info SET value=" + CURRENT_DB_SCHEMA_VERSION.getMinor() + " WHERE id=" + id); - } else { - statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_MINOR_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')"); - } - } catch (SQLException ex) { - LOGGER.log(Level.SEVERE, "Error adding schema version to db_info.", ex); - return false; + static void updateSchemaVersion(Connection conn) throws SQLException { + try (Statement statement = conn.createStatement()) { + statement.execute("UPDATE db_info SET value = '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "' WHERE name = '" + AbstractSqlEamDb.SCHEMA_MAJOR_VERSION_KEY + "'"); + statement.execute("UPDATE db_info SET value = '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "' WHERE name = '" + AbstractSqlEamDb.SCHEMA_MINOR_VERSION_KEY + "'"); } - - return true; } /** @@ -191,9 +166,9 @@ public class EamDbUtil { } /** - * Upgrade the current central reposity to the newest version. If the upgrade - * fails, the central repository will be disabled and the current settings - * will be cleared. + * Upgrade the current Central Reposity schema to the newest version. If the + * upgrade fails, the Central Repository will be disabled and the current + * settings will be cleared. * * @return true if the upgrade succeeds, false otherwise. */ @@ -201,7 +176,7 @@ public class EamDbUtil { if (!EamDb.isEnabled()) { return true; } - + CoordinationService.Lock lock = null; try { EamDb db = EamDb.getInstance(); @@ -217,23 +192,23 @@ public class EamDbUtil { LOGGER.log(Level.SEVERE, "Error updating central repository", ex); // Disable the central repo and clear the current settings. - try{ + try { if (null != EamDb.getInstance()) { EamDb.getInstance().shutdownConnections(); } - } catch (EamDbException ex2){ + } catch (EamDbException ex2) { LOGGER.log(Level.SEVERE, "Error shutting down central repo connection pool", ex); - } + } setUseCentralRepo(false); EamDbPlatformEnum.setSelectedPlatform(EamDbPlatformEnum.DISABLED.name()); EamDbPlatformEnum.saveSelectedPlatform(); - + return false; } finally { - if(lock != null){ - try{ + if (lock != null) { + try { lock.release(); - } catch (CoordinationServiceException ex){ + } catch (CoordinationServiceException ex) { LOGGER.log(Level.SEVERE, "Error releasing database lock", ex); } } @@ -254,6 +229,7 @@ public class EamDbUtil { * Check whether the given org is the default organization. * * @param org + * * @return true if it is the default org, false otherwise */ public static boolean isDefaultOrg(EamOrganization org) { @@ -264,6 +240,7 @@ public class EamDbUtil { * Add the default organization to the database * * @param conn + * * @return true if successful, false otherwise */ static boolean insertDefaultOrganization(Connection conn) { @@ -294,7 +271,7 @@ public class EamDbUtil { * If the Central Repos use has been enabled. * * @return true if the Central Repo may be configured, false if it should - * not be able to be + * not be able to be */ public static boolean useCentralRepo() { return Boolean.parseBoolean(ModuleSettings.getConfigSetting(CENTRAL_REPO_NAME, CENTRAL_REPO_USE_KEY)); @@ -305,7 +282,7 @@ public class EamDbUtil { * configured. * * @param centralRepoCheckBoxIsSelected - true if the central repo can be - * used + * used */ public static void setUseCentralRepo(boolean centralRepoCheckBoxIsSelected) { ModuleSettings.setConfigSetting(CENTRAL_REPO_NAME, CENTRAL_REPO_USE_KEY, Boolean.toString(centralRepoCheckBoxIsSelected)); @@ -364,7 +341,7 @@ public class EamDbUtil { * Close the prepared statement. * * @param preparedStatement The prepared statement to be closed. - * + * * @deprecated Use closeStatement() instead. * * @throws EamDbException diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java old mode 100644 new mode 100755 diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java index fa1fe9207b..14a5719f52 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java @@ -406,13 +406,6 @@ public final class PostgresEamDbSettings { String instancesKnownStatusIdx = getAddKnownStatusIndexTemplate(); String instancesObjectIdIdx = getAddObjectIdIndexTemplate(); - StringBuilder createDbInfoTable = new StringBuilder(); - createDbInfoTable.append("CREATE TABLE IF NOT EXISTS db_info ("); - createDbInfoTable.append("id SERIAL PRIMARY KEY NOT NULL,"); - createDbInfoTable.append("name text NOT NULL,"); - createDbInfoTable.append("value text NOT NULL"); - createDbInfoTable.append(")"); - // NOTE: the db_info table currenly only has 1 row, so having an index // provides no benefit. Connection conn = null; @@ -438,11 +431,16 @@ public final class PostgresEamDbSettings { stmt.execute(createCorrelationTypesTable.toString()); - stmt.execute(createDbInfoTable.toString()); + /* + * Note that the essentially useless id column in the following + * table is required for backwards compatibility. Otherwise, the + * name column could be the primary key. + */ + stmt.execute("CREATE TABLE db_info (id SERIAL, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)"); stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.SCHEMA_MAJOR_VERSION_KEY + "', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')"); stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.SCHEMA_MINOR_VERSION_KEY + "', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATED_SCHEMA_MAJOR_VERSION_KEY + "', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATED_SCHEMA_MINOR_VERSION_KEY + "', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATION_SCHEMA_MINOR_VERSION_KEY + "', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')"); // Create a separate instance and reference table for each correlation type List DEFAULT_CORRELATION_TYPES = CorrelationAttributeInstance.getDefaultCorrelationTypes(); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java index 8ebf70b14e..4851e51b51 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java @@ -291,7 +291,7 @@ public final class SqliteEamDbSettings { createDataSourcesTable.append("datasource_obj_id integer,"); createDataSourcesTable.append("md5 text DEFAULT NULL,"); createDataSourcesTable.append("sha1 text DEFAULT NULL,"); - createDataSourcesTable.append("sha256 text DEFAULT NULL,"); + createDataSourcesTable.append("sha256 text DEFAULT NULL,"); createDataSourcesTable.append("foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,"); createDataSourcesTable.append("CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name)"); createDataSourcesTable.append(")"); @@ -348,13 +348,6 @@ public final class SqliteEamDbSettings { String instancesValueIdx = getAddValueIndexTemplate(); String instancesKnownStatusIdx = getAddKnownStatusIndexTemplate(); String instancesObjectIdIdx = getAddObjectIdIndexTemplate(); - - StringBuilder createDbInfoTable = new StringBuilder(); - createDbInfoTable.append("CREATE TABLE IF NOT EXISTS db_info ("); - createDbInfoTable.append("id integer primary key NOT NULL,"); - createDbInfoTable.append("name text NOT NULL,"); - createDbInfoTable.append("value text NOT NULL"); - createDbInfoTable.append(")"); // NOTE: the db_info table currenly only has 1 row, so having an index // provides no benefit. @@ -387,11 +380,16 @@ public final class SqliteEamDbSettings { stmt.execute(createCorrelationTypesTable.toString()); - stmt.execute(createDbInfoTable.toString()); + /* + * Note that the essentially useless id column in the following + * table is required for backwards compatibility. Otherwise, the + * name column could be the primary key. + */ + stmt.execute("CREATE TABLE db_info (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)"); stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.SCHEMA_MAJOR_VERSION_KEY + "', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')"); stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.SCHEMA_MINOR_VERSION_KEY + "', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATED_SCHEMA_MAJOR_VERSION_KEY + "', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATED_SCHEMA_MINOR_VERSION_KEY + "', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATION_SCHEMA_MINOR_VERSION_KEY + "', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')"); // Create a separate instance and reference table for each artifact type List DEFAULT_CORRELATION_TYPES = CorrelationAttributeInstance.getDefaultCorrelationTypes(); @@ -427,7 +425,7 @@ public final class SqliteEamDbSettings { } return true; } - + /** * Get the template String for creating a new _instances table in a Sqlite * central repository. %s will exist in the template where the name of the @@ -511,8 +509,8 @@ public final class SqliteEamDbSettings { * instance table. %s will exist in the template where the name of the new * table will be addedd. * - * @return a String which is a template for adding an index to the file_obj_id - * column of a _instances table + * @return a String which is a template for adding an index to the + * file_obj_id column of a _instances table */ static String getAddObjectIdIndexTemplate() { // Each "%s" will be replaced with the relevant TYPE_instances table name. diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CentralRepoCommonAttributeInstance.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CentralRepoCommonAttributeInstance.java index cfcc40e603..7847b31ca4 100644 --- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CentralRepoCommonAttributeInstance.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CentralRepoCommonAttributeInstance.java @@ -81,7 +81,7 @@ final public class CentralRepoCommonAttributeInstance extends AbstractCommonAttr // Find the correct data source Optional dataSource = tskDb.getDataSources().stream() - .filter(p -> p.getDeviceId().equals(currentAttribute.getCorrelationDataSource().getDeviceID())) + .filter(p -> p.getId() == currentAttribute.getCorrelationDataSource().getDataSourceObjectID()) .findFirst(); if (!dataSource.isPresent()) { LOGGER.log(Level.WARNING, String.format("Unable to find data source with device ID %s in the current case", currentAttribute.getCorrelationDataSource().getDeviceID())); diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributePanel.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributePanel.java index 0bad76d40d..a4d6fe7b17 100644 --- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributePanel.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributePanel.java @@ -19,7 +19,7 @@ package org.sleuthkit.autopsy.commonfilesearch; import org.sleuthkit.autopsy.guiutils.DataSourceComboBoxModel; -import org.sleuthkit.autopsy.guiutils.DataSourceLoader; +import org.sleuthkit.autopsy.datamodel.utils.DataSourceLoader; import java.awt.Dimension; import java.sql.SQLException; import java.util.ArrayList; diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/InterCaseSearchResultsProcessor.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/InterCaseSearchResultsProcessor.java index 173a472f1f..37426184ba 100644 --- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/InterCaseSearchResultsProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/InterCaseSearchResultsProcessor.java @@ -331,8 +331,8 @@ final class InterCaseSearchResultsProcessor { CorrelationCase correlationCase = EamDb.getInstance().getCaseById(InstanceTableCallback.getCaseId(resultSet)); String caseName = correlationCase.getDisplayName(); CorrelationDataSource correlationDatasource = EamDb.getInstance().getDataSourceById(correlationCase, InstanceTableCallback.getDataSourceId(resultSet)); -// String dataSourceName = correlationDatasource.getName(); - String dataSourceNameKey = correlationDatasource.getName() + correlationDatasource.getDataSourceObjectID(); + //label datasource with it's id for uniqueness done in same manner as ImageGallery does in the DataSourceCell class + String dataSourceNameKey = correlationDatasource.getName() + " (Id: " + correlationDatasource.getDataSourceObjectID() + ")"; if (!caseCollatedDataSourceCollections.containsKey(caseName)) { caseCollatedDataSourceCollections.put(caseName, new HashMap()); } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java index c33a653292..84f216e253 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java @@ -46,7 +46,7 @@ public class FileViewer extends javax.swing.JPanel implements DataContentViewer private final Map mimeTypeToViewerMap = new HashMap<>(); // TBD: This hardcoded list of viewers should be replaced with a dynamic lookup - private static final FileTypeViewer[] KNOWN_VIEWERS = new FileTypeViewer[]{ + private final FileTypeViewer[] KNOWN_VIEWERS = new FileTypeViewer[]{ new SQLiteViewer(), new PListViewer(), new MediaFileViewer() diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java index 06a442eb2a..740bf6511d 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java @@ -27,7 +27,6 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Image; -import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.FsContent; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; @@ -116,7 +115,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { } private void addRow(StringBuilder sb, String key, String value) { - sb.append(""); //NON-NLS + sb.append(""); //NON-NLS sb.append(key); sb.append(""); //NON-NLS sb.append(value); @@ -238,6 +237,18 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.timezone"), image.getTimeZone()); addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.deviceId"), image.getDeviceId()); addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.internalid"), Long.toString(image.getId())); + + // Add all the data source paths to the "Local Path" value cell. + String[] imagePaths = image.getPaths(); + StringBuilder pathValues = new StringBuilder("
"); + pathValues.append(imagePaths[0]); + pathValues.append("
"); + for (int i=1; i < imagePaths.length; i++) { + pathValues.append("
"); + pathValues.append(imagePaths[i]); + pathValues.append("
"); + } + addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.localPath"), pathValues.toString()); } setText(sb.toString()); diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java index f2db7c2532..104c70ef6b 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java @@ -457,10 +457,10 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { */ private void initReader() { viewReader = new SQLiteTableReader.Builder(sqliteDbFile) - .onColumnNames((columnName) -> { + .forAllColumnNames((columnName) -> { currentTableHeader.add(columnName); }) - .forAll(getForAllStrategy()).build(); + .forAllTableValues(getForAllStrategy()).build(); } /** @@ -510,8 +510,8 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { String tableName = (String) this.tablesDropdownList.getSelectedItem(); try (FileOutputStream out = new FileOutputStream(csvFile, false)) { try (SQLiteTableReader sqliteStream = new SQLiteTableReader.Builder(sqliteDbFile) - .onColumnNames(getColumnNameCSVStrategy(out)) - .forAll(getForAllCSVStrategy(out)).build()) { + .forAllColumnNames(getColumnNameCSVStrategy(out)) + .forAllTableValues(getForAllCSVStrategy(out)).build()) { totalColumnCount = sqliteStream.getColumnCount(tableName); sqliteStream.read(tableName); } diff --git a/Core/src/org/sleuthkit/autopsy/coordinationservice/CoordinationService.java b/Core/src/org/sleuthkit/autopsy/coordinationservice/CoordinationService.java index 6272cc9ab7..36cf5a503c 100644 --- a/Core/src/org/sleuthkit/autopsy/coordinationservice/CoordinationService.java +++ b/Core/src/org/sleuthkit/autopsy/coordinationservice/CoordinationService.java @@ -357,6 +357,24 @@ public final class CoordinationService { } } + /** + * Deletes a specified node. + * + * @param category The desired category in the namespace. + * @param nodePath The node to be deleted. + * + * @throws CoordinationServiceException If there is an error deleting the + * node. + */ + void deleteNode(CategoryNode category, String nodePath) throws CoordinationServiceException { + String fullNodePath = getFullyQualifiedNodePath(category, nodePath); + try { + curator.delete().forPath(fullNodePath); + } catch (Exception ex) { + throw new CoordinationServiceException(String.format("Failed to delete node %s", fullNodePath), ex); + } + } + /** * Gets a list of the child nodes of a category in the namespace. * diff --git a/Core/src/org/sleuthkit/autopsy/core/Installer.java b/Core/src/org/sleuthkit/autopsy/core/Installer.java index e45055b077..2f65b6099b 100644 --- a/Core/src/org/sleuthkit/autopsy/core/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/core/Installer.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.core; import java.awt.Cursor; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; @@ -29,6 +30,8 @@ import java.util.logging.Handler; import java.util.logging.Level; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; +import org.apache.commons.io.FileUtils; +import org.openide.modules.InstalledFileLocator; import org.openide.modules.ModuleInstall; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; @@ -285,12 +288,34 @@ public class Installer extends ModuleInstall { File pythonModulesDir = new File(PlatformUtil.getUserPythonModulesPath()); pythonModulesDir.mkdir(); } + + /** + * Make a folder in the config directory for Ocr Language Packs if one does + * not exist. + */ + private static void ensureOcrLanguagePacksFolderExists() { + File ocrLanguagePacksDir = new File(PlatformUtil.getOcrLanguagePacksPath()); + boolean createDirectory = ocrLanguagePacksDir.mkdir(); + + //If the directory did not exist, copy the tessdata folder over so we + //support english. + if(createDirectory) { + File tessdataDir = InstalledFileLocator.getDefault().locate( + "Tesseract-OCR/tessdata", Installer.class.getPackage().getName(), false); + try { + FileUtils.copyDirectory(tessdataDir, ocrLanguagePacksDir); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Copying over default language packs for Tesseract failed.", ex); + } + } + } @Override public void restored() { super.restored(); ensurePythonModulesFolderExists(); ensureClassifierFolderExists(); + ensureOcrLanguagePacksFolderExists(); initJavaFx(); for (ModuleInstall mi : packageInstallers) { try { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index cdc54a12b6..299b0e18d4 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -173,9 +173,8 @@ ViewPreferencesPanel.currentSessionSettingsPanel.border.title=Current Session Se ViewPreferencesPanel.hideRejectedResultsCheckbox.text=Hide rejected results ViewPreferencesPanel.selectFileLabel.text=When selecting a file: ViewPreferencesPanel.globalSettingsPanel.border.title=Global Settings -ViewPreferencesPanel.translateNamesInTableRadioButton.text=Table ViewPreferencesPanel.commentsOccurencesColumnWrapAroundText.text=to reduce loading times -ViewPreferencesPanel.translateTextLabel.text=Translate text in the: +ViewPreferencesPanel.translateTextLabel.text=Translate text: ViewPreferencesPanel.commentsOccurencesColumnsCheckbox.text=C(omments) and O(ccurences) columns ViewPreferencesPanel.centralRepoLabel.text=Do not use Central Repository for: ViewPreferencesPanel.hideOtherUsersTagsLabel.text=Hide other users' tags in the: @@ -193,3 +192,4 @@ ViewPreferencesPanel.keepCurrentViewerRadioButton.toolTipText=For example, stay ViewPreferencesPanel.keepCurrentViewerRadioButton.text=Stay on the same file viewer ViewPreferencesPanel.useBestViewerRadioButton.toolTipText=For example, change from Hex to Media when a JPEG is selected. ViewPreferencesPanel.useBestViewerRadioButton.text=Change to the most specific file viewer +ViewPreferencesPanel.fileNameTranslationColumnCheckbox.text=Add column in result viewer for file name translation diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.form b/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.form index 8b56df7929..a348b49368 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.form @@ -144,11 +144,11 @@ + - @@ -203,7 +203,7 @@ - + @@ -397,14 +397,14 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java index 4900a48a78..cdea98caf6 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java @@ -80,10 +80,10 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { commentsOccurencesColumnsCheckbox.setSelected(UserPreferences.hideCentralRepoCommentsAndOccurrences()); hideOtherUsersTagsCheckbox.setSelected(UserPreferences.showOnlyCurrentUserTags()); - translateNamesInTableRadioButton.setSelected(UserPreferences.displayTranslatedFileNames()); + fileNameTranslationColumnCheckbox.setSelected(UserPreferences.displayTranslatedFileNames()); TextTranslationService tts = TextTranslationService.getInstance(); - translateNamesInTableRadioButton.setEnabled(tts.hasProvider()); + fileNameTranslationColumnCheckbox.setEnabled(tts.hasProvider()); // Current Case Settings boolean caseIsOpen = Case.isCaseOpen(); @@ -113,7 +113,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCheckbox.isSelected()); UserPreferences.setShowOnlyCurrentUserTags(hideOtherUsersTagsCheckbox.isSelected()); UserPreferences.setHideCentralRepoCommentsAndOccurrences(commentsOccurencesColumnsCheckbox.isSelected()); - UserPreferences.setDisplayTranslatedFileNames(translateNamesInTableRadioButton.isSelected()); + UserPreferences.setDisplayTranslatedFileNames(fileNameTranslationColumnCheckbox.isSelected()); storeGroupItemsInTreeByDataSource(); @@ -166,7 +166,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { timeZoneList = new javax.swing.JList<>(); translateTextLabel = new javax.swing.JLabel(); commentsOccurencesColumnWrapAroundText = new javax.swing.JLabel(); - translateNamesInTableRadioButton = new javax.swing.JRadioButton(); + fileNameTranslationColumnCheckbox = new javax.swing.JCheckBox(); currentCaseSettingsPanel = new javax.swing.JPanel(); groupByDataSourceCheckbox = new javax.swing.JCheckBox(); currentSessionSettingsPanel = new javax.swing.JPanel(); @@ -277,10 +277,10 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { org.openide.awt.Mnemonics.setLocalizedText(commentsOccurencesColumnWrapAroundText, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.commentsOccurencesColumnWrapAroundText.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(translateNamesInTableRadioButton, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.translateNamesInTableRadioButton.text")); // NOI18N - translateNamesInTableRadioButton.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(fileNameTranslationColumnCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.fileNameTranslationColumnCheckbox.text")); // NOI18N + fileNameTranslationColumnCheckbox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - translateNamesInTableRadioButtonActionPerformed(evt); + fileNameTranslationColumnCheckboxActionPerformed(evt); } }); @@ -329,11 +329,11 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { .addGroup(globalSettingsPanelLayout.createSequentialGroup() .addGap(10, 10, 10) .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(fileNameTranslationColumnCheckbox) .addComponent(keepCurrentViewerRadioButton) .addComponent(useBestViewerRadioButton) .addComponent(useLocalTimeRadioButton) - .addComponent(useAnotherTimeRadioButton) - .addComponent(translateNamesInTableRadioButton)))))) + .addComponent(useAnotherTimeRadioButton)))))) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); globalSettingsPanelLayout.setVerticalGroup( @@ -380,7 +380,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(translateTextLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(translateNamesInTableRadioButton))) + .addComponent(fileNameTranslationColumnCheckbox))) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); @@ -487,14 +487,6 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { } }//GEN-LAST:event_hideRejectedResultsCheckboxActionPerformed - private void translateNamesInTableRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_translateNamesInTableRadioButtonActionPerformed - if (immediateUpdates) { - UserPreferences.setDisplayTranslatedFileNames(translateNamesInTableRadioButton.isSelected()); - } else { - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - } - }//GEN-LAST:event_translateNamesInTableRadioButtonActionPerformed - private void timeZoneListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_timeZoneListValueChanged if (immediateUpdates && useAnotherTimeRadioButton.isSelected()) { UserPreferences.setTimeZoneForDisplays(timeZoneList.getSelectedValue().substring(11).trim()); @@ -593,6 +585,14 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { } }//GEN-LAST:event_useBestViewerRadioButtonActionPerformed + private void fileNameTranslationColumnCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileNameTranslationColumnCheckboxActionPerformed + if (immediateUpdates) { + UserPreferences.setDisplayTranslatedFileNames(fileNameTranslationColumnCheckbox.isSelected()); + } else { + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + } + }//GEN-LAST:event_fileNameTranslationColumnCheckboxActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel centralRepoLabel; @@ -603,6 +603,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { private javax.swing.JCheckBox dataSourcesHideKnownCheckbox; private javax.swing.JCheckBox dataSourcesHideSlackCheckbox; private javax.swing.JLabel displayTimeLabel; + private javax.swing.JCheckBox fileNameTranslationColumnCheckbox; private javax.swing.JPanel globalSettingsPanel; private javax.swing.JCheckBox groupByDataSourceCheckbox; private javax.swing.JLabel hideKnownFilesLabel; @@ -614,7 +615,6 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { private javax.swing.JRadioButton keepCurrentViewerRadioButton; private javax.swing.JLabel selectFileLabel; private javax.swing.JList timeZoneList; - private javax.swing.JRadioButton translateNamesInTableRadioButton; private javax.swing.JLabel translateTextLabel; private javax.swing.JRadioButton useAnotherTimeRadioButton; private javax.swing.JRadioButton useBestViewerRadioButton; diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/PlatformUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/PlatformUtil.java index f0a3086588..a785bdf638 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/PlatformUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/PlatformUtil.java @@ -52,6 +52,7 @@ public class PlatformUtil { private static final String PYTHON_MODULES_SUBDIRECTORY = "python_modules"; //NON-NLS private static final String CLASSIFIERS_SUBDIRECTORY = "object_detection_classifiers"; //NON-NLS + private static final String OCR_LANGUAGE_SUBDIRECTORY = "ocr_language_packs"; //NON-NLS private static String javaPath = null; public static final String OS_NAME_UNKNOWN = NbBundle.getMessage(PlatformUtil.class, "PlatformUtil.nameUnknown"); public static final String OS_VERSION_UNKNOWN = NbBundle.getMessage(PlatformUtil.class, "PlatformUtil.verUnknown"); @@ -116,6 +117,15 @@ public class PlatformUtil { public static String getUserPythonModulesPath() { return getUserDirectory().getAbsolutePath() + File.separator + PYTHON_MODULES_SUBDIRECTORY; } + + /** + * Get root path where the user's Ocr language packs are stored. + * + * @return Absolute path to the Ocr language packs root directory. + */ + public static String getOcrLanguagePacksPath() { + return getUserDirectory().getAbsolutePath() + File.separator + OCR_LANGUAGE_SUBDIRECTORY; + } /** * Get root path where the user's object detection classifiers are stored. diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/SQLiteTableReader.java b/Core/src/org/sleuthkit/autopsy/coreutils/SQLiteTableReader.java index 2be988c7ed..59940d9e4c 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/SQLiteTableReader.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/SQLiteTableReader.java @@ -42,30 +42,14 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; /** - * Reads row by row through SQLite tables and performs user-defined actions on - * the row values. Table values are processed by data type. Users configure - * these actions for certain data types in the Builder. Example usage: - * - * SQLiteTableReader reader = new SQLiteTableReader.Builder(file) - * .onInteger((i) - * -> { System.out.println(i); }) - * .build(); - * - * reader.read(tableName); - * - * or - * - * SQLiteTableReader reader = new SQLiteTableReader.Builder(file) - * .onInteger(new Consumer() { - * (atSymbol)Override public void accept(Integer i) { - * System.out.println(i); - * } - * }).build(); + * Reads through SQLite tables row by row. Functions performed on the + * data must be declared up front to the Builder. For example: * - * reader.reader(tableName); - * - * Invocation of read(String tableName) reads row by row. When an Integer is - * encountered, its value will be passed to the Consumer that was defined above. + * tableReader = new SQLiteTableReader.Builder(file).forAllColumnNames(System.out::println); + * tableReader.read("Sample Table X"); + * + * By declaring the functions up front, the SQLiteTableReader instance can stream the + * table contents in the most memory efficient manner. */ public class SQLiteTableReader implements AutoCloseable { @@ -76,13 +60,13 @@ public class SQLiteTableReader implements AutoCloseable { private final AbstractFile file; - private Consumer onColumnNameAction; - private Consumer onStringAction; - private Consumer onLongAction; - private Consumer onIntegerAction; - private Consumer onFloatAction; - private Consumer onBlobAction; - private Consumer forAllAction; + private Consumer forAllColumnNamesConsumer; + private Consumer forAllStringValuesConsumer; + private Consumer forAllLongValuesConsumer; + private Consumer forAllIntegerValuesConsumer; + private Consumer forAllFloatValuesConsumer; + private Consumer forAllBlobValuesConsumer; + private Consumer forAllTableValuesConsumer; static Consumer doNothing() { return NOOP -> {}; @@ -96,13 +80,13 @@ public class SQLiteTableReader implements AutoCloseable { public Builder(AbstractFile file) { this.file = file; - this.onColumnNameAction = Builder.doNothing(); - this.onStringAction = Builder.doNothing(); - this.onLongAction = Builder.doNothing(); - this.onIntegerAction = Builder.doNothing(); - this.onFloatAction = Builder.doNothing(); - this.onBlobAction = Builder.doNothing(); - this.forAllAction = Builder.doNothing(); + this.forAllColumnNamesConsumer = Builder.doNothing(); + this.forAllStringValuesConsumer = Builder.doNothing(); + this.forAllLongValuesConsumer = Builder.doNothing(); + this.forAllIntegerValuesConsumer = Builder.doNothing(); + this.forAllFloatValuesConsumer = Builder.doNothing(); + this.forAllBlobValuesConsumer = Builder.doNothing(); + this.forAllTableValuesConsumer = Builder.doNothing(); } /** @@ -113,8 +97,8 @@ public class SQLiteTableReader implements AutoCloseable { * * @return Builder reference */ - public Builder onColumnNames(Consumer action) { - this.onColumnNameAction = action; + public Builder forAllColumnNames(Consumer action) { + this.forAllColumnNamesConsumer = action; return this; } @@ -126,8 +110,8 @@ public class SQLiteTableReader implements AutoCloseable { * * @return Builder reference */ - public Builder onString(Consumer action) { - this.onStringAction = action; + public Builder forAllStringValues(Consumer action) { + this.forAllStringValuesConsumer = action; return this; } @@ -139,8 +123,8 @@ public class SQLiteTableReader implements AutoCloseable { * * @return Builder reference */ - public Builder onInteger(Consumer action) { - this.onIntegerAction = action; + public Builder forAllIntegerValues(Consumer action) { + this.forAllIntegerValuesConsumer = action; return this; } @@ -152,8 +136,8 @@ public class SQLiteTableReader implements AutoCloseable { * * @return Builder reference */ - public Builder onFloat(Consumer action) { - this.onFloatAction = action; + public Builder forAllFloatValues(Consumer action) { + this.forAllFloatValuesConsumer = action; return this; } @@ -165,8 +149,8 @@ public class SQLiteTableReader implements AutoCloseable { * * @return Builder reference */ - public Builder onLong(Consumer action) { - this.onLongAction = action; + public Builder forAllLongValues(Consumer action) { + this.forAllLongValuesConsumer = action; return this; } @@ -178,8 +162,8 @@ public class SQLiteTableReader implements AutoCloseable { * * @return Builder reference */ - public Builder onBlob(Consumer action) { - this.onBlobAction = action; + public Builder forAllBlobValues(Consumer action) { + this.forAllBlobValuesConsumer = action; return this; } @@ -192,8 +176,8 @@ public class SQLiteTableReader implements AutoCloseable { * * @return Builder reference */ - public Builder forAll(Consumer action) { - this.forAllAction = action; + public Builder forAllTableValues(Consumer action) { + this.forAllTableValuesConsumer = action; return this; } @@ -366,7 +350,7 @@ public class SQLiteTableReader implements AutoCloseable { if (condition.getAsBoolean()) { return; } - builder.onColumnNameAction.accept(currentMetadata + builder.forAllColumnNamesConsumer.accept(currentMetadata .getColumnName(++columnNameIndex)); } @@ -379,18 +363,18 @@ public class SQLiteTableReader implements AutoCloseable { Object item = queryResults.getObject(++currRowColumnIndex); if (item instanceof String) { - builder.onStringAction.accept((String) item); + builder.forAllStringValuesConsumer.accept((String) item); } else if (item instanceof Integer) { - builder.onIntegerAction.accept((Integer) item); + builder.forAllIntegerValuesConsumer.accept((Integer) item); } else if (item instanceof Double) { - builder.onFloatAction.accept((Double) item); + builder.forAllFloatValuesConsumer.accept((Double) item); } else if (item instanceof Long) { - builder.onLongAction.accept((Long) item); + builder.forAllLongValuesConsumer.accept((Long) item); } else if (item instanceof byte[]) { - builder.onBlobAction.accept((byte[]) item); + builder.forAllBlobValuesConsumer.accept((byte[]) item); } - builder.forAllAction.accept(item); + builder.forAllTableValuesConsumer.accept(item); } unfinishedRow = false; //Wrap column index back around if we've reached the end of the row diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index a89c1bff8a..f9b7690f4c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -31,7 +31,7 @@ import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNod import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode; import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode; import org.sleuthkit.autopsy.datamodel.accounts.Accounts; -import org.sleuthkit.autopsy.othercasessearch.CorrelationAttributeInstanceNode; +import org.sleuthkit.autopsy.allcasessearch.CorrelationAttributeInstanceNode; /** * Visitor pattern that goes over all nodes in the directory tree. This includes diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/DataSourceLoader.java b/Core/src/org/sleuthkit/autopsy/datamodel/utils/DataSourceLoader.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/guiutils/DataSourceLoader.java rename to Core/src/org/sleuthkit/autopsy/datamodel/utils/DataSourceLoader.java index deb333780a..0c1329d9f6 100644 --- a/Core/src/org/sleuthkit/autopsy/guiutils/DataSourceLoader.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/utils/DataSourceLoader.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.guiutils; +package org.sleuthkit.autopsy.datamodel.utils; import java.io.File; import java.sql.ResultSet; diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java index 265cab388f..5e4f9ce03b 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorDashboard.java @@ -46,10 +46,10 @@ import java.awt.GridLayout; import java.nio.file.Paths; import java.util.logging.Level; import java.util.stream.Collectors; -import org.openide.modules.Places; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; /** * Dashboard for viewing metrics and controlling the health monitor. @@ -58,8 +58,8 @@ public class HealthMonitorDashboard { private final static Logger logger = Logger.getLogger(HealthMonitorDashboard.class.getName()); - private final static String ADMIN_ACCESS_FILE_NAME = "adminAccess"; // NON-NLS - private final static String ADMIN_ACCESS_FILE_PATH = Paths.get(Places.getUserDirectory().getAbsolutePath(), ADMIN_ACCESS_FILE_NAME).toString(); + private final static String ADMIN_ACCESS_FILE_NAME = "_aiaa"; // NON-NLS + private final static String ADMIN_ACCESS_FILE_PATH = Paths.get(PlatformUtil.getUserConfigDirectory(), ADMIN_ACCESS_FILE_NAME).toString(); Map> timingData; List userData; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/events/DataSourceAnalysisEvent.java b/Core/src/org/sleuthkit/autopsy/ingest/events/DataSourceAnalysisEvent.java index fb7d2f2f56..94f628a601 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/events/DataSourceAnalysisEvent.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/events/DataSourceAnalysisEvent.java @@ -39,6 +39,7 @@ public abstract class DataSourceAnalysisEvent extends AutopsyEvent implements Se private final long ingestJobId; private final long dataSourceIngestJobId; private transient Content dataSource; + private final long dataSourceObjectId; /** * Constructs an instance of the base class for events published in @@ -56,6 +57,7 @@ public abstract class DataSourceAnalysisEvent extends AutopsyEvent implements Se this.ingestJobId = ingestJobId; this.dataSourceIngestJobId = dataSourceIngestJobId; this.dataSource = dataSource; + this.dataSourceObjectId = dataSource.getId(); } /** @@ -81,7 +83,8 @@ public abstract class DataSourceAnalysisEvent extends AutopsyEvent implements Se /** * Gets the data source associated with this event. * - * @return The data source. + * @return The data source or null if there is an error getting the data + * source from an event published by a remote node. */ public Content getDataSource() { /** @@ -96,11 +99,10 @@ public abstract class DataSourceAnalysisEvent extends AutopsyEvent implements Se return dataSource; } try { - long id = (Long) super.getNewValue(); - dataSource = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(id); + dataSource = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(dataSourceObjectId); return dataSource; } catch (NoCurrentCaseException | TskCoreException ex) { - logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS + logger.log(Level.SEVERE, String.format("Error doing lazy load of data source (objId=%d) for remote event", this.dataSourceObjectId), ex); //NON-NLS return null; } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/case_uco/ReportCaseUco.java b/Core/src/org/sleuthkit/autopsy/modules/case_uco/ReportCaseUco.java index bde76ecb70..37d7ef21c2 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/case_uco/ReportCaseUco.java +++ b/Core/src/org/sleuthkit/autopsy/modules/case_uco/ReportCaseUco.java @@ -243,12 +243,15 @@ class ReportCaseUco implements GeneralReportModule { catalog.writeStringField("@type", "Trace"); catalog.writeFieldName("propertyBundle"); - catalog.writeStartArray(); - + catalog.writeStartArray(); catalog.writeStartObject(); + + // replace double slashes with single ones + caseDirPath = caseDirPath.replaceAll("\\\\", "/"); + catalog.writeStringField("@type", "File"); if (dbType == TskData.DbType.SQLITE) { - catalog.writeStringField("filePath", caseDirPath + java.io.File.separator + dbFileName); + catalog.writeStringField("filePath", caseDirPath + "/" + dbFileName); catalog.writeBooleanField("isDirectory", false); } else { catalog.writeStringField("filePath", caseDirPath); @@ -300,7 +303,7 @@ class ReportCaseUco implements GeneralReportModule { } } } - + return saveDataSourceInCaseUcoFormat(jsonGenerator, imageName, imageSize, selectedDataSourceId, caseTraceId); } @@ -317,6 +320,10 @@ class ReportCaseUco implements GeneralReportModule { catalog.writeStartObject(); catalog.writeStringField("@type", "File"); + + // replace double back slashes with single ones + imageName = imageName.replaceAll("\\\\", "/"); + catalog.writeStringField("filePath", imageName); catalog.writeEndObject(); @@ -391,7 +398,7 @@ class ReportCaseUco implements GeneralReportModule { catalog.writeStartArray(); catalog.writeStartObject(); catalog.writeStringField("@type", "Hash"); - catalog.writeStringField("hashMethod", "SHA256"); + catalog.writeStringField("hashMethod", "MD5"); catalog.writeStringField("hashValue", md5Hash); catalog.writeEndObject(); catalog.writeEndArray(); diff --git a/Core/src/org/sleuthkit/autopsy/modules/case_uco/ReportCaseUcoConfigPanel.java b/Core/src/org/sleuthkit/autopsy/modules/case_uco/ReportCaseUcoConfigPanel.java index 4ed5a8f624..d2859fd6bc 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/case_uco/ReportCaseUcoConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/case_uco/ReportCaseUcoConfigPanel.java @@ -24,7 +24,7 @@ import java.util.Map; import java.util.Map.Entry; import javax.swing.ComboBoxModel; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.guiutils.DataSourceLoader; +import org.sleuthkit.autopsy.datamodel.utils.DataSourceLoader; import org.sleuthkit.autopsy.guiutils.DataSourceComboBoxModel; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 73af437ec1..68db7a36d7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -185,10 +185,10 @@ class SevenZipExtractor { //As a result, many corrupted files have wonky compression ratios and could flood the UI //with false zip bomb notifications. The decision was made to skip compression ratio checks //for unallocated zip files. Instead, we let the depth be an indicator of a zip bomb. - if(archiveFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)) { + if (archiveFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)) { return false; } - + try { final Long archiveItemSize = (Long) inArchive.getProperty( inArchiveItemIndex, PropID.SIZE); @@ -253,14 +253,14 @@ class SevenZipExtractor { attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, EmbeddedFileExtractorModuleFactory.getModuleName(), details)); - + SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); org.sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard(); // Create artifact if it doesn't already exist. if (!tskBlackboard.artifactExists(archiveFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) { BlackboardArtifact artifact = archiveFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); artifact.addAttributes(attributes); - + try { // index the artifact for keyword search blackboard.indexArtifact(artifact); @@ -269,9 +269,9 @@ class SevenZipExtractor { MessageNotifyUtil.Notify.error( Bundle.SevenZipExtractor_indexError_message(), artifact.getDisplayName()); } - + services.postMessage(IngestMessage.createWarningMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details)); - + services.fireModuleDataEvent(new ModuleDataEvent(EmbeddedFileExtractorModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT)); } } catch (TskCoreException ex) { @@ -370,11 +370,7 @@ class SevenZipExtractor { * @return the archiveFilePath to be used by the unpack method */ private String getArchiveFilePath(AbstractFile archiveFile) { - try { - return archiveFile.getUniquePath(); - } catch (TskCoreException ex) { - return archiveFile.getParentPath() + archiveFile.getName(); - } + return archiveFile.getParentPath() + archiveFile.getName(); } /** @@ -808,37 +804,37 @@ class SevenZipExtractor { .mapToInt(Integer::intValue) .toArray(); } - + /** - * UnpackStream used by the SevenZipBindings to do archive extraction. A memory - * leak exists in the SevenZip library that will not let go of the streams until - * the entire archive extraction is complete. Instead of creating a new UnpackStream - * for every file in the archive, instead we just rebase our EncodedFileOutputStream pointer - * for every new file. + * UnpackStream used by the SevenZipBindings to do archive extraction. A + * memory leak exists in the SevenZip library that will not let go of the + * streams until the entire archive extraction is complete. Instead of + * creating a new UnpackStream for every file in the archive, instead we + * just rebase our EncodedFileOutputStream pointer for every new file. */ private final static class UnpackStream implements ISequentialOutStream { private EncodedFileOutputStream output; private String localAbsPath; private int bytesWritten; - + UnpackStream(String localAbsPath) throws IOException { this.output = new EncodedFileOutputStream(new FileOutputStream(localAbsPath), TskData.EncodingType.XOR1); this.localAbsPath = localAbsPath; this.bytesWritten = 0; - } - + } + public void setNewOutputStream(String localAbsPath) throws IOException { this.output.close(); this.output = new EncodedFileOutputStream(new FileOutputStream(localAbsPath), TskData.EncodingType.XOR1); this.localAbsPath = localAbsPath; this.bytesWritten = 0; } - + public int getSize() { return bytesWritten; } - + @Override public int write(byte[] bytes) throws SevenZipException { try { @@ -846,19 +842,19 @@ class SevenZipExtractor { this.bytesWritten += bytes.length; } catch (IOException ex) { throw new SevenZipException( - NbBundle.getMessage(SevenZipExtractor.class, - "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.exception.msg", - localAbsPath), ex); + NbBundle.getMessage(SevenZipExtractor.class, + "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.exception.msg", + localAbsPath), ex); } return bytes.length; } - + public void close() throws IOException { - try(EncodedFileOutputStream out = output) { - out.flush(); - } + try (EncodedFileOutputStream out = output) { + out.flush(); + } } - + } /** @@ -955,7 +951,7 @@ class SevenZipExtractor { final String localAbsPath = archiveDetailsMap.get( inArchiveItemIndex).getLocalAbsPath(); - + //If the Unpackstream has been allocated, then set the Outputstream //to another file rather than creating a new unpack stream. The 7Zip //binding has a memory leak, so creating new unpack streams will not be diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/CustomFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/CustomFileTypesManager.java index 22b064dca6..0746fe6cf1 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/CustomFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/CustomFileTypesManager.java @@ -215,11 +215,15 @@ final class CustomFileTypesManager { signatureList.add(new Signature(byteArray, 522L)); fileType = new FileType("image/x-pict", signatureList); //NON-NLS autopsyDefinedFileTypes.add(fileType); + + /* NOTE: see JIRA-4269. This MIME type seems to match a lot of random file types, + including ZIP archives. As a result those files get assigned this MIME type instead + of having their MIME type detected by Tika. byteArray = DatatypeConverter.parseHexBinary("1100"); //NON-NLS signatureList.clear(); signatureList.add(new Signature(byteArray, 522L)); fileType = new FileType("image/x-pict", signatureList); //NON-NLS - autopsyDefinedFileTypes.add(fileType); + autopsyDefinedFileTypes.add(fileType);*/ /* * Add type for pam. diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index 11ace044fb..e87f75a8c8 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -194,12 +194,10 @@ AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHa AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHash.msg=Error adding valid hashes to the hash set: HashLookupSettingsPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. HashLookupSettingsPanel.addHashesToDatabaseButton.text=Add Hashes to Hash Set -HashLookupSettingsPanel.indexPathLabel.text= HashLookupSettingsPanel.indexPathLabelLabel.text=Index Path: HashLookupSettingsPanel.createDatabaseButton.toolTipText= HashLookupSettingsPanel.createDatabaseButton.text=New Hash Set -HashLookupSettingsPanel.optionsLabel.text=Options -HashLookupSettingsPanel.informationLabel.text=Information +HashLookupSettingsPanel.informationLabel.text=Hash Set Details HashLookupSettingsPanel.sendIngestMessagesCheckBox.text=Send ingest inbox message for each hit HashLookupSettingsPanel.indexButton.text=Index HashLookupSettingsPanel.indexLabel.text=Index Status: @@ -246,3 +244,4 @@ HashDbCreateDatabaseDialog.databasePathLabel.text=Hash Set Path: 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= 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 feb99fc532..47a18afeda 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties @@ -187,10 +187,8 @@ AddHashValuesToDatabaseProgressDialog.addHashValuesToDatabase.errorAddingValidHa HashLookupSettingsPanel.deleteDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u524a\u9664 HashLookupSettingsPanel.ingestWarningLabel.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u4e2d\u3067\u3059\u3002\u5b8c\u4e86\u3059\u308b\u307e\u3067\u4e00\u90e8\u306e\u8a2d\u5b9a\u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002 HashLookupSettingsPanel.addHashesToDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u30cf\u30c3\u30b7\u30e5\u3092\u8ffd\u52a0 -HashLookupSettingsPanel.indexPathLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093 HashLookupSettingsPanel.indexPathLabelLabel.text=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u30d1\u30b9\uff1a HashLookupSettingsPanel.createDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u4f5c\u6210 -HashLookupSettingsPanel.optionsLabel.text=\u30aa\u30d7\u30b7\u30e7\u30f3 HashLookupSettingsPanel.informationLabel.text=\u60c5\u5831 HashLookupSettingsPanel.sendIngestMessagesCheckBox.text=\u30d2\u30c3\u30c8\u6bce\u306b\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30a4\u30f3\u30dc\u30c3\u30af\u30b9\u306b\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u9001\u308b HashLookupSettingsPanel.indexButton.text=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9 @@ -206,3 +204,4 @@ HashLookupSettingsPanel.hashDatabasesLabel.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u HashLookupSettingsPanel.importDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30dd\u30fc\u30c8 HashDbCreateDatabaseDialog.databasePathLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\uff1a AddHashValuesToDatabaseDialog.okButton.text_2=OK +HashLookupSettingsPanel.indexPathLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093 diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form index aebeb35828..0eea228e69 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form @@ -66,10 +66,7 @@ - - - - + @@ -89,80 +86,35 @@ - + - + - - - + + + - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + - + @@ -191,63 +143,14 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - @@ -268,18 +171,15 @@ - + - + - - - - + @@ -318,18 +218,21 @@ - + - + - + - + + + + @@ -339,7 +242,7 @@ - + @@ -369,114 +272,316 @@ - + - + + + + - + + + + + + + + + + - + - + - + - + - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -493,100 +598,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -603,45 +614,33 @@ - + + + + + + - + + + + - + - - + + + + - - - - - - + + - - - - - - - - - - - - - - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java index 9c2962797f..e6f399d38b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -142,8 +142,6 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan // Update ingest options. sendIngestMessagesCheckBox.setSelected(false); sendIngestMessagesCheckBox.setEnabled(false); - optionsLabel.setEnabled(false); - optionsSeparator.setEnabled(false); // Update database action buttons. createDatabaseButton.setEnabled(true); @@ -194,14 +192,14 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan deleteDatabaseButton.setEnabled(!ingestIsRunning); try { - hashDbLocationLabel.setText(shortenPath(db.getDatabasePath())); + hashDbLocationLabel.setText(db.getDatabasePath()); } catch (TskCoreException ex) { Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting hash set path of " + db.getHashSetName() + " hash set", ex); //NON-NLS hashDbLocationLabel.setText(ERROR_GETTING_PATH_TEXT); } try { - indexPathLabel.setText(shortenPath(hashDb.getIndexPath())); + indexPathLabel.setText(hashDb.getIndexPath()); } catch (TskCoreException ex) { Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index path of " + db.getHashSetName() + " hash set", ex); //NON-NLS indexPathLabel.setText(ERROR_GETTING_PATH_TEXT); @@ -270,8 +268,6 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan // Update ingest option components. sendIngestMessagesCheckBox.setSelected(db.getSendIngestMessages()); sendIngestMessagesCheckBox.setEnabled(!ingestIsRunning && db.getKnownFilesType().equals(KnownFilesType.KNOWN_BAD)); - optionsLabel.setEnabled(!ingestIsRunning); - optionsSeparator.setEnabled(!ingestIsRunning); // Update database action buttons. createDatabaseButton.setEnabled(true); @@ -281,14 +277,6 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan ingestWarningLabel.setVisible(ingestIsRunning); } - private static String shortenPath(String path) { - String shortenedPath = path; - if (shortenedPath.length() > 50) { - shortenedPath = shortenedPath.substring(0, 10 + shortenedPath.substring(10).indexOf(File.separator) + 1) + "..." + shortenedPath.substring((shortenedPath.length() - 20) + shortenedPath.substring(shortenedPath.length() - 20).indexOf(File.separator)); - } - return shortenedPath; - } - private boolean isLocalIngestJobEvent(PropertyChangeEvent evt) { if (evt instanceof AutopsyEvent) { AutopsyEvent event = (AutopsyEvent) evt; @@ -591,36 +579,35 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan jButton3 = new javax.swing.JButton(); jScrollPane2 = new javax.swing.JScrollPane(); jPanel1 = new javax.swing.JPanel(); - ingestWarningLabel = new javax.swing.JLabel(); + hashDatabasesLabel = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); hashSetTable = new HashSetTable(); - deleteDatabaseButton = new javax.swing.JButton(); + createDatabaseButton = new javax.swing.JButton(); importDatabaseButton = new javax.swing.JButton(); - hashDatabasesLabel = new javax.swing.JLabel(); + deleteDatabaseButton = new javax.swing.JButton(); + informationLabel = new javax.swing.JLabel(); + informationScrollPanel = new javax.swing.JScrollPane(); + informationPanel = new javax.swing.JPanel(); nameLabel = new javax.swing.JLabel(); hashDbNameLabel = new javax.swing.JLabel(); - hashDbLocationLabel = new javax.swing.JLabel(); - locationLabel = new javax.swing.JLabel(); typeLabel = new javax.swing.JLabel(); hashDbTypeLabel = new javax.swing.JLabel(); - hashDbIndexStatusLabel = new javax.swing.JLabel(); - indexLabel = new javax.swing.JLabel(); - indexButton = new javax.swing.JButton(); - sendIngestMessagesCheckBox = new javax.swing.JCheckBox(); - informationLabel = new javax.swing.JLabel(); - optionsLabel = new javax.swing.JLabel(); - informationSeparator = new javax.swing.JSeparator(); - optionsSeparator = new javax.swing.JSeparator(); - createDatabaseButton = new javax.swing.JButton(); - indexPathLabelLabel = new javax.swing.JLabel(); - indexPathLabel = new javax.swing.JLabel(); - addHashesToDatabaseButton = new javax.swing.JButton(); + locationLabel = new javax.swing.JLabel(); + hashDbLocationLabel = new javax.swing.JLabel(); versionLabel = new javax.swing.JLabel(); hashDbVersionLabel = new javax.swing.JLabel(); orgLabel = new javax.swing.JLabel(); hashDbOrgLabel = new javax.swing.JLabel(); readOnlyLabel = new javax.swing.JLabel(); hashDbReadOnlyLabel = new javax.swing.JLabel(); + indexPathLabelLabel = new javax.swing.JLabel(); + indexPathLabel = new javax.swing.JLabel(); + indexLabel = new javax.swing.JLabel(); + hashDbIndexStatusLabel = new javax.swing.JLabel(); + indexButton = new javax.swing.JButton(); + addHashesToDatabaseButton = new javax.swing.JButton(); + sendIngestMessagesCheckBox = new javax.swing.JCheckBox(); + ingestWarningLabel = new javax.swing.JLabel(); jLabel2.setFont(jLabel2.getFont().deriveFont(jLabel2.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.jLabel2.text")); // NOI18N @@ -634,9 +621,8 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan jButton3.setFont(jButton3.getFont().deriveFont(jButton3.getFont().getStyle() & ~java.awt.Font.BOLD, 14)); org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.jButton3.text")); // NOI18N - ingestWarningLabel.setFont(ingestWarningLabel.getFont().deriveFont(ingestWarningLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/warning16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.ingestWarningLabel.text")); // NOI18N + hashDatabasesLabel.setFont(hashDatabasesLabel.getFont().deriveFont(hashDatabasesLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(hashDatabasesLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDatabasesLabel.text")); // NOI18N hashSetTable.setFont(hashSetTable.getFont().deriveFont(hashSetTable.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); hashSetTable.setModel(new javax.swing.table.DefaultTableModel( @@ -656,14 +642,15 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan }); jScrollPane1.setViewportView(hashSetTable); - deleteDatabaseButton.setFont(deleteDatabaseButton.getFont().deriveFont(deleteDatabaseButton.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - deleteDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/delete16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(deleteDatabaseButton, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.deleteDatabaseButton.text")); // NOI18N - deleteDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25)); - deleteDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25)); - deleteDatabaseButton.addActionListener(new java.awt.event.ActionListener() { + createDatabaseButton.setFont(createDatabaseButton.getFont().deriveFont(createDatabaseButton.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + createDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/new16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(createDatabaseButton, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.createDatabaseButton.text")); // NOI18N + createDatabaseButton.setToolTipText(org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.createDatabaseButton.toolTipText")); // NOI18N + createDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25)); + createDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25)); + createDatabaseButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - deleteDatabaseButtonActionPerformed(evt); + createDatabaseButtonActionPerformed(evt); } }); @@ -679,8 +666,21 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } }); - hashDatabasesLabel.setFont(hashDatabasesLabel.getFont().deriveFont(hashDatabasesLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(hashDatabasesLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDatabasesLabel.text")); // NOI18N + deleteDatabaseButton.setFont(deleteDatabaseButton.getFont().deriveFont(deleteDatabaseButton.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + deleteDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/delete16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteDatabaseButton, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.deleteDatabaseButton.text")); // NOI18N + deleteDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25)); + deleteDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25)); + deleteDatabaseButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + deleteDatabaseButtonActionPerformed(evt); + } + }); + + informationLabel.setFont(informationLabel.getFont().deriveFont(informationLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(informationLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.informationLabel.text")); // NOI18N + + informationScrollPanel.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); nameLabel.setFont(nameLabel.getFont().deriveFont(nameLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.nameLabel.text")); // NOI18N @@ -688,73 +688,17 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan hashDbNameLabel.setFont(hashDbNameLabel.getFont().deriveFont(hashDbNameLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); org.openide.awt.Mnemonics.setLocalizedText(hashDbNameLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDbNameLabel.text")); // NOI18N - hashDbLocationLabel.setFont(hashDbLocationLabel.getFont().deriveFont(hashDbLocationLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(hashDbLocationLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDbLocationLabel.text")); // NOI18N - - locationLabel.setFont(locationLabel.getFont().deriveFont(locationLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(locationLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.locationLabel.text")); // NOI18N - typeLabel.setFont(typeLabel.getFont().deriveFont(typeLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); org.openide.awt.Mnemonics.setLocalizedText(typeLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.typeLabel.text")); // NOI18N hashDbTypeLabel.setFont(hashDbTypeLabel.getFont().deriveFont(hashDbTypeLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); org.openide.awt.Mnemonics.setLocalizedText(hashDbTypeLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDbTypeLabel.text")); // NOI18N - hashDbIndexStatusLabel.setFont(hashDbIndexStatusLabel.getFont().deriveFont(hashDbIndexStatusLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(hashDbIndexStatusLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDbIndexStatusLabel.text")); // NOI18N + locationLabel.setFont(locationLabel.getFont().deriveFont(locationLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(locationLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.locationLabel.text")); // NOI18N - indexLabel.setFont(indexLabel.getFont().deriveFont(indexLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(indexLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.indexLabel.text")); // NOI18N - - indexButton.setFont(indexButton.getFont().deriveFont(indexButton.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(indexButton, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.indexButton.text")); // NOI18N - indexButton.setEnabled(false); - indexButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - indexButtonActionPerformed(evt); - } - }); - - sendIngestMessagesCheckBox.setFont(sendIngestMessagesCheckBox.getFont().deriveFont(sendIngestMessagesCheckBox.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(sendIngestMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.sendIngestMessagesCheckBox.text")); // NOI18N - sendIngestMessagesCheckBox.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - sendIngestMessagesCheckBoxActionPerformed(evt); - } - }); - - informationLabel.setFont(informationLabel.getFont().deriveFont(informationLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(informationLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.informationLabel.text")); // NOI18N - - optionsLabel.setFont(optionsLabel.getFont().deriveFont(optionsLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.optionsLabel.text")); // NOI18N - - createDatabaseButton.setFont(createDatabaseButton.getFont().deriveFont(createDatabaseButton.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - createDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/new16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(createDatabaseButton, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.createDatabaseButton.text")); // NOI18N - createDatabaseButton.setToolTipText(org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.createDatabaseButton.toolTipText")); // NOI18N - createDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25)); - createDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25)); - createDatabaseButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - createDatabaseButtonActionPerformed(evt); - } - }); - - indexPathLabelLabel.setFont(indexPathLabelLabel.getFont().deriveFont(indexPathLabelLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(indexPathLabelLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.indexPathLabelLabel.text")); // NOI18N - - indexPathLabel.setFont(indexPathLabel.getFont().deriveFont(indexPathLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(indexPathLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.indexPathLabel.text")); // NOI18N - - addHashesToDatabaseButton.setFont(addHashesToDatabaseButton.getFont().deriveFont(addHashesToDatabaseButton.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(addHashesToDatabaseButton, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.addHashesToDatabaseButton.text")); // NOI18N - addHashesToDatabaseButton.setEnabled(false); - addHashesToDatabaseButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - addHashesToDatabaseButtonActionPerformed(evt); - } - }); + hashDbLocationLabel.setFont(hashDbLocationLabel.getFont().deriveFont(hashDbLocationLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(hashDbLocationLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDbLocationLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(versionLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.versionLabel.text_1")); // NOI18N @@ -768,6 +712,131 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan org.openide.awt.Mnemonics.setLocalizedText(hashDbReadOnlyLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDbReadOnlyLabel.text_1")); // NOI18N + indexPathLabelLabel.setFont(indexPathLabelLabel.getFont().deriveFont(indexPathLabelLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(indexPathLabelLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.indexPathLabelLabel.text")); // NOI18N + + indexPathLabel.setFont(indexPathLabel.getFont().deriveFont(indexPathLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(indexPathLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.indexPathLabel.text")); // NOI18N + + indexLabel.setFont(indexLabel.getFont().deriveFont(indexLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(indexLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.indexLabel.text")); // NOI18N + + hashDbIndexStatusLabel.setFont(hashDbIndexStatusLabel.getFont().deriveFont(hashDbIndexStatusLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(hashDbIndexStatusLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.hashDbIndexStatusLabel.text")); // NOI18N + + javax.swing.GroupLayout informationPanelLayout = new javax.swing.GroupLayout(informationPanel); + informationPanel.setLayout(informationPanelLayout); + informationPanelLayout.setHorizontalGroup( + informationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(informationPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(informationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(informationPanelLayout.createSequentialGroup() + .addComponent(locationLabel) + .addGap(18, 18, 18) + .addComponent(hashDbLocationLabel)) + .addGroup(informationPanelLayout.createSequentialGroup() + .addComponent(nameLabel) + .addGap(18, 18, 18) + .addComponent(hashDbNameLabel)) + .addGroup(informationPanelLayout.createSequentialGroup() + .addComponent(typeLabel) + .addGap(18, 18, 18) + .addComponent(hashDbTypeLabel)) + .addGroup(informationPanelLayout.createSequentialGroup() + .addComponent(versionLabel) + .addGap(18, 18, 18) + .addComponent(hashDbVersionLabel)) + .addGroup(informationPanelLayout.createSequentialGroup() + .addComponent(orgLabel) + .addGap(18, 18, 18) + .addComponent(hashDbOrgLabel)) + .addGroup(informationPanelLayout.createSequentialGroup() + .addComponent(readOnlyLabel) + .addGap(18, 18, 18) + .addComponent(hashDbReadOnlyLabel)) + .addGroup(informationPanelLayout.createSequentialGroup() + .addComponent(indexLabel) + .addGap(18, 18, 18) + .addComponent(hashDbIndexStatusLabel)) + .addGroup(informationPanelLayout.createSequentialGroup() + .addComponent(indexPathLabelLabel) + .addGap(18, 18, 18) + .addComponent(indexPathLabel))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + informationPanelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {indexLabel, indexPathLabelLabel, locationLabel, nameLabel, orgLabel, readOnlyLabel, typeLabel, versionLabel}); + + informationPanelLayout.setVerticalGroup( + informationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(informationPanelLayout.createSequentialGroup() + .addGroup(informationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(hashDbNameLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(informationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(typeLabel) + .addComponent(hashDbTypeLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(informationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(locationLabel) + .addComponent(hashDbLocationLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(informationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(versionLabel) + .addComponent(hashDbVersionLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(informationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(orgLabel) + .addComponent(hashDbOrgLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(informationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(readOnlyLabel) + .addComponent(hashDbReadOnlyLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(informationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(indexPathLabelLabel) + .addComponent(indexPathLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(informationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(indexLabel) + .addComponent(hashDbIndexStatusLabel)) + .addGap(0, 49, Short.MAX_VALUE)) + ); + + informationScrollPanel.setViewportView(informationPanel); + + indexButton.setFont(indexButton.getFont().deriveFont(indexButton.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(indexButton, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.indexButton.text")); // NOI18N + indexButton.setEnabled(false); + indexButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + indexButtonActionPerformed(evt); + } + }); + + addHashesToDatabaseButton.setFont(addHashesToDatabaseButton.getFont().deriveFont(addHashesToDatabaseButton.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(addHashesToDatabaseButton, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.addHashesToDatabaseButton.text")); // NOI18N + addHashesToDatabaseButton.setEnabled(false); + addHashesToDatabaseButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + addHashesToDatabaseButtonActionPerformed(evt); + } + }); + + sendIngestMessagesCheckBox.setFont(sendIngestMessagesCheckBox.getFont().deriveFont(sendIngestMessagesCheckBox.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(sendIngestMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.sendIngestMessagesCheckBox.text")); // NOI18N + sendIngestMessagesCheckBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + sendIngestMessagesCheckBoxActionPerformed(evt); + } + }); + + ingestWarningLabel.setFont(ingestWarningLabel.getFont().deriveFont(ingestWarningLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/warning16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.ingestWarningLabel.text")); // NOI18N + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( @@ -780,57 +849,23 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addComponent(informationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addGap(356, 356, 356)) .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(informationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(309, 309, 309)) + .addComponent(indexButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(addHashesToDatabaseButton) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(informationScrollPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 420, Short.MAX_VALUE) .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(10, 10, 10) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(indexLabel) - .addComponent(indexPathLabelLabel)) - .addGap(55, 55, 55) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(hashDbIndexStatusLabel) - .addComponent(indexPathLabel))) - .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(indexButton) - .addGap(10, 10, 10) - .addComponent(addHashesToDatabaseButton)) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(locationLabel) - .addComponent(typeLabel) - .addComponent(versionLabel) - .addComponent(orgLabel) - .addComponent(readOnlyLabel) - .addComponent(nameLabel)) - .addGap(55, 55, 55) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(hashDbNameLabel) - .addComponent(hashDbTypeLabel) - .addComponent(hashDbLocationLabel) - .addComponent(hashDbVersionLabel) - .addComponent(hashDbOrgLabel) - .addComponent(hashDbReadOnlyLabel))))) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(70, 70, 70) - .addComponent(informationSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 305, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() - .addComponent(optionsLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(optionsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 334, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(25, 25, 25) - .addComponent(sendIngestMessagesCheckBox)) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(10, 10, 10) - .addComponent(ingestWarningLabel)))) - .addContainerGap(24, Short.MAX_VALUE)))) + .addComponent(sendIngestMessagesCheckBox) + .addComponent(ingestWarningLabel)) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()))) .addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(hashDatabasesLabel) @@ -842,9 +877,6 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan .addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) .addGap(0, 0, Short.MAX_VALUE)))) ); - - jPanel1Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {indexLabel, indexPathLabelLabel, locationLabel, nameLabel, orgLabel, readOnlyLabel, typeLabel, versionLabel}); - jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() @@ -853,51 +885,13 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan .addGap(6, 6, 6) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(informationLabel) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(7, 7, 7) - .addComponent(informationSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 3, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(7, 7, 7) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(hashDbNameLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(typeLabel) - .addComponent(hashDbTypeLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(locationLabel) - .addComponent(hashDbLocationLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(versionLabel) - .addComponent(hashDbVersionLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(orgLabel) - .addComponent(hashDbOrgLabel)) - .addGap(7, 7, 7) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(readOnlyLabel) - .addComponent(hashDbReadOnlyLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(indexPathLabelLabel) - .addComponent(indexPathLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(indexLabel) - .addComponent(hashDbIndexStatusLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(informationLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(informationScrollPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 185, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(indexButton) .addComponent(addHashesToDatabaseButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(optionsLabel) - .addComponent(optionsSeparator, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(18, 18, 18) .addComponent(sendIngestMessagesCheckBox) .addGap(18, 18, 18) @@ -918,9 +912,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(jScrollPane2) - .addContainerGap()) + .addComponent(jScrollPane2) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -1059,7 +1051,8 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan private javax.swing.JLabel indexPathLabel; private javax.swing.JLabel indexPathLabelLabel; private javax.swing.JLabel informationLabel; - private javax.swing.JSeparator informationSeparator; + private javax.swing.JPanel informationPanel; + private javax.swing.JScrollPane informationScrollPanel; private javax.swing.JLabel ingestWarningLabel; private javax.swing.JButton jButton3; private javax.swing.JLabel jLabel2; @@ -1070,8 +1063,6 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan private javax.swing.JScrollPane jScrollPane2; private javax.swing.JLabel locationLabel; private javax.swing.JLabel nameLabel; - private javax.swing.JLabel optionsLabel; - private javax.swing.JSeparator optionsSeparator; private javax.swing.JLabel orgLabel; private javax.swing.JLabel readOnlyLabel; private javax.swing.JCheckBox sendIngestMessagesCheckBox; diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/Bundle.properties b/Core/src/org/sleuthkit/autopsy/othercasessearch/Bundle.properties deleted file mode 100755 index 95951884a2..0000000000 --- a/Core/src/org/sleuthkit/autopsy/othercasessearch/Bundle.properties +++ /dev/null @@ -1,10 +0,0 @@ - -OtherCasesSearchDialog.searchButton.AccessibleContext.accessibleDescription= -OtherCasesSearchDialog.searchButton.AccessibleContext.accessibleName=Search -OtherCasesSearchDialog.searchButton.text=Search -OtherCasesSearchDialog.correlationValueTextField.text= -OtherCasesSearchDialog.correlationValueLabel.text=Correlation Property Value: -OtherCasesSearchDialog.descriptionLabel.text=Search the Central Repository for correlation properties with a specified value. The search is case insensitive. -OtherCasesSearchDialog.errorLabel.text=\ -OtherCasesSearchDialog.correlationTypeLabel.text=Correlation Property Type: -OtherCasesSearchDialog.casesLabel.text=\ diff --git a/Core/src/org/sleuthkit/autopsy/textextractors/ArtifactTextExtractor.java b/Core/src/org/sleuthkit/autopsy/textextractors/ArtifactTextExtractor.java index ba91a6cc3a..ff806845f1 100644 --- a/Core/src/org/sleuthkit/autopsy/textextractors/ArtifactTextExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/textextractors/ArtifactTextExtractor.java @@ -32,16 +32,16 @@ import org.sleuthkit.datamodel.TskCoreException; * Extracts text from artifacts by concatenating the values of all of the * artifact's attributes. */ -class ArtifactTextExtractor extends TextExtractor { +class ArtifactTextExtractor implements TextExtractor { private final BlackboardArtifact artifact; - public ArtifactTextExtractor(Content artifact) { - this.artifact = (BlackboardArtifact) artifact; + public ArtifactTextExtractor(BlackboardArtifact artifact) { + this.artifact = artifact; } @Override - public Reader getReader() throws ExtractionException { + public Reader getReader() throws InitReaderException { // Concatenate the string values of all attributes into a single // "content" string to be indexed. StringBuilder artifactContents = new StringBuilder(); @@ -50,10 +50,10 @@ class ArtifactTextExtractor extends TextExtractor { try { dataSource = artifact.getDataSource(); } catch (TskCoreException tskCoreException) { - throw new ExtractionException("Unable to get datasource for artifact: " + artifact.toString(), tskCoreException); + throw new InitReaderException("Unable to get datasource for artifact: " + artifact.toString(), tskCoreException); } if (dataSource == null) { - throw new ExtractionException("Datasource was null for artifact: " + artifact.toString()); + throw new InitReaderException("Datasource was null for artifact: " + artifact.toString()); } try { @@ -75,7 +75,7 @@ class ArtifactTextExtractor extends TextExtractor { artifactContents.append(System.lineSeparator()); } } catch (TskCoreException tskCoreException) { - throw new ExtractionException("Unable to get attributes for artifact: " + artifact.toString(), tskCoreException); + throw new InitReaderException("Unable to get attributes for artifact: " + artifact.toString(), tskCoreException); } return new InputStreamReader(IOUtils.toInputStream(artifactContents, @@ -83,7 +83,7 @@ class ArtifactTextExtractor extends TextExtractor { } @Override - public boolean isSupported(Content file, String detectedFormat) { + public boolean isSupported() { return true; } } diff --git a/Core/src/org/sleuthkit/autopsy/textextractors/Bundle.properties b/Core/src/org/sleuthkit/autopsy/textextractors/Bundle.properties new file mode 100755 index 0000000000..b2b9a6846d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/textextractors/Bundle.properties @@ -0,0 +1,2 @@ +AbstractFileTikaTextExtract.index.tikaParseTimeout.text=Exception\: Tika parse timeout for content\: {0}, {1} +AbstractFileTikaTextExtract.index.exception.tikaParse.msg=Exception\: Unexpected exception from Tika parse task execution for file\: {0}, {1} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/textextractors/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/textextractors/Bundle_ja.properties new file mode 100755 index 0000000000..5d243eba03 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/textextractors/Bundle_ja.properties @@ -0,0 +1,2 @@ +AbstractFileTikaTextExtract.index.exception.tikaParse.msg=\u4f8b\u5916\uff1a\u30d5\u30a1\u30a4\u30eb\uff1a{0}, {1}\u306eApache Tika\u30d1\u30fc\u30b9\u30bf\u30b9\u30af\u5b9f\u884c\u4e2d\u306e\u4e88\u671f\u305b\u306c\u4f8b\u5916 +AbstractFileTikaTextExtract.index.tikaParseTimeout.text=\u4f8b\u5916\uff1a\u30b3\u30f3\u30c6\u30f3\u30c4\uff1a{0}, {1}\u306eApache Tika\u30d1\u30fc\u30b9\u306e\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8 \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/textextractors/HtmlTextExtractor.java b/Core/src/org/sleuthkit/autopsy/textextractors/HtmlTextExtractor.java index 86dbd15c1b..defcdc23a5 100644 --- a/Core/src/org/sleuthkit/autopsy/textextractors/HtmlTextExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/textextractors/HtmlTextExtractor.java @@ -32,17 +32,17 @@ import net.htmlparser.jericho.Source; import net.htmlparser.jericho.StartTag; import net.htmlparser.jericho.StartTagType; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.ReadContentInputStream; /** * Extracts text from HTML content. */ -final class HtmlTextExtractor extends TextExtractor { +final class HtmlTextExtractor implements TextExtractor { static final private Logger logger = Logger.getLogger(HtmlTextExtractor.class.getName()); private final int MAX_SIZE; - private final Content file; + private final AbstractFile file; static final List WEB_MIME_TYPES = Arrays.asList( "application/javascript", //NON-NLS @@ -62,7 +62,7 @@ final class HtmlTextExtractor extends TextExtractor { * Creates a default instance of the HtmlTextExtractor. Supported file size * is 50MB. */ - public HtmlTextExtractor(Content file) { + public HtmlTextExtractor(AbstractFile file) { //Set default to be 50 MB. MAX_SIZE = 50_000_000; this.file = file; @@ -77,10 +77,10 @@ final class HtmlTextExtractor extends TextExtractor { * @return flag indicating support */ @Override - public boolean isSupported(Content content, String detectedFormat) { - return detectedFormat != null - && WEB_MIME_TYPES.contains(detectedFormat) - && content.getSize() <= MAX_SIZE; + public boolean isSupported() { + return file.getMIMEType() != null + && WEB_MIME_TYPES.contains(file.getMIMEType()) + && file.getSize() <= MAX_SIZE; } /** @@ -93,7 +93,7 @@ final class HtmlTextExtractor extends TextExtractor { * @throws TextExtractorException */ @Override - public Reader getReader() throws ExtractionException { + public Reader getReader() throws InitReaderException { //TODO JIRA-4467, there is only harm in excluding HTML documents greater //than 50MB due to our troubled approach of extraction. ReadContentInputStream stream = new ReadContentInputStream(file); @@ -190,7 +190,7 @@ final class HtmlTextExtractor extends TextExtractor { return new StringReader(stringBuilder.toString()); } catch (IOException ex) { logger.log(Level.WARNING, "Error extracting HTML from content.", ex); - throw new ExtractionException("Error extracting HTML from content.", ex); + throw new InitReaderException("Error extracting HTML from content.", ex); } } } diff --git a/Core/src/org/sleuthkit/autopsy/textextractors/SqliteTextExtractor.java b/Core/src/org/sleuthkit/autopsy/textextractors/SqliteTextExtractor.java index ea204d5e30..889062189c 100755 --- a/Core/src/org/sleuthkit/autopsy/textextractors/SqliteTextExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/textextractors/SqliteTextExtractor.java @@ -28,7 +28,6 @@ import org.sleuthkit.autopsy.coreutils.SQLiteTableReaderException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.SQLiteTableReader; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.Content; /** * Extracts text from SQLite database files. @@ -39,14 +38,14 @@ import org.sleuthkit.datamodel.Content; * 2) Tables that contain spaces in their name are not extracted * 3) Table names are not included in its output text */ -final class SqliteTextExtractor extends TextExtractor { +final class SqliteTextExtractor implements TextExtractor { private static final String SQLITE_MIMETYPE = "application/x-sqlite3"; private static final Logger logger = Logger.getLogger(SqliteTextExtractor.class.getName()); private final AbstractFile file; - public SqliteTextExtractor(Content file) { - this.file = (AbstractFile) file; + public SqliteTextExtractor(AbstractFile file) { + this.file = file; } /** * Supports only the sqlite mimetypes @@ -57,8 +56,8 @@ final class SqliteTextExtractor extends TextExtractor { * @return true if x-sqlite3 */ @Override - public boolean isSupported(Content file, String detectedFormat) { - return SQLITE_MIMETYPE.equals(detectedFormat); + public boolean isSupported() { + return SQLITE_MIMETYPE.equals(file.getMIMEType()); } /** @@ -71,7 +70,7 @@ final class SqliteTextExtractor extends TextExtractor { * @throws TextExtractorException */ @Override - public Reader getReader() throws ExtractionException { + public Reader getReader() throws InitReaderException { return new SQLiteStreamReader(file); } @@ -105,8 +104,8 @@ final class SqliteTextExtractor extends TextExtractor { public SQLiteStreamReader(AbstractFile file) { this.file = file; reader = new SQLiteTableReader.Builder(file) - .onColumnNames(getColumnNameStrategy()) - .forAll(getForAllTableValuesStrategy()).build(); + .forAllColumnNames(getColumnNameStrategy()) + .forAllTableValues(getForAllTableValuesStrategy()).build(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/textextractors/StringsTextExtractor.java b/Core/src/org/sleuthkit/autopsy/textextractors/StringsTextExtractor.java index 899cec9ef2..db0df6fa00 100644 --- a/Core/src/org/sleuthkit/autopsy/textextractors/StringsTextExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/textextractors/StringsTextExtractor.java @@ -28,7 +28,7 @@ import java.util.Objects; import org.openide.util.Lookup; import org.sleuthkit.autopsy.coreutils.StringExtract; import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT; -import org.sleuthkit.autopsy.textextractors.extractionconfigs.DefaultExtractionConfig; +import org.sleuthkit.autopsy.textextractors.configs.StringsConfig; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskException; @@ -36,7 +36,7 @@ import org.sleuthkit.datamodel.TskException; /** * Extracts raw strings from content. */ -final class StringsTextExtractor extends TextExtractor { +final class StringsTextExtractor implements TextExtractor { private boolean extractUTF8; private boolean extractUTF16; @@ -78,8 +78,6 @@ final class StringsTextExtractor extends TextExtractor { * * @return A reader instance that content text can be obtained from * - * @throws - * org.sleuthkit.autopsy.textextractors.TextExtractor.TextExtractorException */ @Override public InputStreamReader getReader() { @@ -100,15 +98,15 @@ final class StringsTextExtractor extends TextExtractor { * Determines how the extraction process will proceed given the settings * stored in this context instance. * - * See the DefaultExtractionConfig class in the extractionconfigs package - * for available settings. + * See the StringsConfig class in the extractionconfigs package for + * available settings. * * @param context Lookup instance containing config classes */ @Override public void setExtractionSettings(Lookup context) { if (context != null) { - DefaultExtractionConfig configInstance = context.lookup(DefaultExtractionConfig.class); + StringsConfig configInstance = context.lookup(StringsConfig.class); if (configInstance == null) { return; } @@ -118,8 +116,8 @@ final class StringsTextExtractor extends TextExtractor { if (Objects.nonNull(configInstance.getExtractUTF16())) { extractUTF16 = configInstance.getExtractUTF16(); } - if (Objects.nonNull(configInstance.getExtractScripts())) { - setScripts(configInstance.getExtractScripts()); + if (Objects.nonNull(configInstance.getLanguageScripts())) { + setScripts(configInstance.getLanguageScripts()); } } } @@ -129,15 +127,10 @@ final class StringsTextExtractor extends TextExtractor { * @return */ @Override - public boolean isEnabled() { + public boolean isSupported() { return extractUTF8 || extractUTF16; } - @Override - boolean isSupported(Content file, String detectedFormat) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - /** * Content input string stream reader/converter - given Content, extract * strings from it and return encoded bytes via read() diff --git a/Core/src/org/sleuthkit/autopsy/textextractors/TextExtractor.java b/Core/src/org/sleuthkit/autopsy/textextractors/TextExtractor.java index d75d4bb1a6..bada144fe5 100644 --- a/Core/src/org/sleuthkit/autopsy/textextractors/TextExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/textextractors/TextExtractor.java @@ -20,55 +20,37 @@ package org.sleuthkit.autopsy.textextractors; import java.io.Reader; import org.openide.util.Lookup; -import org.sleuthkit.datamodel.Content; /** - * Extracts the text out of {@link org.sleuthkit.datamodel.Content} instances - * and exposes them as a {@link java.io.Reader}. Concrete implementations can be - * obtained from - * {@link org.sleuthkit.autopsy.textextractors.TextExtractorFactory#getExtractor(org.sleuthkit.datamodel.Content)} - * or - * {@link org.sleuthkit.autopsy.textextractors.TextExtractorFactory#getExtractor(org.sleuthkit.datamodel.Content, org.openide.util.Lookup)}. - * - * @see org.sleuthkit.autopsy.textextractors.TextExtractorFactory + * Extracts the text out of Content instances and exposes them as a Reader. + * Concrete implementations can be obtained from + * {@link org.sleuthkit.autopsy.textextractors.TextExtractorFactory} */ -public abstract class TextExtractor { +public interface TextExtractor { /** - * Determines if the file content is supported by the extractor. - * - * @param file to test if its content should be supported - * @param detectedFormat mime-type with detected format (such as text/plain) - * or null if not detected - * - * @return true if the file content is supported, false otherwise - */ - abstract boolean isSupported(Content file, String detectedFormat); - - /** - * Determines if the TextExtractor instance is enabled to read content. - * - * @return - */ - boolean isEnabled() { - return true; - } - - /** - * Get a {@link java.io.Reader} that will iterate over the text extracted - * from the {@link org.sleuthkit.datamodel.Content} passed into + * Determines if this extractor supports the given Content and + * configurations passed into it in * {@link org.sleuthkit.autopsy.textextractors.TextExtractorFactory}. * - * @return {@link java.io.Reader} that contains the text of the underlying - * {@link org.sleuthkit.datamodel.Content} + * @return true if content is supported, false otherwise + */ + boolean isSupported(); + + /** + * Get a Reader that will iterate over the text extracted from the Content + * passed into + * {@link org.sleuthkit.autopsy.textextractors.TextExtractorFactory}. + * + * @return Reader that contains the text of the underlying Content * * @throws - * org.sleuthkit.autopsy.textextractors.TextExtractor.ExtractionException + * org.sleuthkit.autopsy.textextractors.TextExtractor.InitReaderException * * @see org.sleuthkit.autopsy.textextractors.TextExtractorFactory * */ - public abstract Reader getReader() throws ExtractionException; + Reader getReader() throws InitReaderException; /** * Determines how the extraction process will proceed given the settings @@ -76,27 +58,24 @@ public abstract class TextExtractor { * * @param context Instance containing file config classes */ - void setExtractionSettings(Lookup context) { + default void setExtractionSettings(Lookup context) { //no-op by default } /** - * Exception encountered during - * {@link org.sleuthkit.autopsy.textextractors.TextExtractor#getReader()}. - * This indicates that there was an internal parsing error that occurred - * during the reading of Content text. + * System level exception for reader initialization. */ - public class ExtractionException extends Exception { + public class InitReaderException extends Exception { - public ExtractionException(String msg, Throwable ex) { + public InitReaderException(String msg, Throwable ex) { super(msg, ex); } - public ExtractionException(Throwable ex) { + public InitReaderException(Throwable ex) { super(ex); } - public ExtractionException(String msg) { + public InitReaderException(String msg) { super(msg); } } diff --git a/Core/src/org/sleuthkit/autopsy/textextractors/TextExtractorFactory.java b/Core/src/org/sleuthkit/autopsy/textextractors/TextExtractorFactory.java index 10f2e84ba0..22d4aa5040 100755 --- a/Core/src/org/sleuthkit/autopsy/textextractors/TextExtractorFactory.java +++ b/Core/src/org/sleuthkit/autopsy/textextractors/TextExtractorFactory.java @@ -27,52 +27,37 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Report; /** - * Factory for creating - * {@link org.sleuthkit.autopsy.textextractors.TextExtractor}'s given a - * {@link org.sleuthkit.datamodel.Content} instance + * Factory for creating TextExtractors given a Content instance * - * See {@link org.sleuthkit.autopsy.textextractors.extractionconfigs} for - * available {@link org.sleuthkit.autopsy.textextractors.TextExtractor} - * configuration options. + * See {@link org.sleuthkit.autopsy.textextractors.textextractorconfigs} for + * available extractor configuration options. * * @see org.openide.util.Lookup */ public class TextExtractorFactory { /** - * Auto detects the correct - * {@link org.sleuthkit.autopsy.textextractors.TextExtractor} given the - * {@link org.sleuthkit.datamodel.Content}. + * Returns a TextExtractor containing the Content text. Configuration files + * can be added to the Lookup. * - * See {@link org.sleuthkit.autopsy.textextractors.extractionconfigs} for - * available {@link org.sleuthkit.autopsy.textextractors.TextExtractor} - * configuration options. + * See {@link org.sleuthkit.autopsy.textextractors.textextractorconfigs} for + * available extractor configuration options. * * @param content Content source that will be read from * @param context Contains extraction configurations for certain file types * - * @return A TextExtractor that supports the given content. File text can be - * obtained from - * {@link org.sleuthkit.autopsy.textextractors.TextExtractor#getReader()}. + * @return TextExtractor containing file text * - * @throws NoTextExtractorFound Encountered when there is no TextExtractor - * was found for the given content type. Use {@link - * TextExtractorFactory#getDefaultExtractor(org.sleuthkit.datamodel.Content, - * org.openide.util.Lookup)} + * @throws NoTextExtractorFound Encountered when there is no Reader found + * for the given content type or there was an + * error while creating the reader. * * @see org.openide.util.Lookup */ - public static TextExtractor getExtractor(Content content, - Lookup context) throws NoTextExtractorFound { + public static TextExtractor getExtractor(Content content, Lookup context) throws NoTextExtractorFound { if (content instanceof AbstractFile) { - String mimeType = ((AbstractFile) content).getMIMEType(); - List extractors = Arrays.asList( - new HtmlTextExtractor(content), - new SqliteTextExtractor(content), - new TikaTextExtractor(content)); - for (TextExtractor extractor : extractors) { - extractor.setExtractionSettings(context); - if (extractor.isEnabled() && extractor.isSupported(content, mimeType)) { + for (TextExtractor extractor : getFileExtractors((AbstractFile) content, context)) { + if (extractor.isSupported()) { return extractor; } } @@ -87,49 +72,69 @@ public class TextExtractorFactory { } throw new NoTextExtractorFound( - String.format("Could not find a suitable extractor for " - + "content with name [%s] and id=[%d]. Try using the default, " - + "non content specific extractor as an alternative.", + String.format("Could not find a suitable reader for " + + "content with name [%s] and id=[%d]. Try using " + + "the strings extractor instead.", content.getName(), content.getId()) ); } /** - * Auto detects the correct - * {@link org.sleuthkit.autopsy.textextractors.TextExtractor} given the - * {@link org.sleuthkit.datamodel.Content}. + * Initializes, orders, and returns all file extractors that can read + * AbstractFile instances. * - * @param content Content instance that will be read from + * @param content AbstractFile content + * @param context Lookup containing extractor configurations * - * @return A TextExtractor that supports the given content. File text can be - * obtained from {@link TextExtractor#getReader()}. - * - * @throws NoTextExtractorFound Encountered when there is no TextExtractor - * was found for the given content type. Use {@link - * TextExtractorFactory#getDefaultExtractor(org.sleuthkit.datamodel.Content, - * org.openide.util.Lookup)} + * @return */ - public static TextExtractor getExtractor(Content content) - throws NoTextExtractorFound { - return getExtractor(content, null); + private static List getFileExtractors(AbstractFile content, Lookup context) { + List fileExtractors = Arrays.asList( + new HtmlTextExtractor(content), + new SqliteTextExtractor(content), + new TikaTextExtractor(content)); + + fileExtractors.forEach((fileExtractor) -> { + fileExtractor.setExtractionSettings(context); + }); + + return fileExtractors; } /** - * Returns the default extractor that can be run on any content type. This - * extractor should be used as a backup in the event that no extractor was - * found using or {@link TextExtractorFactory#getDefaultExtractor(org.sleuthkit.datamodel.Content, org.openide.util.Lookup)} - * {@link TextExtractorFactory#getExtractor(org.sleuthkit.datamodel.Content)}. + * Returns a TextExtractor containing the Content text. + * + * @param content Content instance that will be read from + * + * @return TextExtractor containing file text + * + * @throws NoTextExtractorFound Encountered when there is no Reader was + * found for the given content type. Use + * getStringsExtractor(Content,Lookup) method + * instead. + */ + public static TextExtractor getExtractor(Content content) throws NoTextExtractorFound { + return TextExtractorFactory.getExtractor(content, null); + } + + /** + * Returns a TextExtractor containing the Content strings. This method + * supports all content types. This method should be used as a backup in the + * event that no reader was found using getExtractor(Content) or + * getExtractor(Content, Lookup). + * + * Configure this extractor with the StringsConfig in + * {@link org.sleuthkit.autopsy.textextractors.textextractorconfigs} * * @param content Content source to read from * @param context Contains extraction configurations for certain file types * - * @return A DefaultExtractor instance. File text can be obtained from - * {@link TextExtractor#getReader()}. + * @return TextExtractor containing file text * * @see org.openide.util.Lookup */ - public static TextExtractor getDefaultExtractor(Content content, Lookup context) { - TextExtractor stringsInstance = new StringsTextExtractor(content); + public static TextExtractor getStringsExtractor(Content content, Lookup context) { + StringsTextExtractor stringsInstance = new StringsTextExtractor(content); stringsInstance.setExtractionSettings(context); return stringsInstance; } @@ -137,12 +142,6 @@ public class TextExtractorFactory { /** * System level exception for handling content types that have no specific * strategy defined for extracting their text. - * - * @see - * org.sleuthkit.autopsy.textextractors.TextExtractorFactory#getExtractor(org.sleuthkit.datamodel.Content) - * @see - * org.sleuthkit.autopsy.textextractors.TextExtractorFactory#getDefaultExtractor(org.sleuthkit.datamodel.Content, - * org.openide.util.Lookup)} */ public static class NoTextExtractorFound extends Exception { @@ -153,5 +152,9 @@ public class TextExtractorFactory { public NoTextExtractorFound(Throwable ex) { super(ex); } + + private NoTextExtractorFound(String msg, Throwable ex) { + super(msg, ex); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/textextractors/TikaTextExtractor.java b/Core/src/org/sleuthkit/autopsy/textextractors/TikaTextExtractor.java index 9b766a9e9e..8ceb99d0d2 100644 --- a/Core/src/org/sleuthkit/autopsy/textextractors/TikaTextExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/textextractors/TikaTextExtractor.java @@ -20,18 +20,23 @@ package org.sleuthkit.autopsy.textextractors; import com.google.common.collect.ImmutableList; import com.google.common.io.CharSource; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.io.PushbackReader; import java.io.Reader; import java.nio.file.Paths; -import java.util.Arrays; -import java.util.HashSet; +import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.logging.Level; @@ -50,8 +55,15 @@ import org.apache.tika.parser.pdf.PDFParserConfig; import org.openide.util.NbBundle; import org.openide.modules.InstalledFileLocator; import org.openide.util.Lookup; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.coreutils.ExecUtil; +import org.sleuthkit.autopsy.coreutils.ExecUtil.ProcessTerminator; +import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.textextractors.extractionconfigs.ImageFileExtractionConfig; +import org.sleuthkit.autopsy.textextractors.configs.ImageConfig; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ReadContentInputStream; @@ -59,7 +71,7 @@ import org.sleuthkit.datamodel.ReadContentInputStream; * Extracts text from Tika supported content. Protects against Tika parser hangs * (for unexpected/corrupt content) using a timeout mechanism. */ -final class TikaTextExtractor extends TextExtractor { +final class TikaTextExtractor implements TextExtractor { //Mimetype groups to aassist extractor implementations in ignoring binary and //archive files. @@ -110,7 +122,9 @@ final class TikaTextExtractor extends TextExtractor { private static final java.util.logging.Logger tikaLogger = java.util.logging.Logger.getLogger("Tika"); //NON-NLS - private final ExecutorService tikaParseExecutor = Executors.newSingleThreadExecutor(); + private final ThreadFactory tikaThreadFactory + = new ThreadFactoryBuilder().setNameFormat("tika-reader-%d").build(); + private final ExecutorService executorService = Executors.newSingleThreadExecutor(tikaThreadFactory); private static final String SQLITE_MIMETYPE = "application/x-sqlite3"; private final AutoDetectParser parser = new AutoDetectParser(); @@ -121,6 +135,10 @@ final class TikaTextExtractor extends TextExtractor { private static final String TESSERACT_EXECUTABLE = "tesseract.exe"; //NON-NLS private static final File TESSERACT_PATH = locateTesseractExecutable(); private static final String LANGUAGE_PACKS = getLanguagePacks(); + private static final String TESSERACT_LANGUAGE_PACK_EXT = "traineddata"; //NON-NLS + private static final String TESSERACT_OUTPUT_FILE_NAME = "tess_output"; //NON-NLS + + private ProcessTerminator processTerminator; private static final List TIKA_SUPPORTED_TYPES = new Tika().getParser().getSupportedTypes(new ParseContext()) @@ -132,6 +150,18 @@ final class TikaTextExtractor extends TextExtractor { this.content = content; } + /** + * If Tesseract has been installed and is set to be used through + * configuration, then ocr is enabled. OCR can only currently be run on + * 64 bit Windows OS. + * + * @return Flag indicating if OCR is set to be used. + */ + private boolean ocrEnabled() { + return TESSERACT_PATH != null && tesseractOCREnabled + && PlatformUtil.isWindowsOS() == true && PlatformUtil.is64BitOS(); + } + /** * Returns a reader that will iterate over the text extracted from Apache * Tika. @@ -144,13 +174,46 @@ final class TikaTextExtractor extends TextExtractor { * org.sleuthkit.autopsy.textextractors.TextExtractor.TextExtractorException */ @Override - public Reader getReader() throws ExtractionException { - ReadContentInputStream stream = new ReadContentInputStream(content); + public Reader getReader() throws InitReaderException { + InputStream stream = null; - Metadata metadata = new Metadata(); ParseContext parseContext = new ParseContext(); parseContext.set(Parser.class, parser); + if (ocrEnabled() && content instanceof AbstractFile) { + AbstractFile file = ((AbstractFile) content); + //Run OCR on images with Tesseract directly. + if (file.getMIMEType().toLowerCase().startsWith("image/")) { + stream = performOCR(file); + } else { + //Otherwise, go through Tika for PDFs so that it can + //extract images and run Tesseract on them. + PDFParserConfig pdfConfig = new PDFParserConfig(); + + // Extracting the inline images and letting Tesseract run on each inline image. + // https://wiki.apache.org/tika/PDFParser%20%28Apache%20PDFBox%29 + // https://tika.apache.org/1.7/api/org/apache/tika/parser/pdf/PDFParserConfig.html + pdfConfig.setExtractInlineImages(true); + // Multiple pages within a PDF file might refer to the same underlying image. + pdfConfig.setExtractUniqueInlineImagesOnly(true); + parseContext.set(PDFParserConfig.class, pdfConfig); + + // Configure Tesseract parser to perform OCR + TesseractOCRConfig ocrConfig = new TesseractOCRConfig(); + String tesseractFolder = TESSERACT_PATH.getParent(); + ocrConfig.setTesseractPath(tesseractFolder); + + ocrConfig.setLanguage(LANGUAGE_PACKS); + ocrConfig.setTessdataPath(PlatformUtil.getOcrLanguagePacksPath()); + parseContext.set(TesseractOCRConfig.class, ocrConfig); + + stream = new ReadContentInputStream(content); + } + } else { + stream = new ReadContentInputStream(content); + } + + Metadata metadata = new Metadata(); // Use the more memory efficient Tika SAX parsers for DOCX and // PPTX files (it already uses SAX for XLSX). OfficeParserConfig officeParserConfig = new OfficeParserConfig(); @@ -158,60 +221,163 @@ final class TikaTextExtractor extends TextExtractor { officeParserConfig.setUseSAXDocxExtractor(true); parseContext.set(OfficeParserConfig.class, officeParserConfig); - // configure OCR if it is enabled in KWS settings and installed on the machine - if (TESSERACT_PATH != null && tesseractOCREnabled && PlatformUtil.isWindowsOS() == true) { - - // configure PDFParser. - PDFParserConfig pdfConfig = new PDFParserConfig(); - - // Extracting the inline images and letting Tesseract run on each inline image. - // https://wiki.apache.org/tika/PDFParser%20%28Apache%20PDFBox%29 - // https://tika.apache.org/1.7/api/org/apache/tika/parser/pdf/PDFParserConfig.html - pdfConfig.setExtractInlineImages(true); - // Multiple pages within a PDF file might refer to the same underlying image. - pdfConfig.setExtractUniqueInlineImagesOnly(true); - parseContext.set(PDFParserConfig.class, pdfConfig); - - // Configure Tesseract parser to perform OCR - TesseractOCRConfig ocrConfig = new TesseractOCRConfig(); - String tesseractFolder = TESSERACT_PATH.getParent(); - ocrConfig.setTesseractPath(tesseractFolder); - // Tesseract expects language data packs to be in a subdirectory of tesseractFolder, in a folder called "tessdata". - // If they are stored somewhere else, use ocrConfig.setTessdataPath(String tessdataPath) to point to them - ocrConfig.setLanguage(LANGUAGE_PACKS); - parseContext.set(TesseractOCRConfig.class, ocrConfig); - } - - //Parse the file in a task, a convenient way to have a timeout... - final Future future = tikaParseExecutor.submit(() -> new ParsingReader(parser, stream, metadata, parseContext)); + //Make the creation of a TikaReader a cancellable future in case it takes too long + Future future = executorService.submit( + new GetTikaReader(parser, stream, metadata, parseContext)); try { final Reader tikaReader = future.get(getTimeout(content.getSize()), TimeUnit.SECONDS); - //check if the reader is empty PushbackReader pushbackReader = new PushbackReader(tikaReader); int read = pushbackReader.read(); if (read == -1) { - throw new ExtractionException("Unable to extract text: Tika returned empty reader for " + content); + throw new InitReaderException("Unable to extract text: " + + "Tika returned empty reader for " + content); } pushbackReader.unread(read); - //concatenate parsed content and meta data into a single reader. CharSource metaDataCharSource = getMetaDataCharSource(metadata); return CharSource.concat(new ReaderCharSource(pushbackReader), metaDataCharSource).openStream(); } catch (TimeoutException te) { - final String msg = NbBundle.getMessage(this.getClass(), "AbstractFileTikaTextExtract.index.tikaParseTimeout.text", content.getId(), content.getName()); - throw new ExtractionException(msg, te); - } catch (ExtractionException ex) { + final String msg = NbBundle.getMessage(this.getClass(), + "AbstractFileTikaTextExtract.index.tikaParseTimeout.text", + content.getId(), content.getName()); + throw new InitReaderException(msg, te); + } catch (InitReaderException ex) { throw ex; } catch (Exception ex) { - tikaLogger.log(Level.WARNING, "Exception: Unable to Tika parse the content" + content.getId() + ": " + content.getName(), ex.getCause()); //NON-NLS - final String msg = NbBundle.getMessage(this.getClass(), "AbstractFileTikaTextExtract.index.exception.tikaParse.msg", content.getId(), content.getName()); - throw new ExtractionException(msg, ex); + tikaLogger.log(Level.WARNING, "Exception: Unable to Tika parse the " + + "content" + content.getId() + ": " + content.getName(), + ex.getCause()); //NON-NLS + final String msg = NbBundle.getMessage(this.getClass(), + "AbstractFileTikaTextExtract.index.exception.tikaParse.msg", + content.getId(), content.getName()); + throw new InitReaderException(msg, ex); } finally { future.cancel(true); } } + /** + * Run OCR and return the file stream produced by Tesseract. + * + * @param file Image file to run OCR on + * + * @return InputStream connected to the output file that Tesseract produced. + * + * @throws + * org.sleuthkit.autopsy.textextractors.TextExtractor.InitReaderException + */ + private InputStream performOCR(AbstractFile file) throws InitReaderException { + File inputFile = null; + File outputFile = null; + try { + String tempDirectory = Case.getCurrentCaseThrows().getTempDirectory(); + + //Appending file id makes the name unique + String tempFileName = FileUtil.escapeFileName(file.getId() + file.getName()); + inputFile = Paths.get(tempDirectory, tempFileName).toFile(); + ContentUtils.writeToFile(content, inputFile); + + String tempOutputName = FileUtil.escapeFileName(file.getId() + TESSERACT_OUTPUT_FILE_NAME); + String outputFilePath = Paths.get(tempDirectory, tempOutputName).toString(); + String executeablePath = TESSERACT_PATH.toString(); + + //Build tesseract commands + ProcessBuilder process = new ProcessBuilder(); + process.command(executeablePath, + String.format("\"%s\"", inputFile.getAbsolutePath()), + String.format("\"%s\"", outputFilePath), + "--tessdata-dir", PlatformUtil.getOcrLanguagePacksPath(), + //language pack command flag + "-l", LANGUAGE_PACKS); + + //If the ProcessTerminator was supplied during + //configuration apply it here. + if (processTerminator != null) { + ExecUtil.execute(process, 1, TimeUnit.SECONDS, processTerminator); + } else { + ExecUtil.execute(process); + } + + outputFile = new File(outputFilePath + ".txt"); + //Open a stream of the Tesseract text file and send this to Tika + return new CleanUpStream(outputFile); + } catch (NoCurrentCaseException | IOException ex) { + if (outputFile != null) { + outputFile.delete(); + } + throw new InitReaderException("Could not successfully run Tesseract", ex); + } finally { + if (inputFile != null) { + inputFile.delete(); + } + } + } + + /** + * Wraps the creation of a TikaReader into a Future so that it can be + * cancelled. + */ + private class GetTikaReader implements Callable { + + private final AutoDetectParser parser; + private final InputStream stream; + private final Metadata metadata; + private final ParseContext parseContext; + + public GetTikaReader(AutoDetectParser parser, InputStream stream, + Metadata metadata, ParseContext parseContext) { + this.parser = parser; + this.stream = stream; + this.metadata = metadata; + this.parseContext = parseContext; + } + + @Override + public Reader call() throws Exception { + return new ParsingReader(parser, stream, metadata, parseContext); + } + } + + /** + * Automatically deletes the underlying File when the close() method is + * called. This is used to delete the Output file produced from Tesseract + * once it has been read by Tika. + */ + private class CleanUpStream extends FileInputStream { + + private File file; + + /** + * Store a reference to file on construction + * + * @param file + * + * @throws FileNotFoundException + */ + public CleanUpStream(File file) throws FileNotFoundException { + super(file); + this.file = file; + } + + /** + * Delete this underlying file when close is called. + * + * @throws IOException + */ + @Override + public void close() throws IOException { + try { + super.close(); + } finally { + if (file != null) { + file.delete(); + file = null; + } + } + } + } + /** * Finds and returns the path to the Tesseract executable, if able. * @@ -253,24 +419,27 @@ final class TikaTextExtractor extends TextExtractor { } /** - * Determines if Tika is supported for this content type and mimetype. - * - * @param content Source content to read - * @param detectedFormat Mimetype of content + * Determines if Tika is enabled for this content * * @return Flag indicating support for reading content type */ @Override - public boolean isSupported(Content content, String detectedFormat) { - if (detectedFormat == null - || BINARY_MIME_TYPES.contains(detectedFormat) //any binary unstructured blobs (string extraction will be used) - || ARCHIVE_MIME_TYPES.contains(detectedFormat) - || (detectedFormat.startsWith("video/") && !detectedFormat.equals("video/x-flv")) //skip video other than flv (tika supports flv only) //NON-NLS - || detectedFormat.equals(SQLITE_MIMETYPE) //Skip sqlite files, Tika cannot handle virtual tables and will fail with an exception. //NON-NLS + public boolean isSupported() { + if(!(content instanceof AbstractFile)) { + return false; + } + + String detectedType = ((AbstractFile)content).getMIMEType(); + if (detectedType == null + || BINARY_MIME_TYPES.contains(detectedType) //any binary unstructured blobs (string extraction will be used) + || ARCHIVE_MIME_TYPES.contains(detectedType) + || (detectedType.startsWith("video/") && !detectedType.equals("video/x-flv")) //skip video other than flv (tika supports flv only) //NON-NLS + || detectedType.equals(SQLITE_MIMETYPE) //Skip sqlite files, Tika cannot handle virtual tables and will fail with an exception. //NON-NLS ) { return false; } - return TIKA_SUPPORTED_TYPES.contains(detectedFormat); + + return TIKA_SUPPORTED_TYPES.contains(detectedType); } /** @@ -280,26 +449,17 @@ final class TikaTextExtractor extends TextExtractor { * @return String of all language packs available for Tesseract to use */ private static String getLanguagePacks() { - File languagePackRootDir = new File(TESSERACT_PATH.getParent(), "tessdata"); - //Acceptable extensions for Tesseract-OCR version 3.05 language packs. - //All extensions other than traineddata are associated with cube files that - //have been made obsolete since version 4.0. - List acceptableExtensions = Arrays.asList("traineddata", "params", - "lm", "fold", "bigrams", "nn", "word-freq", "size", - "user-patterns", "user-words"); - //Pull out only unique languagePacks - HashSet languagePacks = new HashSet<>(); - if (languagePackRootDir.exists()) { - for (File languagePack : languagePackRootDir.listFiles()) { - if (languagePack.isDirectory() || !acceptableExtensions.contains( - FilenameUtils.getExtension(languagePack.getName()))) { - continue; - } - String threeLetterPackageName = languagePack.getName().substring(0, 3); - //Ignore the eng language pack if accidentally added - languagePacks.add(threeLetterPackageName); + File languagePackRootDir = new File(PlatformUtil.getOcrLanguagePacksPath()); + + List languagePacks = new ArrayList<>(); + for (File languagePack : languagePackRootDir.listFiles()) { + String fileExt = FilenameUtils.getExtension(languagePack.getName()); + if (!languagePack.isDirectory() && TESSERACT_LANGUAGE_PACK_EXT.equals(fileExt)) { + String packageName = FilenameUtils.getBaseName(languagePack.getName()); + languagePacks.add(packageName); } } + return String.join("+", languagePacks); } @@ -330,21 +490,23 @@ final class TikaTextExtractor extends TextExtractor { * Determines how the extraction process will proceed given the settings * stored in this context instance. * - * See the ImageFileExtractionConfig class in the extractionconfigs package - * for available settings. + * See the ImageConfig class in the extractionconfigs package for available + * settings. * * @param context Instance containing config classes */ @Override public void setExtractionSettings(Lookup context) { if (context != null) { - ImageFileExtractionConfig configInstance = context.lookup(ImageFileExtractionConfig.class); - if (configInstance == null) { - return; - } - if (Objects.nonNull(configInstance.getOCREnabled())) { + ImageConfig configInstance = context.lookup(ImageConfig.class); + if (configInstance != null && Objects.nonNull(configInstance.getOCREnabled())) { this.tesseractOCREnabled = configInstance.getOCREnabled(); } + + ProcessTerminator terminatorInstance = context.lookup(ProcessTerminator.class); + if (terminatorInstance != null) { + this.processTerminator = terminatorInstance; + } } } diff --git a/Core/src/org/sleuthkit/autopsy/textextractors/extractionconfigs/ImageFileExtractionConfig.java b/Core/src/org/sleuthkit/autopsy/textextractors/configs/ImageConfig.java similarity index 63% rename from Core/src/org/sleuthkit/autopsy/textextractors/extractionconfigs/ImageFileExtractionConfig.java rename to Core/src/org/sleuthkit/autopsy/textextractors/configs/ImageConfig.java index 944e2f39fb..33d7987537 100755 --- a/Core/src/org/sleuthkit/autopsy/textextractors/extractionconfigs/ImageFileExtractionConfig.java +++ b/Core/src/org/sleuthkit/autopsy/textextractors/configs/ImageConfig.java @@ -16,25 +16,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.textextractors.extractionconfigs; +package org.sleuthkit.autopsy.textextractors.configs; /** - * Allows for configuration of OCR on image files. - * {@link org.sleuthkit.autopsy.textextractors.TextExtractor}'s that use - * ImageFileExtractionConfig can be obtained through - * {@link org.sleuthkit.autopsy.textextractors.TextExtractorFactory#getExtractor(org.sleuthkit.datamodel.Content)} - * or - * {@link org.sleuthkit.autopsy.textextractors.TextExtractorFactory#getDefaultExtractor(org.sleuthkit.datamodel.Content, org.openide.util.Lookup)}. + * Allows for configuration of OCR on image files. Extractors that use ImageConfig + * can be obtained through TextExtractoryFactory.getExtractor(). * - * @see org.sleuthkit.autopsy.textextractors.TextExtractorFactory * @see org.openide.util.Lookup */ -public class ImageFileExtractionConfig { +public class ImageConfig { private Boolean OCREnabled; /** - * Enables OCR to be run on the text extractor responsible for handling + * Enables OCR to be run on the text reader responsible for handling * image files. * * @param enabled Flag indicating if OCR is enabled. diff --git a/Core/src/org/sleuthkit/autopsy/textextractors/extractionconfigs/DefaultExtractionConfig.java b/Core/src/org/sleuthkit/autopsy/textextractors/configs/StringsConfig.java similarity index 66% rename from Core/src/org/sleuthkit/autopsy/textextractors/extractionconfigs/DefaultExtractionConfig.java rename to Core/src/org/sleuthkit/autopsy/textextractors/configs/StringsConfig.java index 4e5a08a8ba..9cbdaea002 100755 --- a/Core/src/org/sleuthkit/autopsy/textextractors/extractionconfigs/DefaultExtractionConfig.java +++ b/Core/src/org/sleuthkit/autopsy/textextractors/configs/StringsConfig.java @@ -16,33 +16,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.textextractors.extractionconfigs; +package org.sleuthkit.autopsy.textextractors.configs; import java.util.List; import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT; /** - * Allows for configuration of the - * {@link org.sleuthkit.autopsy.textextractors.TextExtractor} obtained from - * {@link org.sleuthkit.autopsy.textextractors.TextExtractorFactory#getDefaultExtractor(org.sleuthkit.datamodel.Content, org.openide.util.Lookup)}. + * Allows for configuration of the TextExtractor obtained from + * TextExtractorFactory.getStringsExtractor(). * - * The default extractor will read strings from the Content instance. This class - * allows for the configuration of the encoding language script to use during - * extraction. + * The Strings extractor will extract strings from the Content instance. This + * class allows for the configuration of the encoding and language scripts that + * will be used. * * @see org.sleuthkit.autopsy.textextractors.TextExtractorFactory * @see * org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT * @see org.openide.util.Lookup */ -public class DefaultExtractionConfig { +public class StringsConfig { private Boolean extractUTF8; private Boolean extractUTF16; - private List