From 2ca0c7de960965c28cec4da336c54856506ecb3e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 21 Dec 2018 12:37:51 -0500 Subject: [PATCH 01/30] Added HxD button --- .../autopsy/corecomponents/Bundle.properties | 1 + .../corecomponents/DataContentViewerHex.form | 23 +++++-- .../corecomponents/DataContentViewerHex.java | 63 ++++++++++++++----- 3 files changed, 66 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 299b0e18d4..38f8388cc4 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -193,3 +193,4 @@ ViewPreferencesPanel.keepCurrentViewerRadioButton.text=Stay on the same file vie 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 +DataContentViewerHex.launchHxDButton.text=Launch in HxD diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form index 745c862756..8c9b3c36a2 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form @@ -45,7 +45,7 @@ - + @@ -54,7 +54,7 @@ - + @@ -120,7 +120,9 @@ - + + + @@ -140,7 +142,10 @@ - + + + + @@ -289,6 +294,16 @@ + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index 6639856099..8d855b7aa0 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -21,6 +21,9 @@ package org.sleuthkit.autopsy.corecomponents; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; import java.util.logging.Level; import org.openide.util.NbBundle; @@ -29,9 +32,14 @@ import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.text.BadLocationException; import javax.swing.text.Utilities; +import org.openide.modules.InstalledFileLocator; import org.openide.nodes.Node; import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; +import org.sleuthkit.autopsy.coreutils.ExecUtil; +import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.DataConversion; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskException; @@ -105,6 +113,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont goToPageLabel = new javax.swing.JLabel(); goToOffsetLabel = new javax.swing.JLabel(); goToOffsetTextField = new javax.swing.JTextField(); + launchHxDButton = new javax.swing.JButton(); copyMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerHex.class, "DataContentViewerHex.copyMenuItem.text")); // NOI18N rightClickMenu.add(copyMenuItem); @@ -187,6 +196,13 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont } }); + launchHxDButton.setText(org.openide.util.NbBundle.getMessage(DataContentViewerHex.class, "DataContentViewerHex.launchHxDButton.text")); // NOI18N + launchHxDButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + launchHxDButtonActionPerformed(evt); + } + }); + javax.swing.GroupLayout hexViewerPanelLayout = new javax.swing.GroupLayout(hexViewerPanel); hexViewerPanel.setLayout(hexViewerPanelLayout); hexViewerPanelLayout.setHorizontalGroup( @@ -214,7 +230,9 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont .addComponent(goToOffsetLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(32, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(launchHxDButton) + .addContainerGap(39, Short.MAX_VALUE)) ); hexViewerPanelLayout.setVerticalGroup( hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -231,7 +249,9 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont .addComponent(goToPageLabel) .addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(goToOffsetLabel) - .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(launchHxDButton))) .addGap(0, 0, 0)) ); @@ -241,7 +261,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 100, Short.MAX_VALUE) + .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 686, Short.MAX_VALUE) .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( @@ -249,7 +269,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 27, Short.MAX_VALUE)) + .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 267, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -334,6 +354,27 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont } }//GEN-LAST:event_goToOffsetTextFieldActionPerformed + private void launchHxDButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_launchHxDButtonActionPerformed + try { + String tempDirectory = Case.getCurrentCaseThrows().getTempDirectory(); + File dataSourceInTempDirectory = Paths.get(tempDirectory, dataSource.getId() + dataSource.getName()).toFile(); + ContentUtils.writeToFile(dataSource, dataSourceInTempDirectory); + + String HdXExecutableToFind = Paths.get("HxD", "HxD64.exe").toString(); + File HdXExecutable = InstalledFileLocator.getDefault().locate(HdXExecutableToFind, DataContentViewerHex.class.getPackage().getName(), false); + if (null == HdXExecutable) { + throw new IOException(String.format("Could not find HdXExecutable at %s", HdXExecutableToFind)); + } + + ProcessBuilder launchHdXExecutable = new ProcessBuilder(); + launchHdXExecutable.command(String.format("%s \"%s\"", HdXExecutable.getAbsolutePath(), dataSourceInTempDirectory.getAbsolutePath())); + ExecUtil.execute(launchHdXExecutable); + } catch (NoCurrentCaseException | IOException ex) { + logger.log(Level.SEVERE, "Unable to launch HxD Editor", ex); + //TODO - Make pop-up appear saying there were problems attempting to launch editor + } + }//GEN-LAST:event_launchHxDButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JMenuItem copyMenuItem; private javax.swing.JLabel currentPageLabel; @@ -344,6 +385,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont private javax.swing.JPanel hexViewerPanel; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JScrollPane jScrollPane3; + private javax.swing.JButton launchHxDButton; private javax.swing.JButton nextPageButton; private javax.swing.JLabel ofLabel; private javax.swing.JTextArea outputTextArea; @@ -528,17 +570,4 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont public Component getComponent() { return this; } - - /* - * Show the right click menu only if evt is the correct mouse event - */ - private void maybeShowPopup(java.awt.event.MouseEvent evt) { - if (evt.isPopupTrigger()) { - rightClickMenu.setLocation(evt.getLocationOnScreen()); - rightClickMenu.setVisible(true); - copyMenuItem.setEnabled(outputTextArea.getSelectedText() != null); - } else { - rightClickMenu.setVisible(false); - } - } } From 25f40787a475524cf47b04613f9441482602b482 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 21 Dec 2018 17:35:38 -0500 Subject: [PATCH 02/30] Making significant progress on redoing UI and adding in new HxD path --- .../autopsy/directorytree/Bundle.properties | 23 +- .../ExternalViewerGlobalSettingsPanel.form | 467 ++++++++++-------- .../ExternalViewerGlobalSettingsPanel.java | 378 +++++++------- 3 files changed, 443 insertions(+), 425 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties index 26c970b2b3..1526f404c0 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties @@ -90,12 +90,6 @@ ExtractUnallocAction.done.errMsg.msg=Error extracting unallocated space\: {0} ExtractAction.done.notifyMsg.extractErr=Error extracting files\: {0} OptionsCategory_Name_ExternalViewer=External Viewer OptionsCategory_Keywords_ExternalViewer=ExternalViewer -ExternalViewerGlobalSettingsPanel.newRuleButton.text=New Rule -ExternalViewerGlobalSettingsPanel.editRuleButton.text=Edit Rule -ExternalViewerGlobalSettingsPanel.deleteRuleButton.text=Delete Rule -ExternalViewerGlobalSettingsPanel.externalViewerTitleLabel.text=Add your custom rules for external viewers -ExternalViewerGlobalSettingsPanel.ruleListLabel.text=MIME type and extensions -ExternalViewerGlobalSettingsPanel.exePathLabel.text=Program associated with this MIME type or extension ExternalViewerGlobalSettingsPanel.exePathLabel.MIME.text=Program associated with this MIME type ExternalViewerGlobalSettingsPanel.exePathLabel.EXT.text=Program associated with this extension ExternalViewerGlobalSettingsPanel.exePathLabel.empty.text=No MIME type or extension selected @@ -108,7 +102,6 @@ ExternalViewerGlobalSettingsPanel.JOptionPane.invalidExt.message=The extension i ExternalViewerGlobalSettingsPanel.JOptionPane.invalidExt.title=Invalid extension ExternalViewerGlobalSettingsPanel.JOptionPane.invalidExePath.message=The path to the program executable is invalid ExternalViewerGlobalSettingsPanel.JOptionPane.invalidExePath.title=Invalid Path -ExternalViewerGlobalSettingsPanel.exePathNameLabel.text=No MIME type or extension currently selected ExternalViewerGlobalSettingsPanel.JOptionPane.ruleAlreadyExists.message=A rule already exists with this MIME type or extension. Please edit that one. ExternalViewerGlobalSettingsPanel.JOptionPane.ruleAlreadyExists.title=Rule not added AddExternalViewerRulePanel.mimeRadioButton.text=MIME type @@ -124,3 +117,19 @@ GroupDataSourcesDialog.yesButton.text=Yes GroupDataSourcesDialog.noButton.text=No GroupDataSourcesDialog.title=Group by Data Source? DirectoryTreeTopComponent.openViewPreferencesButton.text= +ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title3=Title 4 +ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title2=Title 3 +ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title3_1=Title 4 +ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title2_1=Title 3 +ExternalViewerGlobalSettingsPanel.newRuleButton1.text=New Rule +ExternalViewerGlobalSettingsPanel.editRuleButton.text=Edit Rule +ExternalViewerGlobalSettingsPanel.deleteRuleButton.text=Delete Rule +ExternalViewerGlobalSettingsPanel.externalViewerTitleLabel.text=Set aplication viewer to use for files with specific mime types/extensions: +ExternalViewerGlobalSettingsPanel.newRuleButton.text=New Rule +ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title1=Application +ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title0=Mime type/Extension +ExternalViewerGlobalSettingsPanel.jLabel1.text=HxD Editor Path: +ExternalViewerGlobalSettingsPanel.jTextField1.text=C:/Program Files/HxD +ExternalViewerGlobalSettingsPanel.jButton1.text=Browse +ExternalViewerGlobalSettingsPanel.jButton2.text=jButton2 +ExternalViewerGlobalSettingsPanel.jLabel2.text=Set launchable content viewer extensions diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form index e04dc19270..e082b56e6f 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form @@ -1,6 +1,31 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + @@ -21,12 +46,12 @@ - + - + @@ -41,241 +66,257 @@ - - - - - - - - - - + + + + + + + + - - - - - - - - - - + + + + + - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + <ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + + + + + + + <ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index f5351393dc..aab3d3acf9 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * + * * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,14 +20,11 @@ package org.sleuthkit.autopsy.directorytree; import java.util.ArrayList; import java.util.Collections; -import javax.swing.DefaultListModel; -import javax.swing.JOptionPane; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import org.netbeans.spi.options.OptionsPanelController; -import org.openide.util.NbBundle; +import javax.swing.table.DefaultTableModel; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; -import org.sleuthkit.autopsy.coreutils.Logger; +import javax.swing.JOptionPane; +import org.openide.util.NbBundle; +import org.netbeans.spi.options.OptionsPanelController; /** * An options panel for the user to create, edit, and delete associations for @@ -37,8 +34,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel implements OptionsPanel { - private static final Logger logger = Logger.getLogger(ExternalViewerGlobalSettingsPanel.class.getName()); - private DefaultListModel rulesListModel; + private DefaultTableModel rulesTableModel; private java.util.List rules; /** @@ -53,21 +49,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme * Initializes field variables. Adds a listener to the list of rules. */ private void customizeComponents() { - rulesListModel = new DefaultListModel<>(); rules = new ArrayList<>(); - rulesList.setModel(rulesListModel); - rulesList.addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - if (e.getValueIsAdjusting() == false) { - if (rulesList.getSelectedIndex() == -1) { - clearExePath(); - } else { - populateExePath(); - } - } - } - }); } /** @@ -79,60 +61,33 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme // //GEN-BEGIN:initComponents private void initComponents() { + newRuleButton1 = new javax.swing.JButton(); + jButton2 = new javax.swing.JButton(); jPanel1 = new javax.swing.JPanel(); - externalViewerTitleLabel = new javax.swing.JLabel(); - jScrollPane1 = new javax.swing.JScrollPane(); - jSplitPane1 = new javax.swing.JSplitPane(); - exePanel = new javax.swing.JPanel(); - exePathLabel = new javax.swing.JLabel(); - exePathNameLabel = new javax.swing.JLabel(); - rulesPanel = new javax.swing.JPanel(); - ruleListLabel = new javax.swing.JLabel(); + jPanel2 = new javax.swing.JPanel(); newRuleButton = new javax.swing.JButton(); - editRuleButton = new javax.swing.JButton(); + jScrollPane4 = new javax.swing.JScrollPane(); + jTable1 = new javax.swing.JTable(); + externalViewerTitleLabel = new javax.swing.JLabel(); deleteRuleButton = new javax.swing.JButton(); - jScrollPane2 = new javax.swing.JScrollPane(); - rulesList = new javax.swing.JList<>(); + editRuleButton = new javax.swing.JButton(); + jPanel3 = new javax.swing.JPanel(); + jTextField1 = new javax.swing.JTextField(); + jLabel1 = new javax.swing.JLabel(); + jLabel2 = new javax.swing.JLabel(); + jButton1 = new javax.swing.JButton(); + + newRuleButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(newRuleButton1, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.newRuleButton1.text")); // NOI18N + newRuleButton1.setMaximumSize(new java.awt.Dimension(111, 25)); + newRuleButton1.setMinimumSize(new java.awt.Dimension(111, 25)); + + org.openide.awt.Mnemonics.setLocalizedText(jButton2, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jButton2.text")); // NOI18N setPreferredSize(new java.awt.Dimension(701, 453)); jPanel1.setPreferredSize(new java.awt.Dimension(701, 453)); - org.openide.awt.Mnemonics.setLocalizedText(externalViewerTitleLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.externalViewerTitleLabel.text")); // NOI18N - - jSplitPane1.setDividerSize(1); - - exePanel.setPreferredSize(new java.awt.Dimension(311, 224)); - - org.openide.awt.Mnemonics.setLocalizedText(exePathLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.exePathLabel.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(exePathNameLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.exePathNameLabel.text")); // NOI18N - - javax.swing.GroupLayout exePanelLayout = new javax.swing.GroupLayout(exePanel); - exePanel.setLayout(exePanelLayout); - exePanelLayout.setHorizontalGroup( - exePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(exePanelLayout.createSequentialGroup() - .addContainerGap() - .addGroup(exePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(exePathLabel) - .addComponent(exePathNameLabel)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - exePanelLayout.setVerticalGroup( - exePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(exePanelLayout.createSequentialGroup() - .addContainerGap() - .addComponent(exePathLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(exePathNameLabel) - .addContainerGap(355, Short.MAX_VALUE)) - ); - - jSplitPane1.setRightComponent(exePanel); - - org.openide.awt.Mnemonics.setLocalizedText(ruleListLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.ruleListLabel.text")); // NOI18N - newRuleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(newRuleButton, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.newRuleButton.text")); // NOI18N newRuleButton.setMaximumSize(new java.awt.Dimension(111, 25)); @@ -143,6 +98,40 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme } }); + jScrollPane4.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(204, 204, 204))); + + rulesTableModel = new javax.swing.table.DefaultTableModel( + new Object [][] { + + }, + new String [] { + "Mime type/Extension", "Application" + } + ) { + @Override + public boolean isCellEditable(int i, int i1) { + return false; + } + }; + jTable1.setModel(rulesTableModel); + jScrollPane4.setViewportView(jTable1); + if (jTable1.getColumnModel().getColumnCount() > 0) { + jTable1.getColumnModel().getColumn(0).setHeaderValue(org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title0")); // NOI18N + jTable1.getColumnModel().getColumn(1).setHeaderValue(org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title1")); // NOI18N + } + + org.openide.awt.Mnemonics.setLocalizedText(externalViewerTitleLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.externalViewerTitleLabel.text")); // NOI18N + + deleteRuleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteRuleButton, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.deleteRuleButton.text")); // NOI18N + deleteRuleButton.setMaximumSize(new java.awt.Dimension(111, 25)); + deleteRuleButton.setMinimumSize(new java.awt.Dimension(111, 25)); + deleteRuleButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + deleteRuleButtonActionPerformed(evt); + } + }); + editRuleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/edit16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(editRuleButton, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.editRuleButton.text")); // NOI18N editRuleButton.setMaximumSize(new java.awt.Dimension(111, 25)); @@ -153,94 +142,126 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme } }); - deleteRuleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(deleteRuleButton, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.deleteRuleButton.text")); // NOI18N - deleteRuleButton.setMaximumSize(new java.awt.Dimension(111, 25)); - deleteRuleButton.setMinimumSize(new java.awt.Dimension(111, 25)); - deleteRuleButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - deleteRuleButtonActionPerformed(evt); - } - }); - - jScrollPane2.setViewportView(rulesList); - - javax.swing.GroupLayout rulesPanelLayout = new javax.swing.GroupLayout(rulesPanel); - rulesPanel.setLayout(rulesPanelLayout); - rulesPanelLayout.setHorizontalGroup( - rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(rulesPanelLayout.createSequentialGroup() + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() .addContainerGap() - .addGroup(rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(ruleListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, rulesPanelLayout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(newRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(16, 16, 16) - .addComponent(editRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(16, 16, 16) - .addComponent(deleteRuleButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addComponent(jScrollPane2)) - .addContainerGap()) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane4, javax.swing.GroupLayout.PREFERRED_SIZE, 634, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(jPanel2Layout.createSequentialGroup() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(externalViewerTitleLabel) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(newRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, 97, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(editRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deleteRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) ); - rulesPanelLayout.setVerticalGroup( - rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(rulesPanelLayout.createSequentialGroup() - .addContainerGap() - .addComponent(ruleListLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane2) + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(externalViewerTitleLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGap(12, 12, 12) - .addGroup(rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(newRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(editRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jScrollPane4, javax.swing.GroupLayout.PREFERRED_SIZE, 219, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(newRuleButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(editRuleButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(deleteRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); - jSplitPane1.setLeftComponent(rulesPanel); + jTextField1.setText(org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jTextField1.text")); // NOI18N + jTextField1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jTextField1ActionPerformed(evt); + } + }); - jScrollPane1.setViewportView(jSplitPane1); + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jLabel1.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jLabel2.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jButton1.text")); // NOI18N + jButton1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButton1ActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jLabel2) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(jPanel3Layout.createSequentialGroup() + .addGap(21, 21, 21) + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jTextField1, javax.swing.GroupLayout.DEFAULT_SIZE, 441, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jButton1)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(externalViewerTitleLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 681, Short.MAX_VALUE) - .addContainerGap()) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jScrollPane1) - .addContainerGap())) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(547, 547, 547)) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() - .addComponent(externalViewerTitleLabel) - .addContainerGap(428, Short.MAX_VALUE)) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(32, 32, 32) - .addComponent(jScrollPane1) - .addContainerGap())) + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(83, Short.MAX_VALUE)) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 1191, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); }// //GEN-END:initComponents + private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_jButton1ActionPerformed + + private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jTextField1ActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_jTextField1ActionPerformed + private void newRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newRuleButtonActionPerformed AddExternalViewerRuleDialog dialog = new AddExternalViewerRuleDialog(); AddExternalViewerRuleDialog.BUTTON_PRESSED result = dialog.getResult(); @@ -254,9 +275,9 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme JOptionPane.ERROR_MESSAGE); } else { rules.add(newRule); - updateRulesListModel(); + updateRulesTableModel(); int index = rules.indexOf(newRule); - rulesList.setSelectedIndex(index); + jTable1.getSelectionModel().setSelectionInterval(index, index); enableButtons(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } @@ -264,33 +285,11 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme }//GEN-LAST:event_newRuleButtonActionPerformed private void editRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editRuleButtonActionPerformed - int selected = rulesList.getSelectedIndex(); - AddExternalViewerRuleDialog dialog = new AddExternalViewerRuleDialog(rulesListModel.get(rulesList.getSelectedIndex())); - AddExternalViewerRuleDialog.BUTTON_PRESSED result = dialog.getResult(); - if (result == AddExternalViewerRuleDialog.BUTTON_PRESSED.OK) { - rules.remove(selected); - ExternalViewerRule newRule = dialog.getRule(); - // Only allow one association for each MIME type or extension. - if (rules.contains(newRule)) { - JOptionPane.showMessageDialog(this, - NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.JOptionPane.ruleAlreadyExists.message"), - NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.JOptionPane.ruleAlreadyExists.title"), - JOptionPane.ERROR_MESSAGE); - } else { - rules.add(selected, dialog.getRule()); - updateRulesListModel(); - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - } - } - rulesList.setSelectedIndex(selected); - enableButtons(); + // TODO add your handling code here: }//GEN-LAST:event_editRuleButtonActionPerformed private void deleteRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteRuleButtonActionPerformed - ExternalViewerRule rule = rulesList.getSelectedValue(); - rules.remove(rule); - updateRulesListModel(); - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + // TODO add your handling code here: }//GEN-LAST:event_deleteRuleButtonActionPerformed @Override @@ -301,7 +300,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme @Override public void load() { rules = ExternalViewerRulesManager.getInstance().getUserRules(); - updateRulesListModel(); + updateRulesTableModel(); enableButtons(); } @@ -309,68 +308,37 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme * Enable edit and delete buttons if there is a rule selected. */ private void enableButtons() { - boolean ruleIsSelected = rulesList.getSelectedIndex() != -1; + boolean ruleIsSelected = jTable1.getSelectedRow() != -1; editRuleButton.setEnabled(ruleIsSelected); deleteRuleButton.setEnabled(ruleIsSelected); } /** - * Sets the list model for the rules list component, sorted by the MIME - * type or extension alphabetically. + * Sets the list model for the rules list component, sorted by the MIME type + * or extension alphabetically. */ - private void updateRulesListModel() { - rulesListModel.clear(); + private void updateRulesTableModel() { Collections.sort(rules); - for (ExternalViewerRule rule : rules) { - rulesListModel.addElement(rule); - } - } - - /** - * Fills in the .exe file path label if a rule is selected. - */ - private void populateExePath() { - ExternalViewerRule rule = rulesList.getSelectedValue(); - if (rule != null) { - if (rule.getRuleType() == ExternalViewerRule.RuleType.MIME) { - exePathLabel.setText(NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, - "ExternalViewerGlobalSettingsPanel.exePathLabel.MIME.text")); - } else { - exePathLabel.setText(NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, - "ExternalViewerGlobalSettingsPanel.exePathLabel.EXT.text")); - } - exePathNameLabel.setText(rule.getExePath()); - } - enableButtons(); - } - - /** - * Clears the .exe file path label. - */ - private void clearExePath() { - rulesList.clearSelection(); - exePathLabel.setText(NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, - "ExternalViewerGlobalSettingsPanel.exePathLabel.text")); - exePathNameLabel.setText(NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, - "ExternalViewerGlobalSettingsPanel.exePathLabel.empty.text")); - enableButtons(); + rules.forEach((rule) -> { + rulesTableModel.addRow(new Object[]{rule.getName(), rule.getExePath()}); + }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton deleteRuleButton; private javax.swing.JButton editRuleButton; - private javax.swing.JPanel exePanel; - private javax.swing.JLabel exePathLabel; - private javax.swing.JLabel exePathNameLabel; private javax.swing.JLabel externalViewerTitleLabel; + private javax.swing.JButton jButton1; + private javax.swing.JButton jButton2; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; private javax.swing.JPanel jPanel1; - private javax.swing.JScrollPane jScrollPane1; - private javax.swing.JScrollPane jScrollPane2; - private javax.swing.JSplitPane jSplitPane1; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; + private javax.swing.JScrollPane jScrollPane4; + private javax.swing.JTable jTable1; + private javax.swing.JTextField jTextField1; private javax.swing.JButton newRuleButton; - private javax.swing.JLabel ruleListLabel; - private javax.swing.JList rulesList; - private javax.swing.JPanel rulesPanel; - private javax.swing.JScrollPane rulesScrollPane; + private javax.swing.JButton newRuleButton1; // End of variables declaration//GEN-END:variables } From 5cc79ecce93cecaf0b1a92cc81fd5fffd418a8ff Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 31 Dec 2018 11:58:01 -0500 Subject: [PATCH 03/30] Reorganized the settings panel for External viewers --- .../autopsy/directorytree/Bundle.properties | 4 +- .../ExternalViewerGlobalSettingsPanel.form | 26 +-- .../ExternalViewerGlobalSettingsPanel.java | 190 ++++++++++++------ 3 files changed, 145 insertions(+), 75 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties index 1526f404c0..5857deb2b9 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties @@ -129,7 +129,7 @@ ExternalViewerGlobalSettingsPanel.newRuleButton.text=New Rule ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title1=Application ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title0=Mime type/Extension ExternalViewerGlobalSettingsPanel.jLabel1.text=HxD Editor Path: -ExternalViewerGlobalSettingsPanel.jTextField1.text=C:/Program Files/HxD -ExternalViewerGlobalSettingsPanel.jButton1.text=Browse ExternalViewerGlobalSettingsPanel.jButton2.text=jButton2 ExternalViewerGlobalSettingsPanel.jLabel2.text=Set launchable content viewer extensions +ExternalViewerGlobalSettingsPanel.browseHxDDirectory.text=Browse +ExternalViewerGlobalSettingsPanel.HxDPath.text=C:/Program Files/HxD/HxD.exe diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form index e082b56e6f..b3d33e0b2b 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form @@ -169,9 +169,6 @@ - - - @@ -196,7 +193,6 @@ - @@ -261,9 +257,9 @@ - + - + @@ -273,9 +269,9 @@ - + - + @@ -283,15 +279,13 @@ - + + - + - - - @@ -307,14 +301,14 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index aab3d3acf9..1903729ec5 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -18,13 +18,16 @@ */ package org.sleuthkit.autopsy.directorytree; +import java.io.File; import java.util.ArrayList; -import java.util.Collections; -import javax.swing.table.DefaultTableModel; +import javax.swing.JFileChooser; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import javax.swing.JOptionPane; +import javax.swing.table.AbstractTableModel; import org.openide.util.NbBundle; import org.netbeans.spi.options.OptionsPanelController; +import org.sleuthkit.autopsy.casemodule.GeneralFilter; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; /** * An options panel for the user to create, edit, and delete associations for @@ -34,8 +37,10 @@ import org.netbeans.spi.options.OptionsPanelController; @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel implements OptionsPanel { - private DefaultTableModel rulesTableModel; + private RulesTableModel rulesTableModel; private java.util.List rules; + private static final String MODULE_NAME = ExternalViewerGlobalSettingsPanel.class.getName(); + private static final String HXD_PATH_NAME = "HxDExecutablePath"; /** * Creates new form ExternalViewerGlobalSettingsPanel @@ -50,6 +55,10 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme */ private void customizeComponents() { rules = new ArrayList<>(); + rulesTableModel = new RulesTableModel(new String[] { + "Mime type/Extension", "Application"}); + jTable1.setModel(rulesTableModel); + jTable1.setAutoCreateRowSorter(true); } /** @@ -72,10 +81,10 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme deleteRuleButton = new javax.swing.JButton(); editRuleButton = new javax.swing.JButton(); jPanel3 = new javax.swing.JPanel(); - jTextField1 = new javax.swing.JTextField(); + HxDPath = new javax.swing.JTextField(); jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); - jButton1 = new javax.swing.JButton(); + browseHxDDirectory = new javax.swing.JButton(); newRuleButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(newRuleButton1, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.newRuleButton1.text")); // NOI18N @@ -100,20 +109,6 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme jScrollPane4.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(204, 204, 204))); - rulesTableModel = new javax.swing.table.DefaultTableModel( - new Object [][] { - - }, - new String [] { - "Mime type/Extension", "Application" - } - ) { - @Override - public boolean isCellEditable(int i, int i1) { - return false; - } - }; - jTable1.setModel(rulesTableModel); jScrollPane4.setViewportView(jTable1); if (jTable1.getColumnModel().getColumnCount() > 0) { jTable1.getColumnModel().getColumn(0).setHeaderValue(org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title0")); // NOI18N @@ -175,21 +170,17 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme .addContainerGap()) ); - jTextField1.setText(org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jTextField1.text")); // NOI18N - jTextField1.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - jTextField1ActionPerformed(evt); - } - }); + HxDPath.setEditable(false); + HxDPath.setText(org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.HxDPath.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jLabel1.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jLabel2.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jButton1.text")); // NOI18N - jButton1.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(browseHxDDirectory, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.browseHxDDirectory.text")); // NOI18N + browseHxDDirectory.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - jButton1ActionPerformed(evt); + browseHxDDirectoryActionPerformed(evt); } }); @@ -204,9 +195,9 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme .addGap(21, 21, 21) .addComponent(jLabel1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jTextField1, javax.swing.GroupLayout.DEFAULT_SIZE, 441, Short.MAX_VALUE) + .addComponent(HxDPath, javax.swing.GroupLayout.DEFAULT_SIZE, 441, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(browseHxDDirectory, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE)) ); jPanel3Layout.setVerticalGroup( jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -214,9 +205,9 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(HxDPath, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jButton1)) + .addComponent(browseHxDDirectory)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); @@ -254,13 +245,24 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme ); }// //GEN-END:initComponents - private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed - // TODO add your handling code here: - }//GEN-LAST:event_jButton1ActionPerformed - - private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jTextField1ActionPerformed - // TODO add your handling code here: - }//GEN-LAST:event_jTextField1ActionPerformed + private void browseHxDDirectoryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseHxDDirectoryActionPerformed + JFileChooser fileWindow = new JFileChooser(); + fileWindow.setFileSelectionMode(JFileChooser.FILES_ONLY); + GeneralFilter exeFilter = new GeneralFilter(GeneralFilter.EXECUTABLE_EXTS, GeneralFilter.EXECUTABLE_DESC); + File HxDPathFile = new File(HxDPath.getText()); + if(HxDPathFile.exists() && HxDPathFile.canExecute()) { + fileWindow.setCurrentDirectory(new File(HxDPath.getText())); + } + fileWindow.setDragEnabled(false); + fileWindow.setFileFilter(exeFilter); + fileWindow.setMultiSelectionEnabled(false); + int returnVal = fileWindow.showSaveDialog(this); + if(returnVal == JFileChooser.APPROVE_OPTION) { + File HxDExecutable = fileWindow.getSelectedFile(); + HxDPath.setText(HxDExecutable.getAbsolutePath()); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + } + }//GEN-LAST:event_browseHxDDirectoryActionPerformed private void newRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newRuleButtonActionPerformed AddExternalViewerRuleDialog dialog = new AddExternalViewerRuleDialog(); @@ -275,60 +277,135 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme JOptionPane.ERROR_MESSAGE); } else { rules.add(newRule); - updateRulesTableModel(); + rulesTableModel.fireTableDataChanged(); int index = rules.indexOf(newRule); + jTable1.getSelectionModel().clearSelection(); jTable1.getSelectionModel().setSelectionInterval(index, index); - enableButtons(); + checkButtons(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } } }//GEN-LAST:event_newRuleButtonActionPerformed private void editRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editRuleButtonActionPerformed - // TODO add your handling code here: + int selectedIndex = jTable1.convertRowIndexToModel(jTable1.getSelectedRow()); + ExternalViewerRule selectedRule = rulesTableModel.getRuleAt(selectedIndex); + AddExternalViewerRuleDialog dialog = new AddExternalViewerRuleDialog(selectedRule); + AddExternalViewerRuleDialog.BUTTON_PRESSED result = dialog.getResult(); + if (result == AddExternalViewerRuleDialog.BUTTON_PRESSED.OK) { + ExternalViewerRule newRule = dialog.getRule(); + // Only allow one association for each MIME type or extension. + if (rules.contains(newRule)) { + JOptionPane.showMessageDialog(this, + NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.JOptionPane.ruleAlreadyExists.message"), + NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.JOptionPane.ruleAlreadyExists.title"), + JOptionPane.ERROR_MESSAGE); + } else { + rules.set(selectedIndex, dialog.getRule()); + rulesTableModel.fireTableDataChanged(); + jTable1.getSelectionModel().clearSelection(); + int tableIndex = jTable1.convertRowIndexToView(selectedIndex); + jTable1.getSelectionModel().setSelectionInterval(tableIndex, tableIndex); + checkButtons(); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + } + } }//GEN-LAST:event_editRuleButtonActionPerformed private void deleteRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteRuleButtonActionPerformed - // TODO add your handling code here: + ExternalViewerRule selectedRule = rulesTableModel.getRuleAt(jTable1.convertRowIndexToModel(jTable1.getSelectedRow())); + rules.remove(selectedRule); + rulesTableModel.fireTableDataChanged(); + jTable1.getSelectionModel().clearSelection(); + checkButtons(); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_deleteRuleButtonActionPerformed @Override public void store() { ExternalViewerRulesManager.getInstance().setUserRules(rules); + ModuleSettings.setConfigSetting(MODULE_NAME, HXD_PATH_NAME, HxDPath.getText()); } @Override public void load() { rules = ExternalViewerRulesManager.getInstance().getUserRules(); - updateRulesTableModel(); - enableButtons(); + if(ModuleSettings.settingExists(MODULE_NAME, HXD_PATH_NAME)) { + HxDPath.setText(ModuleSettings.getConfigSetting(MODULE_NAME, HXD_PATH_NAME)); + } + rulesTableModel.fireTableDataChanged(); + checkButtons(); } /** * Enable edit and delete buttons if there is a rule selected. */ - private void enableButtons() { - boolean ruleIsSelected = jTable1.getSelectedRow() != -1; + private void checkButtons() { + boolean ruleIsSelected = jTable1.getRowCount() > 0; editRuleButton.setEnabled(ruleIsSelected); deleteRuleButton.setEnabled(ruleIsSelected); } - + /** - * Sets the list model for the rules list component, sorted by the MIME type - * or extension alphabetically. + * */ - private void updateRulesTableModel() { - Collections.sort(rules); - rules.forEach((rule) -> { - rulesTableModel.addRow(new Object[]{rule.getName(), rule.getExePath()}); - }); + private class RulesTableModel extends AbstractTableModel { + private final String[] columnNames; + + public RulesTableModel(String[] columnNames) { + this.columnNames = columnNames; + } + + public void addRule(ExternalViewerRule rule) { + rules.add(rule); + fireTableRowsInserted(rules.size()-1, rules.size()-1); + } + + @Override + public int getRowCount() { + return rules.size(); + } + + @Override + public String getColumnName(int columnIndex) { + return columnNames[columnIndex]; + } + + @Override + public Class getColumnClass(int columnIndex) { + return String.class; + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + if(columnIndex == 0) { + return rules.get(rowIndex).getName(); + } else { + return rules.get(rowIndex).getExePath(); + } + } + + public ExternalViewerRule getRuleAt(int rowIndex) { + return rules.get(rowIndex); + } + + @Override + public boolean isCellEditable(int rowIndex, int colIndex) { + return false; + } } // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JTextField HxDPath; + private javax.swing.JButton browseHxDDirectory; private javax.swing.JButton deleteRuleButton; private javax.swing.JButton editRuleButton; private javax.swing.JLabel externalViewerTitleLabel; - private javax.swing.JButton jButton1; private javax.swing.JButton jButton2; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; @@ -337,7 +414,6 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme private javax.swing.JPanel jPanel3; private javax.swing.JScrollPane jScrollPane4; private javax.swing.JTable jTable1; - private javax.swing.JTextField jTextField1; private javax.swing.JButton newRuleButton; private javax.swing.JButton newRuleButton1; // End of variables declaration//GEN-END:variables From 490ea446cda7e01f5bf3e4a4fbd8b3c0ba49910c Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 31 Dec 2018 14:47:39 -0500 Subject: [PATCH 04/30] HdXViewer capability has been added to the Hex Viewer --- .../autopsy/core/UserPreferences.java | 18 ++++++ .../autopsy/corecomponents/Bundle.properties | 30 ++++++++++ .../corecomponents/DataContentViewerHex.java | 35 +++++++---- .../autopsy/directorytree/Bundle.properties | 9 +-- .../ExternalViewerGlobalSettingsPanel.form | 3 - .../ExternalViewerGlobalSettingsPanel.java | 58 ++++++++++--------- 6 files changed, 105 insertions(+), 48 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index 2be9a9b447..bf4d5dc3c1 100644 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.core; +import java.nio.file.Paths; import org.sleuthkit.autopsy.coreutils.TextConverter; import java.util.prefs.BackingStoreException; import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo; @@ -75,6 +76,7 @@ public final class UserPreferences { public static final String SHOW_ONLY_CURRENT_USER_TAGS = "ShowOnlyCurrentUserTags"; public static final String HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES = "HideCentralRepoCommentsAndOccurrences"; public static final String DISPLAY_TRANSLATED_NAMES = "DisplayTranslatedNames"; + public static final String HDX_EDITOR_PATH = "HdXEditorPath"; // Prevent instantiation. private UserPreferences() { @@ -471,4 +473,20 @@ public final class UserPreferences { public static void setLogFileCount(int count) { preferences.putInt(MAX_NUM_OF_LOG_FILE, count); } + + /** + * + * @param executablePath + */ + public static void setHdXEditorPath(String executablePath) { + preferences.put(HDX_EDITOR_PATH, executablePath); + } + + /** + * + * @return + */ + public static String getHdXEditorPath() { + return preferences.get(HDX_EDITOR_PATH, Paths.get("C:", "Program Files", "HxD", "HxD.exe").toString()); + } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 38f8388cc4..d91a751a1a 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -194,3 +194,33 @@ ViewPreferencesPanel.useBestViewerRadioButton.toolTipText=For example, change fr ViewPreferencesPanel.useBestViewerRadioButton.text=Change to the most specific file viewer ViewPreferencesPanel.fileNameTranslationColumnCheckbox.text=Add column in result viewer for file name translation DataContentViewerHex.launchHxDButton.text=Launch in HxD +ExternalViewerGlobalSettingsPanel.jButton2.text=jButton2 +ExternalViewerGlobalSettingsPanel.newRuleButton1.text=New Rule +ExternalViewerGlobalSettingsPanel.newRuleButton.text=New Rule +ExternalViewerGlobalSettingsPanel.browseHxDDirectory.text=Browse +ExternalViewerGlobalSettingsPanel.jLabel2.text=Set launchable content viewer extensions +ExternalViewerGlobalSettingsPanel.jLabel1.text=HxD Editor Path: +ExternalViewerGlobalSettingsPanel.editRuleButton.text=Edit Rule +ExternalViewerGlobalSettingsPanel.deleteRuleButton.text=Delete Rule +ExternalViewerGlobalSettingsPanel.externalViewerTitleLabel.text=Set aplication viewer to use for files with specific mime types/extensions: +ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title1=Application +ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title0=Mime type/Extension +AddExternalViewerRulePanel.nameLabel.text=MIME type or extension +AddExternalViewerRulePanel.browseButton.text=Browse +AddExternalViewerRulePanel.exePathTextField.text= +AddExternalViewerRulePanel.exePathLabel.text=Path of the program to use for files with this type or extension +AddExternalViewerRulePanel.extRadioButton.text=Extension +AddExternalViewerRulePanel.mimeRadioButton.text=MIME type +AddExternalViewerRulePanel.nameTextField.text= +ExternalViewerGlobalSettingsPanel.jButton2.text_1=jButton2 +ExternalViewerGlobalSettingsPanel.newRuleButton1.text_1=New Rule +ExternalViewerGlobalSettingsPanel.newRuleButton.text_1=New Rule +ExternalViewerGlobalSettingsPanel.browseHxDDirectory.text_1=Browse +ExternalViewerGlobalSettingsPanel.jLabel2.text_1=Set launchable content viewer extensions +ExternalViewerGlobalSettingsPanel.jLabel1.text_1=HxD Editor Path: +ExternalViewerGlobalSettingsPanel.HxDPath.text=C:/Program Files/HxD/HxD.exe +ExternalViewerGlobalSettingsPanel.editRuleButton.text_1=Edit Rule +ExternalViewerGlobalSettingsPanel.deleteRuleButton.text_1=Delete Rule +ExternalViewerGlobalSettingsPanel.externalViewerTitleLabel.text_1=Set aplication viewer to use for files with specific mime types/extensions: +ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title1_1=Application +ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title0_1=Mime type/Extension diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index 8d855b7aa0..ddc6c8f43b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -32,13 +32,12 @@ import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.text.BadLocationException; import javax.swing.text.Utilities; -import org.openide.modules.InstalledFileLocator; import org.openide.nodes.Node; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; -import org.sleuthkit.autopsy.coreutils.ExecUtil; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.DataConversion; import org.sleuthkit.datamodel.Content; @@ -356,22 +355,33 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont private void launchHxDButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_launchHxDButtonActionPerformed try { + File HdXExecutable = new File(UserPreferences.getHdXEditorPath()); + if(!HdXExecutable.exists() || !HdXExecutable.canExecute()) { + JOptionPane.showMessageDialog(null, "Unable to launch HxD Editor. " + + "Please set-up the HdX install location in Tools -> " + + "Options -> External Viewer"); + return; + } + String tempDirectory = Case.getCurrentCaseThrows().getTempDirectory(); File dataSourceInTempDirectory = Paths.get(tempDirectory, dataSource.getId() + dataSource.getName()).toFile(); ContentUtils.writeToFile(dataSource, dataSourceInTempDirectory); - String HdXExecutableToFind = Paths.get("HxD", "HxD64.exe").toString(); - File HdXExecutable = InstalledFileLocator.getDefault().locate(HdXExecutableToFind, DataContentViewerHex.class.getPackage().getName(), false); - if (null == HdXExecutable) { - throw new IOException(String.format("Could not find HdXExecutable at %s", HdXExecutableToFind)); + try { + ProcessBuilder launchHdXExecutable = new ProcessBuilder(); + launchHdXExecutable.command(String.format("\"%s\" \"%s\"", + HdXExecutable.getAbsolutePath(), + dataSourceInTempDirectory.getAbsolutePath())); + launchHdXExecutable.start(); + } catch (IOException ex) { + JOptionPane.showMessageDialog(null, "Unable to launch HxD Editor. " + + "Please set-up the HdX install location in Tools -> " + + "Options -> External Viewer"); + dataSourceInTempDirectory.delete(); } - - ProcessBuilder launchHdXExecutable = new ProcessBuilder(); - launchHdXExecutable.command(String.format("%s \"%s\"", HdXExecutable.getAbsolutePath(), dataSourceInTempDirectory.getAbsolutePath())); - ExecUtil.execute(launchHdXExecutable); } catch (NoCurrentCaseException | IOException ex) { - logger.log(Level.SEVERE, "Unable to launch HxD Editor", ex); - //TODO - Make pop-up appear saying there were problems attempting to launch editor + logger.log(Level.SEVERE, "Unable to copy file into temp directory", ex); + //Should we add a pop-up for this? } }//GEN-LAST:event_launchHxDButtonActionPerformed @@ -546,6 +556,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont goToPageLabel.setVisible(isVisible); goToOffsetTextField.setVisible(isVisible); goToOffsetLabel.setVisible(isVisible); + launchHxDButton.setVisible(isVisible); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties index 5857deb2b9..22ad15405a 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties @@ -124,12 +124,9 @@ ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title2_1=Title 3 ExternalViewerGlobalSettingsPanel.newRuleButton1.text=New Rule ExternalViewerGlobalSettingsPanel.editRuleButton.text=Edit Rule ExternalViewerGlobalSettingsPanel.deleteRuleButton.text=Delete Rule -ExternalViewerGlobalSettingsPanel.externalViewerTitleLabel.text=Set aplication viewer to use for files with specific mime types/extensions: +ExternalViewerGlobalSettingsPanel.externalViewerTitleLabel.text=Add your custom rules for external viewers: ExternalViewerGlobalSettingsPanel.newRuleButton.text=New Rule -ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title1=Application -ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title0=Mime type/Extension -ExternalViewerGlobalSettingsPanel.jLabel1.text=HxD Editor Path: ExternalViewerGlobalSettingsPanel.jButton2.text=jButton2 -ExternalViewerGlobalSettingsPanel.jLabel2.text=Set launchable content viewer extensions +ExternalViewerGlobalSettingsPanel.jLabel1.text=HxD Editor Path: ExternalViewerGlobalSettingsPanel.browseHxDDirectory.text=Browse -ExternalViewerGlobalSettingsPanel.HxDPath.text=C:/Program Files/HxD/HxD.exe +ExternalViewerGlobalSettingsPanel.jLabel2.text=Add content viewer extensions: diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form index b3d33e0b2b..5ca99ba3bf 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form @@ -282,9 +282,6 @@ - - - diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index 1903729ec5..4df9b933fd 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.directorytree; +import java.awt.Color; import java.io.File; import java.util.ArrayList; import javax.swing.JFileChooser; @@ -27,7 +28,7 @@ import javax.swing.table.AbstractTableModel; import org.openide.util.NbBundle; import org.netbeans.spi.options.OptionsPanelController; import org.sleuthkit.autopsy.casemodule.GeneralFilter; -import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.core.UserPreferences; /** * An options panel for the user to create, edit, and delete associations for @@ -39,8 +40,6 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme private RulesTableModel rulesTableModel; private java.util.List rules; - private static final String MODULE_NAME = ExternalViewerGlobalSettingsPanel.class.getName(); - private static final String HXD_PATH_NAME = "HxDExecutablePath"; /** * Creates new form ExternalViewerGlobalSettingsPanel @@ -171,7 +170,6 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme ); HxDPath.setEditable(false); - HxDPath.setText(org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.HxDPath.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jLabel1.text")); // NOI18N @@ -245,25 +243,6 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme ); }// //GEN-END:initComponents - private void browseHxDDirectoryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseHxDDirectoryActionPerformed - JFileChooser fileWindow = new JFileChooser(); - fileWindow.setFileSelectionMode(JFileChooser.FILES_ONLY); - GeneralFilter exeFilter = new GeneralFilter(GeneralFilter.EXECUTABLE_EXTS, GeneralFilter.EXECUTABLE_DESC); - File HxDPathFile = new File(HxDPath.getText()); - if(HxDPathFile.exists() && HxDPathFile.canExecute()) { - fileWindow.setCurrentDirectory(new File(HxDPath.getText())); - } - fileWindow.setDragEnabled(false); - fileWindow.setFileFilter(exeFilter); - fileWindow.setMultiSelectionEnabled(false); - int returnVal = fileWindow.showSaveDialog(this); - if(returnVal == JFileChooser.APPROVE_OPTION) { - File HxDExecutable = fileWindow.getSelectedFile(); - HxDPath.setText(HxDExecutable.getAbsolutePath()); - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - } - }//GEN-LAST:event_browseHxDDirectoryActionPerformed - private void newRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newRuleButtonActionPerformed AddExternalViewerRuleDialog dialog = new AddExternalViewerRuleDialog(); AddExternalViewerRuleDialog.BUTTON_PRESSED result = dialog.getResult(); @@ -321,18 +300,43 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_deleteRuleButtonActionPerformed + private void browseHxDDirectoryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseHxDDirectoryActionPerformed + JFileChooser fileWindow = new JFileChooser(); + fileWindow.setFileSelectionMode(JFileChooser.FILES_ONLY); + GeneralFilter exeFilter = new GeneralFilter(GeneralFilter.EXECUTABLE_EXTS, GeneralFilter.EXECUTABLE_DESC); + File HxDPathFile = new File(HxDPath.getText()); + if(HxDPathFile.exists() && HxDPathFile.canExecute()) { + fileWindow.setCurrentDirectory(new File(HxDPath.getText())); + } + fileWindow.setDragEnabled(false); + fileWindow.setFileFilter(exeFilter); + fileWindow.setMultiSelectionEnabled(false); + int returnVal = fileWindow.showSaveDialog(this); + if(returnVal == JFileChooser.APPROVE_OPTION) { + File HxDExecutable = fileWindow.getSelectedFile(); + HxDPath.setForeground(Color.BLACK); + HxDPath.setText(HxDExecutable.getAbsolutePath()); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + } + }//GEN-LAST:event_browseHxDDirectoryActionPerformed + @Override public void store() { ExternalViewerRulesManager.getInstance().setUserRules(rules); - ModuleSettings.setConfigSetting(MODULE_NAME, HXD_PATH_NAME, HxDPath.getText()); + UserPreferences.setHdXEditorPath(HxDPath.getText()); } @Override public void load() { rules = ExternalViewerRulesManager.getInstance().getUserRules(); - if(ModuleSettings.settingExists(MODULE_NAME, HXD_PATH_NAME)) { - HxDPath.setText(ModuleSettings.getConfigSetting(MODULE_NAME, HXD_PATH_NAME)); - } + String editorPath = UserPreferences.getHdXEditorPath(); + File HdXExecutable = new File(editorPath); + if(HdXExecutable.exists() || HdXExecutable.canExecute()) { + HxDPath.setText(editorPath); + } else { + HxDPath.setForeground(Color.RED); + HxDPath.setText(editorPath); + } rulesTableModel.fireTableDataChanged(); checkButtons(); } From ca54e9b570ad0ad93275e5fab283702c163a64cf Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 2 Jan 2019 13:50:25 -0500 Subject: [PATCH 05/30] Added 100% code coverage to new Table model class and 75% to existing panel --- .../ExternalViewerGlobalSettingsPanel.java | 126 +++------- ...xternalViewerGlobalSettingsTableModel.java | 85 +++++++ ...ExternalViewerGlobalSettingsPanelTest.java | 70 ++++++ ...nalViewerGlobalSettingsTableModelTest.java | 225 ++++++++++++++++++ 4 files changed, 412 insertions(+), 94 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModel.java create mode 100755 Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java create mode 100755 Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModelTest.java diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index 4df9b933fd..bd369ab86b 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -19,12 +19,12 @@ package org.sleuthkit.autopsy.directorytree; import java.awt.Color; +import java.awt.event.ActionListener; import java.io.File; -import java.util.ArrayList; +import java.util.List; import javax.swing.JFileChooser; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import javax.swing.JOptionPane; -import javax.swing.table.AbstractTableModel; import org.openide.util.NbBundle; import org.netbeans.spi.options.OptionsPanelController; import org.sleuthkit.autopsy.casemodule.GeneralFilter; @@ -38,28 +38,34 @@ import org.sleuthkit.autopsy.core.UserPreferences; @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel implements OptionsPanel { - private RulesTableModel rulesTableModel; - private java.util.List rules; + private ExternalViewerGlobalSettingsTableModel tableModel; /** * Creates new form ExternalViewerGlobalSettingsPanel */ public ExternalViewerGlobalSettingsPanel() { + this(new ExternalViewerGlobalSettingsTableModel(new String[] {"Mime type/Extension", "Application"})); + } + + public ExternalViewerGlobalSettingsPanel(ExternalViewerGlobalSettingsTableModel tableModel) { initComponents(); - customizeComponents(); + this.tableModel = tableModel; + customizeComponents(tableModel); } /** * Initializes field variables. Adds a listener to the list of rules. */ - private void customizeComponents() { - rules = new ArrayList<>(); - rulesTableModel = new RulesTableModel(new String[] { - "Mime type/Extension", "Application"}); - jTable1.setModel(rulesTableModel); + private void customizeComponents(ExternalViewerGlobalSettingsTableModel tableModel) { + jTable1.setModel(tableModel); jTable1.setAutoCreateRowSorter(true); } - + + public void deleteRuleButtonClick(int selectedIndex) { + jTable1.getSelectionModel().setSelectionInterval(selectedIndex, selectedIndex); + deleteRuleButton.getListeners(ActionListener.class)[0].actionPerformed(null); + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -109,10 +115,6 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme jScrollPane4.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(204, 204, 204))); jScrollPane4.setViewportView(jTable1); - if (jTable1.getColumnModel().getColumnCount() > 0) { - jTable1.getColumnModel().getColumn(0).setHeaderValue(org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title0")); // NOI18N - jTable1.getColumnModel().getColumn(1).setHeaderValue(org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title1")); // NOI18N - } org.openide.awt.Mnemonics.setLocalizedText(externalViewerTitleLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.externalViewerTitleLabel.text")); // NOI18N @@ -249,18 +251,14 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme if (result == AddExternalViewerRuleDialog.BUTTON_PRESSED.OK) { ExternalViewerRule newRule = dialog.getRule(); // Only allow one association for each MIME type or extension. - if (rules.contains(newRule)) { + if (tableModel.containsRule(newRule)) { JOptionPane.showMessageDialog(this, NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.JOptionPane.ruleAlreadyExists.message"), NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.JOptionPane.ruleAlreadyExists.title"), JOptionPane.ERROR_MESSAGE); } else { - rules.add(newRule); - rulesTableModel.fireTableDataChanged(); - int index = rules.indexOf(newRule); - jTable1.getSelectionModel().clearSelection(); - jTable1.getSelectionModel().setSelectionInterval(index, index); - checkButtons(); + tableModel.addRule(newRule); + enableButtons(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } } @@ -268,35 +266,28 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme private void editRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editRuleButtonActionPerformed int selectedIndex = jTable1.convertRowIndexToModel(jTable1.getSelectedRow()); - ExternalViewerRule selectedRule = rulesTableModel.getRuleAt(selectedIndex); + ExternalViewerRule selectedRule = tableModel.getRuleAt(selectedIndex); AddExternalViewerRuleDialog dialog = new AddExternalViewerRuleDialog(selectedRule); AddExternalViewerRuleDialog.BUTTON_PRESSED result = dialog.getResult(); if (result == AddExternalViewerRuleDialog.BUTTON_PRESSED.OK) { ExternalViewerRule newRule = dialog.getRule(); // Only allow one association for each MIME type or extension. - if (rules.contains(newRule)) { + if (tableModel.containsRule(newRule)) { JOptionPane.showMessageDialog(this, NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.JOptionPane.ruleAlreadyExists.message"), NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.JOptionPane.ruleAlreadyExists.title"), JOptionPane.ERROR_MESSAGE); } else { - rules.set(selectedIndex, dialog.getRule()); - rulesTableModel.fireTableDataChanged(); - jTable1.getSelectionModel().clearSelection(); - int tableIndex = jTable1.convertRowIndexToView(selectedIndex); - jTable1.getSelectionModel().setSelectionInterval(tableIndex, tableIndex); - checkButtons(); + tableModel.setRule(selectedIndex, dialog.getRule()); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } } }//GEN-LAST:event_editRuleButtonActionPerformed private void deleteRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteRuleButtonActionPerformed - ExternalViewerRule selectedRule = rulesTableModel.getRuleAt(jTable1.convertRowIndexToModel(jTable1.getSelectedRow())); - rules.remove(selectedRule); - rulesTableModel.fireTableDataChanged(); + tableModel.removeRule(jTable1.convertRowIndexToModel(jTable1.getSelectedRow())); jTable1.getSelectionModel().clearSelection(); - checkButtons(); + enableButtons(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_deleteRuleButtonActionPerformed @@ -322,13 +313,14 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme @Override public void store() { - ExternalViewerRulesManager.getInstance().setUserRules(rules); + ExternalViewerRulesManager.getInstance().setUserRules(tableModel.getRules()); UserPreferences.setHdXEditorPath(HxDPath.getText()); } @Override public void load() { - rules = ExternalViewerRulesManager.getInstance().getUserRules(); + List rules = ExternalViewerRulesManager.getInstance().getUserRules(); + rules.forEach((rule) -> tableModel.addRule(rule)); String editorPath = UserPreferences.getHdXEditorPath(); File HdXExecutable = new File(editorPath); if(HdXExecutable.exists() || HdXExecutable.canExecute()) { @@ -336,72 +328,18 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme } else { HxDPath.setForeground(Color.RED); HxDPath.setText(editorPath); - } - rulesTableModel.fireTableDataChanged(); - checkButtons(); + } + enableButtons(); } /** * Enable edit and delete buttons if there is a rule selected. */ - private void checkButtons() { + boolean enableButtons() { boolean ruleIsSelected = jTable1.getRowCount() > 0; editRuleButton.setEnabled(ruleIsSelected); deleteRuleButton.setEnabled(ruleIsSelected); - } - - /** - * - */ - private class RulesTableModel extends AbstractTableModel { - private final String[] columnNames; - - public RulesTableModel(String[] columnNames) { - this.columnNames = columnNames; - } - - public void addRule(ExternalViewerRule rule) { - rules.add(rule); - fireTableRowsInserted(rules.size()-1, rules.size()-1); - } - - @Override - public int getRowCount() { - return rules.size(); - } - - @Override - public String getColumnName(int columnIndex) { - return columnNames[columnIndex]; - } - - @Override - public Class getColumnClass(int columnIndex) { - return String.class; - } - - @Override - public int getColumnCount() { - return columnNames.length; - } - - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - if(columnIndex == 0) { - return rules.get(rowIndex).getName(); - } else { - return rules.get(rowIndex).getExePath(); - } - } - - public ExternalViewerRule getRuleAt(int rowIndex) { - return rules.get(rowIndex); - } - - @Override - public boolean isCellEditable(int rowIndex, int colIndex) { - return false; - } + return ruleIsSelected; } // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModel.java new file mode 100755 index 0000000000..31689a98f8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModel.java @@ -0,0 +1,85 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.directorytree; + +import java.util.ArrayList; +import java.util.List; +import javax.swing.table.AbstractTableModel; + +/** +* + */ +class ExternalViewerGlobalSettingsTableModel extends AbstractTableModel { + + private final ArrayList rules; + private final String[] columnNames; + + public ExternalViewerGlobalSettingsTableModel(String[] columnNames) { + this.columnNames = columnNames; + this.rules = new ArrayList<>(); + } + + public void addRule(ExternalViewerRule rule) { + rules.add(rule); + fireTableRowsInserted(getRowCount() - 1, getRowCount() - 1); + } + + @Override + public int getRowCount() { + return rules.size(); + } + + @Override + public String getColumnName(int columnIndex) { + return columnNames[columnIndex]; + } + + @Override + public Class getColumnClass(int columnIndex) { + return String.class; + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + if (columnIndex == 0) { + return rules.get(rowIndex).getName(); + } else { + return rules.get(rowIndex).getExePath(); + } + } + + public ExternalViewerRule getRuleAt(int rowIndex) { + return rules.get(rowIndex); + } + + public void setRule(int rowIndex, ExternalViewerRule rule) { + rules.set(rowIndex, rule); + fireTableDataChanged(); + } + + public void removeRule(int rowIndex) { + rules.remove(rowIndex); + fireTableDataChanged(); + } + + @Override + public boolean isCellEditable(int rowIndex, int colIndex) { + return false; + } + + public List getRules() { + return rules; + } + + public boolean containsRule(ExternalViewerRule rule) { + return rules.contains(rule); + } +} diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java new file mode 100755 index 0000000000..51ca1aa287 --- /dev/null +++ b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java @@ -0,0 +1,70 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.directorytree; + +import junit.framework.Assert; +import org.junit.Test; +import org.sleuthkit.autopsy.directorytree.ExternalViewerRule.RuleType; + +public class ExternalViewerGlobalSettingsPanelTest { + + static final String[] testColumnNames = {"A", "B"}; + + public ExternalViewerGlobalSettingsPanelTest(){ + } + + @Test + public void testEnableButtons() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + ExternalViewerGlobalSettingsPanel panel = new ExternalViewerGlobalSettingsPanel(testModel); + Assert.assertFalse(panel.enableButtons()); + + testModel.addRule(new ExternalViewerRule("image/png", "fake.exe", RuleType.MIME)); + + Assert.assertTrue(panel.enableButtons()); + } + + @Test + public void testDisableButtons() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + ExternalViewerGlobalSettingsPanel panel = new ExternalViewerGlobalSettingsPanel(testModel); + + testModel.addRule(new ExternalViewerRule("image/png", "fake.exe", RuleType.MIME)); + Assert.assertTrue(panel.enableButtons()); + + testModel.removeRule(0); + Assert.assertFalse(panel.enableButtons()); + } + + @Test + public void testDeleteRuleButtonClick() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + ExternalViewerGlobalSettingsPanel testPanel = new ExternalViewerGlobalSettingsPanel(testModel); + Assert.assertFalse(testPanel.enableButtons()); + + testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); + Assert.assertTrue(testPanel.enableButtons()); + Assert.assertEquals(1, testModel.getRowCount()); + + testPanel.deleteRuleButtonClick(0); + + Assert.assertFalse(testPanel.enableButtons()); + Assert.assertEquals(0, testModel.getRowCount()); + } +} diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModelTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModelTest.java new file mode 100755 index 0000000000..f59e400910 --- /dev/null +++ b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModelTest.java @@ -0,0 +1,225 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.directorytree; + +import java.util.List; +import junit.framework.Assert; +import org.junit.Test; +import org.sleuthkit.autopsy.directorytree.ExternalViewerRule.RuleType; + +/** + * + * @author dsmyda + */ +public class ExternalViewerGlobalSettingsTableModelTest { + + static final String[] testColumnNames = {"A", "B"}; + + public ExternalViewerGlobalSettingsTableModelTest() { + } + + /** + * Test of addRule method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testAddRule() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + testModel.addRule(new ExternalViewerRule("image/png", "test.exe", RuleType.MIME)); + + List rules = testModel.getRules(); + Assert.assertEquals(1, rules.size()); + + ExternalViewerRule rule = rules.get(0); + Assert.assertEquals("image/png", rule.getName()); + Assert.assertEquals("test.exe", rule.getExePath()); + Assert.assertEquals(RuleType.MIME, rule.getRuleType()); + } + + /** + * Test of getRowCount method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testGetRowCount() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + Assert.assertEquals(0, testModel.getRowCount()); + + testModel.addRule(new ExternalViewerRule("image/png", "test.exe", RuleType.MIME)); + testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); + testModel.addRule(new ExternalViewerRule(".wav", "video.exe", RuleType.EXT)); + + Assert.assertEquals(3, testModel.getRowCount()); + } + + /** + * Test of getColumnName method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testGetColumnName() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + Assert.assertEquals("A", testModel.getColumnName(0)); + Assert.assertEquals("B", testModel.getColumnName(1)); + } + + @Test(expected = ArrayIndexOutOfBoundsException.class) + public void testColumnNameOutOfBounds() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + testModel.getColumnName(2); + } + + /** + * Test of getColumnClass method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testGetColumnClass() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + Assert.assertEquals(String.class, testModel.getColumnClass(0)); + } + + /** + * Test of getColumnCount method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testGetColumnCount() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + Assert.assertEquals(2, testModel.getColumnCount()); + ExternalViewerGlobalSettingsTableModel testModelTwo = new ExternalViewerGlobalSettingsTableModel(new String[] {"A", "B", "C", "D", "E"}); + Assert.assertEquals(5, testModelTwo.getColumnCount()); + } + + /** + * Test of getValueAt method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testGetValueAt() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + testModel.addRule(new ExternalViewerRule("image/png", "test.exe", RuleType.MIME)); + testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); + testModel.addRule(new ExternalViewerRule(".wav", "video.exe", RuleType.EXT)); + + Assert.assertEquals(".txt", testModel.getValueAt(1,0)); + Assert.assertEquals("notepad.exe", testModel.getValueAt(1,1)); + Assert.assertEquals("image/png", testModel.getValueAt(0,0)); + Assert.assertEquals("test.exe", testModel.getValueAt(0,1)); + } + + /** + * Test of getRuleAt method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testGetRuleAt() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + testModel.addRule(new ExternalViewerRule("image/png", "test.exe", RuleType.MIME)); + testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); + testModel.addRule(new ExternalViewerRule(".wav", "video.exe", RuleType.EXT)); + + ExternalViewerRule rule = testModel.getRuleAt(1); + Assert.assertEquals(".txt", rule.getName()); + Assert.assertEquals("notepad.exe", rule.getExePath()); + Assert.assertEquals(RuleType.EXT, rule.getRuleType()); + + ExternalViewerRule ruleTwo = testModel.getRuleAt(0); + Assert.assertEquals("image/png", ruleTwo.getName()); + Assert.assertEquals("test.exe", ruleTwo.getExePath()); + Assert.assertEquals(RuleType.MIME, ruleTwo.getRuleType()); + } + + /** + * Test of setRule method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testSetRule() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + testModel.addRule(new ExternalViewerRule("image/png", "test.exe", RuleType.MIME)); + testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); + testModel.addRule(new ExternalViewerRule(".wav", "video.exe", RuleType.EXT)); + + testModel.setRule(0, new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); + ExternalViewerRule rule = testModel.getRuleAt(1); + Assert.assertEquals(".txt", rule.getName()); + Assert.assertEquals("notepad.exe", rule.getExePath()); + Assert.assertEquals(RuleType.EXT, rule.getRuleType()); + + testModel.setRule(2, new ExternalViewerRule("image/png", "test.exe", RuleType.MIME)); + ExternalViewerRule ruleTwo = testModel.getRuleAt(2); + Assert.assertEquals("image/png", ruleTwo.getName()); + Assert.assertEquals("test.exe", ruleTwo.getExePath()); + Assert.assertEquals(RuleType.MIME, ruleTwo.getRuleType()); + } + + /** + * Test of removeRule method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testRemoveRule() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + ExternalViewerRule rule = new ExternalViewerRule("image/png", "test.ext", RuleType.MIME); + testModel.addRule(rule); + Assert.assertEquals(1, testModel.getRules().size()); + + testModel.removeRule(0); + Assert.assertEquals(0, testModel.getRules().size()); + Assert.assertFalse(testModel.containsRule(rule)); + } + + /** + * Test of isCellEditable method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testIsCellEditable() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + Assert.assertFalse(testModel.isCellEditable(0, 0)); + } + + /** + * Test of getRules method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testGetRules() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + Assert.assertNotNull(testModel.getRules()); + Assert.assertEquals(0, testModel.getRules().size()); + + testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); + Assert.assertEquals(1, testModel.getRules().size()); + ExternalViewerRule rule = testModel.getRuleAt(0); + Assert.assertEquals(".txt", rule.getName()); + Assert.assertEquals("notepad.exe", rule.getExePath()); + Assert.assertEquals(RuleType.EXT, rule.getRuleType()); + } + + /** + * Test of containsRule method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testContainsRule() { + ExternalViewerRule rule = new ExternalViewerRule("image/png", "test.exe", RuleType.MIME); + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + testModel.addRule(rule); + Assert.assertTrue(testModel.containsRule(rule)); + } + + @Test + public void testNotContains() { + ExternalViewerRule rule = new ExternalViewerRule("image/png", "test.exe", RuleType.MIME); + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + testModel.addRule(rule); + Assert.assertFalse(testModel.containsRule(new ExternalViewerRule("not", "a rule", RuleType.EXT))); + Assert.assertFalse(testModel.containsRule(null)); + } +} \ No newline at end of file From 8afeb39a0039b5cb7b8303d2c85fd184bdaa5a4e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 2 Jan 2019 14:30:11 -0500 Subject: [PATCH 06/30] Added some comments to Table Model and Panel --- .../autopsy/directorytree/Bundle.properties | 4 +- .../ExternalViewerGlobalSettingsPanel.form | 22 ++--- .../ExternalViewerGlobalSettingsPanel.java | 63 +++++++----- ...xternalViewerGlobalSettingsTableModel.java | 97 +++++++++++++++++-- ...ExternalViewerGlobalSettingsPanelTest.java | 3 + ...nalViewerGlobalSettingsTableModelTest.java | 30 +----- 6 files changed, 148 insertions(+), 71 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties index 22ad15405a..c1939adf6c 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties @@ -127,6 +127,6 @@ ExternalViewerGlobalSettingsPanel.deleteRuleButton.text=Delete Rule ExternalViewerGlobalSettingsPanel.externalViewerTitleLabel.text=Add your custom rules for external viewers: ExternalViewerGlobalSettingsPanel.newRuleButton.text=New Rule ExternalViewerGlobalSettingsPanel.jButton2.text=jButton2 -ExternalViewerGlobalSettingsPanel.jLabel1.text=HxD Editor Path: ExternalViewerGlobalSettingsPanel.browseHxDDirectory.text=Browse -ExternalViewerGlobalSettingsPanel.jLabel2.text=Add content viewer extensions: +ExternalViewerGlobalSettingsPanel.HxDLabel.text=HxD Editor Path: +ExternalViewerGlobalSettingsPanel.ContentViewerExtensionLabel.text=Add content viewer extensions: diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form index 5ca99ba3bf..7a6fc16278 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form @@ -167,20 +167,20 @@ - + - <ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + <ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="ExternalViewerGlobalSettingsPanel.ExternalViewerRulesTable.columnModel.title0" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - <ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + <ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="ExternalViewerGlobalSettingsPanel.ExternalViewerRulesTable.columnModel.title1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> @@ -250,12 +250,12 @@ - + - + @@ -266,11 +266,11 @@ - + - + @@ -284,17 +284,17 @@ - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index bd369ab86b..47f58a520e 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.directorytree; import java.awt.Color; import java.awt.event.ActionListener; import java.io.File; +import java.util.ArrayList; import java.util.List; import javax.swing.JFileChooser; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; @@ -40,13 +41,13 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme private ExternalViewerGlobalSettingsTableModel tableModel; - /** - * Creates new form ExternalViewerGlobalSettingsPanel - */ public ExternalViewerGlobalSettingsPanel() { this(new ExternalViewerGlobalSettingsTableModel(new String[] {"Mime type/Extension", "Application"})); } + /** + * Creates new form ExternalViewerGlobalSettingsPanel + */ public ExternalViewerGlobalSettingsPanel(ExternalViewerGlobalSettingsTableModel tableModel) { initComponents(); this.tableModel = tableModel; @@ -57,12 +58,17 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme * Initializes field variables. Adds a listener to the list of rules. */ private void customizeComponents(ExternalViewerGlobalSettingsTableModel tableModel) { - jTable1.setModel(tableModel); - jTable1.setAutoCreateRowSorter(true); + ExternalViewerRulesTable.setModel(tableModel); + ExternalViewerRulesTable.setAutoCreateRowSorter(true); } + /** + * Simulate the delete rule button click action. + * + * @param selectedIndex Index to delete in JTable + */ public void deleteRuleButtonClick(int selectedIndex) { - jTable1.getSelectionModel().setSelectionInterval(selectedIndex, selectedIndex); + ExternalViewerRulesTable.getSelectionModel().setSelectionInterval(selectedIndex, selectedIndex); deleteRuleButton.getListeners(ActionListener.class)[0].actionPerformed(null); } @@ -81,14 +87,14 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme jPanel2 = new javax.swing.JPanel(); newRuleButton = new javax.swing.JButton(); jScrollPane4 = new javax.swing.JScrollPane(); - jTable1 = new javax.swing.JTable(); + ExternalViewerRulesTable = new javax.swing.JTable(); externalViewerTitleLabel = new javax.swing.JLabel(); deleteRuleButton = new javax.swing.JButton(); editRuleButton = new javax.swing.JButton(); jPanel3 = new javax.swing.JPanel(); HxDPath = new javax.swing.JTextField(); - jLabel1 = new javax.swing.JLabel(); - jLabel2 = new javax.swing.JLabel(); + HxDLabel = new javax.swing.JLabel(); + ContentViewerExtensionLabel = new javax.swing.JLabel(); browseHxDDirectory = new javax.swing.JButton(); newRuleButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N @@ -114,7 +120,11 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme jScrollPane4.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(204, 204, 204))); - jScrollPane4.setViewportView(jTable1); + jScrollPane4.setViewportView(ExternalViewerRulesTable); + if (ExternalViewerRulesTable.getColumnModel().getColumnCount() > 0) { + ExternalViewerRulesTable.getColumnModel().getColumn(0).setHeaderValue(org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.ExternalViewerRulesTable.columnModel.title0")); // NOI18N + ExternalViewerRulesTable.getColumnModel().getColumn(1).setHeaderValue(org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.ExternalViewerRulesTable.columnModel.title1")); // NOI18N + } org.openide.awt.Mnemonics.setLocalizedText(externalViewerTitleLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.externalViewerTitleLabel.text")); // NOI18N @@ -173,9 +183,9 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme HxDPath.setEditable(false); - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jLabel1.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(HxDLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.HxDLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.jLabel2.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(ContentViewerExtensionLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.ContentViewerExtensionLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(browseHxDDirectory, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.browseHxDDirectory.text")); // NOI18N browseHxDDirectory.addActionListener(new java.awt.event.ActionListener() { @@ -189,11 +199,11 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme jPanel3Layout.setHorizontalGroup( jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel3Layout.createSequentialGroup() - .addComponent(jLabel2) + .addComponent(ContentViewerExtensionLabel) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGroup(jPanel3Layout.createSequentialGroup() .addGap(21, 21, 21) - .addComponent(jLabel1) + .addComponent(HxDLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(HxDPath, javax.swing.GroupLayout.DEFAULT_SIZE, 441, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -202,11 +212,11 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme jPanel3Layout.setVerticalGroup( jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel3Layout.createSequentialGroup() - .addComponent(jLabel2) + .addComponent(ContentViewerExtensionLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(HxDPath, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(HxDLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(browseHxDDirectory)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); @@ -265,7 +275,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme }//GEN-LAST:event_newRuleButtonActionPerformed private void editRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editRuleButtonActionPerformed - int selectedIndex = jTable1.convertRowIndexToModel(jTable1.getSelectedRow()); + int selectedIndex = ExternalViewerRulesTable.convertRowIndexToModel(ExternalViewerRulesTable.getSelectedRow()); ExternalViewerRule selectedRule = tableModel.getRuleAt(selectedIndex); AddExternalViewerRuleDialog dialog = new AddExternalViewerRuleDialog(selectedRule); AddExternalViewerRuleDialog.BUTTON_PRESSED result = dialog.getResult(); @@ -285,8 +295,8 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme }//GEN-LAST:event_editRuleButtonActionPerformed private void deleteRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteRuleButtonActionPerformed - tableModel.removeRule(jTable1.convertRowIndexToModel(jTable1.getSelectedRow())); - jTable1.getSelectionModel().clearSelection(); + tableModel.removeRule(ExternalViewerRulesTable.convertRowIndexToModel(ExternalViewerRulesTable.getSelectedRow())); + ExternalViewerRulesTable.getSelectionModel().clearSelection(); enableButtons(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_deleteRuleButtonActionPerformed @@ -313,7 +323,12 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme @Override public void store() { - ExternalViewerRulesManager.getInstance().setUserRules(tableModel.getRules()); + //Dump rules from table model into a list to be stored by the rules manager. + List rules = new ArrayList<>(); + for(int i = 0; i < tableModel.getRowCount(); i++) { + rules.add(tableModel.getRuleAt(i)); + } + ExternalViewerRulesManager.getInstance().setUserRules(rules); UserPreferences.setHdXEditorPath(HxDPath.getText()); } @@ -336,26 +351,26 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme * Enable edit and delete buttons if there is a rule selected. */ boolean enableButtons() { - boolean ruleIsSelected = jTable1.getRowCount() > 0; + boolean ruleIsSelected = ExternalViewerRulesTable.getRowCount() > 0; editRuleButton.setEnabled(ruleIsSelected); deleteRuleButton.setEnabled(ruleIsSelected); return ruleIsSelected; } // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel ContentViewerExtensionLabel; + private javax.swing.JTable ExternalViewerRulesTable; + private javax.swing.JLabel HxDLabel; private javax.swing.JTextField HxDPath; private javax.swing.JButton browseHxDDirectory; private javax.swing.JButton deleteRuleButton; private javax.swing.JButton editRuleButton; private javax.swing.JLabel externalViewerTitleLabel; private javax.swing.JButton jButton2; - private javax.swing.JLabel jLabel1; - private javax.swing.JLabel jLabel2; private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel2; private javax.swing.JPanel jPanel3; private javax.swing.JScrollPane jScrollPane4; - private javax.swing.JTable jTable1; private javax.swing.JButton newRuleButton; private javax.swing.JButton newRuleButton1; // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModel.java index 31689a98f8..424c12d4d3 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModel.java @@ -1,16 +1,29 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.directorytree; import java.util.ArrayList; -import java.util.List; import javax.swing.table.AbstractTableModel; /** -* + * Model that stores the External Viewer rules for Mime types and extensions. + * Located at Tools -> Options -> External Viewer */ class ExternalViewerGlobalSettingsTableModel extends AbstractTableModel { @@ -22,31 +35,68 @@ class ExternalViewerGlobalSettingsTableModel extends AbstractTableModel { this.rules = new ArrayList<>(); } + /** + * Stores a new external viewer rule. + * + * @param rule User-inputted rule + */ public void addRule(ExternalViewerRule rule) { rules.add(rule); fireTableRowsInserted(getRowCount() - 1, getRowCount() - 1); } + /** + * Returns the number of rules stored in this model. + * + * @return Integer denoting row count in table model + */ @Override public int getRowCount() { return rules.size(); } + /** + * Returns the column name at the given index. + * + * @param columnIndex + * + * @return Column name + */ @Override public String getColumnName(int columnIndex) { return columnNames[columnIndex]; } + /** + * Retrieves column class type. As for now, this is only type string. + * + * @param columnIndex + * + * @return String.class + */ @Override public Class getColumnClass(int columnIndex) { return String.class; } + /** + * Retrieves the number of columns in this table model. + * + * @return Integer denoting column count + */ @Override public int getColumnCount() { return columnNames.length; } + /** + * Retrieves value at a given row and column in the table. + * + * @param rowIndex Desired row index + * @param columnIndex Desired column index + * + * @return A generic pointer to the underlying data. + */ @Override public Object getValueAt(int rowIndex, int columnIndex) { if (columnIndex == 0) { @@ -56,29 +106,58 @@ class ExternalViewerGlobalSettingsTableModel extends AbstractTableModel { } } + /** + * Gets an entire rule instance from a given index. + * + * @param rowIndex Desired row + * + * @return User-inputted rule at the desired rowIndex + */ public ExternalViewerRule getRuleAt(int rowIndex) { return rules.get(rowIndex); } + /** + * Replaces an existing rule in the table. + * + * @param rowIndex Desired row index + * @param rule New rule to overwrite the old. + */ public void setRule(int rowIndex, ExternalViewerRule rule) { rules.set(rowIndex, rule); fireTableDataChanged(); } + /** + * Removes the rule from the table model. + * + * @param rowIndex Desired row index to delete + */ public void removeRule(int rowIndex) { rules.remove(rowIndex); fireTableDataChanged(); } + /** + * This table model is not editable. + * + * @param rowIndex + * @param colIndex + * + * @return False + */ @Override public boolean isCellEditable(int rowIndex, int colIndex) { return false; } - public List getRules() { - return rules; - } - + /** + * Tests containment of a given rule in the table model. + * + * @param rule Rule in question + * + * @return + */ public boolean containsRule(ExternalViewerRule rule) { return rules.contains(rule); } diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java index 51ca1aa287..07c09f89e1 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java @@ -22,6 +22,9 @@ import junit.framework.Assert; import org.junit.Test; import org.sleuthkit.autopsy.directorytree.ExternalViewerRule.RuleType; +/** + * 72% code coverage of ExternalViewerGlobalSettingsPanel + */ public class ExternalViewerGlobalSettingsPanelTest { static final String[] testColumnNames = {"A", "B"}; diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModelTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModelTest.java index f59e400910..341143e0b5 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModelTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModelTest.java @@ -18,14 +18,12 @@ */ package org.sleuthkit.autopsy.directorytree; -import java.util.List; import junit.framework.Assert; import org.junit.Test; import org.sleuthkit.autopsy.directorytree.ExternalViewerRule.RuleType; /** - * - * @author dsmyda + * 100% code coverage of ExternalViewerGlobalSettingsTableModel */ public class ExternalViewerGlobalSettingsTableModelTest { @@ -42,10 +40,9 @@ public class ExternalViewerGlobalSettingsTableModelTest { ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); testModel.addRule(new ExternalViewerRule("image/png", "test.exe", RuleType.MIME)); - List rules = testModel.getRules(); - Assert.assertEquals(1, rules.size()); + Assert.assertEquals(1, testModel.getRowCount()); - ExternalViewerRule rule = rules.get(0); + ExternalViewerRule rule = testModel.getRuleAt(0); Assert.assertEquals("image/png", rule.getName()); Assert.assertEquals("test.exe", rule.getExePath()); Assert.assertEquals(RuleType.MIME, rule.getRuleType()); @@ -170,10 +167,10 @@ public class ExternalViewerGlobalSettingsTableModelTest { ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); ExternalViewerRule rule = new ExternalViewerRule("image/png", "test.ext", RuleType.MIME); testModel.addRule(rule); - Assert.assertEquals(1, testModel.getRules().size()); + Assert.assertEquals(1, testModel.getRowCount()); testModel.removeRule(0); - Assert.assertEquals(0, testModel.getRules().size()); + Assert.assertEquals(0, testModel.getRowCount()); Assert.assertFalse(testModel.containsRule(rule)); } @@ -186,23 +183,6 @@ public class ExternalViewerGlobalSettingsTableModelTest { Assert.assertFalse(testModel.isCellEditable(0, 0)); } - /** - * Test of getRules method, of class ExternalViewerGlobalSettingsTableModel. - */ - @Test - public void testGetRules() { - ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); - Assert.assertNotNull(testModel.getRules()); - Assert.assertEquals(0, testModel.getRules().size()); - - testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); - Assert.assertEquals(1, testModel.getRules().size()); - ExternalViewerRule rule = testModel.getRuleAt(0); - Assert.assertEquals(".txt", rule.getName()); - Assert.assertEquals("notepad.exe", rule.getExePath()); - Assert.assertEquals(RuleType.EXT, rule.getRuleType()); - } - /** * Test of containsRule method, of class ExternalViewerGlobalSettingsTableModel. */ From bb80bfde1542fd9366908da92a6678acebc12ddd Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 2 Jan 2019 14:42:56 -0500 Subject: [PATCH 07/30] Commented new methods in UserPreferences --- Core/src/org/sleuthkit/autopsy/core/UserPreferences.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index bf4d5dc3c1..f96cd05969 100644 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -475,16 +475,19 @@ public final class UserPreferences { } /** + * Set the HdX path. * - * @param executablePath + * @param executablePath User-inputted path to HxD executable */ public static void setHdXEditorPath(String executablePath) { preferences.put(HDX_EDITOR_PATH, executablePath); } /** + * Retrieves the HdXEditor path set by the User. If not found, the default + * will be the default install location of HxD. * - * @return + * @return Path to HdX */ public static String getHdXEditorPath() { return preferences.get(HDX_EDITOR_PATH, Paths.get("C:", "Program Files", "HxD", "HxD.exe").toString()); From 9e3d5bbe1baad4379459b50ce1c9805f1b859730 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 2 Jan 2019 14:59:52 -0500 Subject: [PATCH 08/30] Disabled feature for non-windows machines --- .../autopsy/corecomponents/DataContentViewerHex.form | 9 ++++++--- .../autopsy/corecomponents/DataContentViewerHex.java | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form index 8c9b3c36a2..0b59085cb8 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form @@ -45,7 +45,7 @@ - + @@ -54,7 +54,7 @@ - + @@ -122,7 +122,7 @@ - + @@ -303,6 +303,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index ddc6c8f43b..d8368d75fc 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -25,6 +25,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.util.logging.Level; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; @@ -231,7 +232,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(launchHxDButton) - .addContainerGap(39, Short.MAX_VALUE)) + .addContainerGap(146, Short.MAX_VALUE)) ); hexViewerPanelLayout.setVerticalGroup( hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -254,13 +255,15 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont .addGap(0, 0, 0)) ); + launchHxDButton.setEnabled(PlatformUtil.isWindowsOS()); + jScrollPane2.setViewportView(hexViewerPanel); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 686, Short.MAX_VALUE) + .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 827, Short.MAX_VALUE) .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( @@ -268,7 +271,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 267, Short.MAX_VALUE)) + .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 239, Short.MAX_VALUE)) ); }// //GEN-END:initComponents From 19adadf467a3c73e69fec58c3844d4e0c944cdb0 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 2 Jan 2019 15:01:42 -0500 Subject: [PATCH 09/30] Disabled browse button for choose exe path for non-windows machine --- .../directorytree/ExternalViewerGlobalSettingsPanel.form | 3 +++ .../directorytree/ExternalViewerGlobalSettingsPanel.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form index 7a6fc16278..fde8a99209 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form @@ -307,6 +307,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index 47f58a520e..cb30626845 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -30,6 +30,7 @@ import org.openide.util.NbBundle; import org.netbeans.spi.options.OptionsPanelController; import org.sleuthkit.autopsy.casemodule.GeneralFilter; import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; /** * An options panel for the user to create, edit, and delete associations for @@ -221,6 +222,8 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); + browseHxDDirectory.setEnabled(PlatformUtil.isWindowsOS()); + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( From 364bef5c3ce58716766b42bf64b806f0968118ca Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 2 Jan 2019 15:33:38 -0500 Subject: [PATCH 10/30] 4568 bring in FileTypeUtils from timeline-event-mgr branch and move to datamodel.utils --- .../datamodel/utils/FileTypeUtils.java | 207 ++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/utils/FileTypeUtils.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/utils/FileTypeUtils.java b/Core/src/org/sleuthkit/autopsy/datamodel/utils/FileTypeUtils.java new file mode 100644 index 0000000000..74545fcc40 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/utils/FileTypeUtils.java @@ -0,0 +1,207 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018-2019 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.datamodel.utils; + +import com.google.common.collect.ImmutableSet; +import static java.util.Arrays.asList; +import java.util.Collection; +import java.util.Collections; +import javax.imageio.ImageIO; +import static org.apache.commons.collections4.ListUtils.removeAll; +import org.openide.util.NbBundle; + +/** + * Utilities for dealing with file/mime-types + */ +public final class FileTypeUtils { + + private static final ImmutableSet IMAGE_MIME_TYPES + = new ImmutableSet.Builder() + .addAll(removeAll(asList(ImageIO.getReaderMIMETypes()), + asList("application/octet-stream"))) //this claims to be supported, but is not really an image. + .add("image/bmp", //NON-NLS + "image/gif", //NON-NLS + "image/jpeg", //NON-NLS + "image/png", //NON-NLS + "image/tiff", //NON-NLS + "image/vnd.adobe.photoshop", //NON-NLS + "image/x-raw-nikon", //NON-NLS + "image/x-ms-bmp", //NON-NLS + "image/x-icon", //NON-NLS + "image/webp", //NON-NLS + "image/vnd.microsoft.icon", //NON-NLS + "image/x-rgb", //NON-NLS + "image/x-ms-bmp", //NON-NLS + "image/x-xbitmap", //NON-NLS + "image/x-portable-graymap", //NON-NLS + "image/x-portable-bitmap" //NON-NLS + ).build(); + private static final ImmutableSet AUDIO_MIME_TYPES + = new ImmutableSet.Builder() + .add("audio/midi", //NON-NLS + "audio/mpeg", //NON-NLS + "audio/webm", //NON-NLS + "audio/ogg", //NON-NLS + "audio/wav", //NON-NLS + "audio/vnd.wave", //NON-NLS + "audio/x-ms-wma"//NON-NLS + ).build(); + private static final ImmutableSet VIDEO_MIME_TYPES + = new ImmutableSet.Builder() + .add("video/webm", //NON-NLS + "video/3gpp", //NON-NLS + "video/3gpp2", //NON-NLS + "video/ogg", //NON-NLS + "video/mpeg", //NON-NLS + "video/mp4", //NON-NLS + "video/quicktime", //NON-NLS + "video/x-msvideo", //NON-NLS + "video/x-flv", //NON-NLS + "video/x-m4v", //NON-NLS + "video/x-ms-wmv"//NON-NLS + ).build(); + private static final ImmutableSet DOCUMENT_MIME_TYPES + = new ImmutableSet.Builder() + .add("text/plain", //NON-NLS + "text/css", //NON-NLS + "text/html", //NON-NLS + "text/csv", //NON-NLS + "text/xml", //NON-NLS + "text/x-log", //NON-NLS + "application/rtf", //NON-NLS + "application/pdf", //NON-NLS + "application/json", //NON-NLS + "application/javascript", //NON-NLS + "application/xml", //NON-NLS + "application/x-msoffice", //NON-NLS + "application/x-ooxml", //NON-NLS + "application/msword", //NON-NLS + "application/msword2", //NON-NLS + "application/vnd.wordperfect", //NON-NLS + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", //NON-NLS + "application/vnd.ms-powerpoint", //NON-NLS + "application/vnd.openxmlformats-officedocument.presentationml.presentation", //NON-NLS + "application/vnd.ms-excel", //NON-NLS + "application/vnd.ms-excel.sheet.4", //NON-NLS + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", //NON-NLS + "application/vnd.oasis.opendocument.presentation", //NON-NLS + "application/vnd.oasis.opendocument.spreadsheet", //NON-NLS + "application/vnd.oasis.opendocument.text" //NON-NLS + ).build(); + private static final ImmutableSet EXECUTABLE_MIME_TYPES + = new ImmutableSet.Builder() + .add("application/x-bat",//NON-NLS + "application/x-dosexec",//NON-NLS + "application/vnd.microsoft.portable-executable",//NON-NLS + "application/x-msdownload",//NON-NLS + "application/exe",//NON-NLS + "application/x-exe",//NON-NLS + "application/dos-exe",//NON-NLS + "vms/exe",//NON-NLS + "application/x-winexe",//NON-NLS + "application/msdos-windows",//NON-NLS + "application/x-msdos-program"//NON-NLS + ).build(); + private static final ImmutableSet MULTI_MEDIA_MIME_TYPES + = new ImmutableSet.Builder() + .addAll(IMAGE_MIME_TYPES) + .addAll(AUDIO_MIME_TYPES) + .addAll(VIDEO_MIME_TYPES) + .build(); + private static final ImmutableSet VISUAL_MEDIA_MIME_TYPES + = new ImmutableSet.Builder() + .addAll(IMAGE_MIME_TYPES) + .addAll(VIDEO_MIME_TYPES) + .add("application/vnd.ms-asf", //NON-NLS + "application/vnd.rn-realmedia", //NON-NLS + "application/x-shockwave-flash" //NON-NLS + ).build(); + + private FileTypeUtils() { + + } + + /** + * Enum of categories/groups of file types. + */ + @NbBundle.Messages({ + "FileTypeCategory.Audio.displayName=Audio", + "FileTypeCategory.Video.displayName=Video", + "FileTypeCategory.Image.displayName=Image", + "FileTypeCategory.Media.displayName=Media", + "FileTypeCategory.Visual.displayName=Visual", + "FileTypeCategory.Documents.displayName=Documents", + "FileTypeCategory.Executables.displayName=Executables"}) + public enum FileTypeCategory { + + IMAGE(Bundle.FileTypeCategory_Image_displayName(), + IMAGE_MIME_TYPES, + Collections.emptyList()), + VIDEO(Bundle.FileTypeCategory_Video_displayName(), + VIDEO_MIME_TYPES, + Collections.emptyList()), + AUDIO(Bundle.FileTypeCategory_Audio_displayName(), + AUDIO_MIME_TYPES, + Collections.emptyList()), + /** + * Images, Videos, flash Animations, etc + */ + VISUAL(Bundle.FileTypeCategory_Media_displayName(), + VISUAL_MEDIA_MIME_TYPES, + Collections.emptyList()), + /** + * VISUAL plus AUDIO. + */ + MEDIA(Bundle.FileTypeCategory_Media_displayName(), + MULTI_MEDIA_MIME_TYPES, + Collections.emptyList()), + EXECUTABLE(Bundle.FileTypeCategory_Executables_displayName(), + EXECUTABLE_MIME_TYPES, + Collections.emptyList()), + /** + * (Plain) Text and "Office" documents. + */ + DOCUMENTS(Bundle.FileTypeCategory_Documents_displayName(), + DOCUMENT_MIME_TYPES, + Collections.emptyList()); + + private final String displayName; + private final ImmutableSet mediaTypes; + private final ImmutableSet extensions; + + private FileTypeCategory(String displayName, Collection mediaTypes, Collection extensions) { + this.displayName = displayName; + this.mediaTypes = ImmutableSet.copyOf(mediaTypes); + this.extensions = ImmutableSet.copyOf(extensions); + } + + public String getDisplayName() { + return displayName; + } + + public ImmutableSet getMediaTypes() { + return mediaTypes; + + } + + public ImmutableSet getExtensions() { + throw new UnsupportedOperationException("This method is not implemented yet."); //just to be explicit. + } + } +} From e3265d4b28e66b24b4e3a8de62f0c38eae7c0f4e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 3 Jan 2019 08:53:57 -0500 Subject: [PATCH 11/30] Codacy suggestions, all but one because I don't agree with it. --- ...xternalViewerGlobalSettingsTableModel.java | 8 ++- ...ExternalViewerGlobalSettingsPanelTest.java | 4 ++ ...nalViewerGlobalSettingsTableModelTest.java | 58 +++++++++++-------- 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModel.java index 424c12d4d3..5662e0cd84 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModel.java @@ -19,6 +19,8 @@ package org.sleuthkit.autopsy.directorytree; import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import javax.swing.table.AbstractTableModel; /** @@ -27,11 +29,11 @@ import javax.swing.table.AbstractTableModel; */ class ExternalViewerGlobalSettingsTableModel extends AbstractTableModel { - private final ArrayList rules; + private final List rules; private final String[] columnNames; - public ExternalViewerGlobalSettingsTableModel(String[] columnNames) { - this.columnNames = columnNames; + public ExternalViewerGlobalSettingsTableModel(String... columnNames) { + this.columnNames = Arrays.copyOf(columnNames, columnNames.length); this.rules = new ArrayList<>(); } diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java index 07c09f89e1..e24884e3b7 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java @@ -29,7 +29,11 @@ public class ExternalViewerGlobalSettingsPanelTest { static final String[] testColumnNames = {"A", "B"}; + /** + * Default constructor for JUnit + */ public ExternalViewerGlobalSettingsPanelTest(){ + //Codacy complains if there is no comment here } @Test diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModelTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModelTest.java index 341143e0b5..72118c7e3e 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModelTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModelTest.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.directorytree; import junit.framework.Assert; +import org.junit.Before; import org.junit.Test; import org.sleuthkit.autopsy.directorytree.ExternalViewerRule.RuleType; @@ -28,8 +29,22 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerRule.RuleType; public class ExternalViewerGlobalSettingsTableModelTest { static final String[] testColumnNames = {"A", "B"}; + private ExternalViewerRule pngMime; + private ExternalViewerRule txtExt; + private ExternalViewerRule wavExt; + /** + * Initialize JUnit test + */ public ExternalViewerGlobalSettingsTableModelTest() { + //Empty constructor + } + + @Before + public void setUp() { + pngMime = new ExternalViewerRule("image/png", "test.exe", RuleType.MIME); + txtExt = new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT); + wavExt = new ExternalViewerRule(".wav", "video.exe", RuleType.EXT); } /** @@ -38,7 +53,7 @@ public class ExternalViewerGlobalSettingsTableModelTest { @Test public void testAddRule() { ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); - testModel.addRule(new ExternalViewerRule("image/png", "test.exe", RuleType.MIME)); + testModel.addRule(pngMime); Assert.assertEquals(1, testModel.getRowCount()); @@ -56,9 +71,9 @@ public class ExternalViewerGlobalSettingsTableModelTest { ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); Assert.assertEquals(0, testModel.getRowCount()); - testModel.addRule(new ExternalViewerRule("image/png", "test.exe", RuleType.MIME)); - testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); - testModel.addRule(new ExternalViewerRule(".wav", "video.exe", RuleType.EXT)); + testModel.addRule(pngMime); + testModel.addRule(txtExt); + testModel.addRule(wavExt); Assert.assertEquals(3, testModel.getRowCount()); } @@ -105,9 +120,9 @@ public class ExternalViewerGlobalSettingsTableModelTest { @Test public void testGetValueAt() { ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); - testModel.addRule(new ExternalViewerRule("image/png", "test.exe", RuleType.MIME)); - testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); - testModel.addRule(new ExternalViewerRule(".wav", "video.exe", RuleType.EXT)); + testModel.addRule(pngMime); + testModel.addRule(txtExt); + testModel.addRule(wavExt); Assert.assertEquals(".txt", testModel.getValueAt(1,0)); Assert.assertEquals("notepad.exe", testModel.getValueAt(1,1)); @@ -121,9 +136,9 @@ public class ExternalViewerGlobalSettingsTableModelTest { @Test public void testGetRuleAt() { ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); - testModel.addRule(new ExternalViewerRule("image/png", "test.exe", RuleType.MIME)); - testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); - testModel.addRule(new ExternalViewerRule(".wav", "video.exe", RuleType.EXT)); + testModel.addRule(pngMime); + testModel.addRule(txtExt); + testModel.addRule(wavExt); ExternalViewerRule rule = testModel.getRuleAt(1); Assert.assertEquals(".txt", rule.getName()); @@ -142,17 +157,17 @@ public class ExternalViewerGlobalSettingsTableModelTest { @Test public void testSetRule() { ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); - testModel.addRule(new ExternalViewerRule("image/png", "test.exe", RuleType.MIME)); - testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); - testModel.addRule(new ExternalViewerRule(".wav", "video.exe", RuleType.EXT)); + testModel.addRule(pngMime); + testModel.addRule(txtExt); + testModel.addRule(wavExt); - testModel.setRule(0, new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); + testModel.setRule(0, txtExt); ExternalViewerRule rule = testModel.getRuleAt(1); Assert.assertEquals(".txt", rule.getName()); Assert.assertEquals("notepad.exe", rule.getExePath()); Assert.assertEquals(RuleType.EXT, rule.getRuleType()); - testModel.setRule(2, new ExternalViewerRule("image/png", "test.exe", RuleType.MIME)); + testModel.setRule(2, pngMime); ExternalViewerRule ruleTwo = testModel.getRuleAt(2); Assert.assertEquals("image/png", ruleTwo.getName()); Assert.assertEquals("test.exe", ruleTwo.getExePath()); @@ -165,13 +180,12 @@ public class ExternalViewerGlobalSettingsTableModelTest { @Test public void testRemoveRule() { ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); - ExternalViewerRule rule = new ExternalViewerRule("image/png", "test.ext", RuleType.MIME); - testModel.addRule(rule); + testModel.addRule(pngMime); Assert.assertEquals(1, testModel.getRowCount()); testModel.removeRule(0); Assert.assertEquals(0, testModel.getRowCount()); - Assert.assertFalse(testModel.containsRule(rule)); + Assert.assertFalse(testModel.containsRule(pngMime)); } /** @@ -188,17 +202,15 @@ public class ExternalViewerGlobalSettingsTableModelTest { */ @Test public void testContainsRule() { - ExternalViewerRule rule = new ExternalViewerRule("image/png", "test.exe", RuleType.MIME); ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); - testModel.addRule(rule); - Assert.assertTrue(testModel.containsRule(rule)); + testModel.addRule(pngMime); + Assert.assertTrue(testModel.containsRule(pngMime)); } @Test public void testNotContains() { - ExternalViewerRule rule = new ExternalViewerRule("image/png", "test.exe", RuleType.MIME); ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); - testModel.addRule(rule); + testModel.addRule(pngMime); Assert.assertFalse(testModel.containsRule(new ExternalViewerRule("not", "a rule", RuleType.EXT))); Assert.assertFalse(testModel.containsRule(null)); } From 1d143a315b586db4f79b5f9f22252928f8aa6425 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 3 Jan 2019 16:02:19 -0500 Subject: [PATCH 12/30] 4568 add initial Data source summary dialog and action --- .../sleuthkit/autopsy/casemodule/Case.java | 3 + .../casemodule/CasePropertiesAction.java | 2 +- .../casemodule/IngestJobInfoPanel.java | 3 +- .../datasourceSummary/Bundle.properties | 9 + .../DataSourceSummaryAction.java | 72 ++++ .../DataSourceSummaryPanel.form | 224 +++++++++++ .../DataSourceSummaryPanel.java | 375 ++++++++++++++++++ Core/src/org/sleuthkit/autopsy/core/layer.xml | 5 + 8 files changed, 691 insertions(+), 2 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index c580309cba..46e9dad2bc 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -67,6 +67,7 @@ import org.sleuthkit.autopsy.appservices.AutopsyService; import org.sleuthkit.autopsy.appservices.AutopsyService.CaseContext; import static org.sleuthkit.autopsy.casemodule.Bundle.*; import org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException; +import org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction; import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent; import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceFailedEvent; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent; @@ -1165,6 +1166,7 @@ public class Case { CallableSystemAction.get(AddImageAction.class).setEnabled(true); CallableSystemAction.get(CaseCloseAction.class).setEnabled(true); CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true); + CallableSystemAction.get(DataSourceSummaryAction.class).setEnabled(true); CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true); CallableSystemAction.get(OpenTimelineAction.class).setEnabled(true); CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(true); @@ -1218,6 +1220,7 @@ public class Case { CallableSystemAction.get(AddImageAction.class).setEnabled(false); CallableSystemAction.get(CaseCloseAction.class).setEnabled(false); CallableSystemAction.get(CasePropertiesAction.class).setEnabled(false); + CallableSystemAction.get(DataSourceSummaryAction.class).setEnabled(false); CallableSystemAction.get(CaseDeleteAction.class).setEnabled(false); CallableSystemAction.get(OpenTimelineAction.class).setEnabled(false); CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(false); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java index 6a9d1d2f2f..2a70c91483 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesAction.java @@ -55,7 +55,7 @@ final class CasePropertiesAction extends CallableSystemAction { casePropertiesDialog = new JDialog(mainWindow, title, true); CaseInformationPanel caseInformationPanel = new CaseInformationPanel(); caseInformationPanel.addCloseButtonAction((ActionEvent e) -> { - casePropertiesDialog.setVisible(false); + casePropertiesDialog.dispose(); }); casePropertiesDialog.add(caseInformationPanel); casePropertiesDialog.setResizable(true); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java index 940f6a9cd5..e274245edd 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java @@ -61,7 +61,8 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { private void customizeComponents() { refresh(); this.ingestJobTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { - this.ingestModuleTableModel = new IngestModuleTableModel(this.ingestJobs.get(ingestJobTable.getSelectedRow())); + IngestJobInfo currJob = (ingestJobTable.getSelectedRow() < 0 ? null : this.ingestJobs.get(ingestJobTable.getSelectedRow())); + this.ingestModuleTableModel = new IngestModuleTableModel(currJob); this.ingestModuleTable.setModel(this.ingestModuleTableModel); }); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties new file mode 100644 index 0000000000..2c7eea054f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties @@ -0,0 +1,9 @@ +CTL_DataSourceSummaryAction=Data Source Summary +DataSourceSummaryPanel.fileCountsLabel.text=Files (based on mimetype) +DataSourceSummaryPanel.opperatingSystemLabel.text=OS: +DataSourceSummaryPanel.opperatingSystemValueLabel.text= +DataSourceSummaryPanel.ingestHistoryDetailsLabel.text=View Ingest History for more details +DataSourceSummaryPanel.ingestHistoryButton.text=Ingest History +DataSourceSummaryPanel.openButton.text=Goto Datasource +DataSourceSummaryPanel.ingestJobsLabel.text=Ingest Jobs +DataSourceSummaryPanel.closeButton.text=Close diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java new file mode 100644 index 0000000000..f33dada13c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java @@ -0,0 +1,72 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.casemodule.datasourceSummary; + +import java.awt.Frame; +import java.awt.event.ActionEvent; +import javax.swing.Action; +import javax.swing.JDialog; +import javax.swing.SwingUtilities; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; +import org.openide.util.actions.CallableSystemAction; +import org.openide.windows.WindowManager; + +public class DataSourceSummaryAction extends CallableSystemAction { + + private static final long serialVersionUID = 1L; + private static JDialog dataSourceSummaryDialog; + + DataSourceSummaryAction() { + putValue(Action.NAME, NbBundle.getMessage(DataSourceSummaryAction.class, "CTL_DataSourceSummaryAction")); + this.setEnabled(false); + } + + @Messages({"DataSourceSummaryAction.window.title=Data Source Summary"}) + @Override + public void performAction() { + SwingUtilities.invokeLater(() -> { + String title = NbBundle.getMessage(this.getClass(), "DataSourceSummaryAction.window.title"); + Frame mainWindow = WindowManager.getDefault().getMainWindow(); + dataSourceSummaryDialog = new JDialog(mainWindow, title, true); + DataSourceSummaryPanel dataSourceSummaryPanel = new DataSourceSummaryPanel(); + dataSourceSummaryPanel.addCloseButtonAction((ActionEvent e) -> { + dataSourceSummaryDialog.dispose(); + }); + dataSourceSummaryDialog.add(dataSourceSummaryPanel); + dataSourceSummaryDialog.setResizable(true); + dataSourceSummaryDialog.pack(); + dataSourceSummaryDialog.setLocationRelativeTo(mainWindow); + dataSourceSummaryDialog.setVisible(true); + dataSourceSummaryDialog.toFront(); + }); + } + + @Override + public String getName() { + return NbBundle.getMessage(DataSourceSummaryAction.class, "CTL_DataSourceSummaryAction"); + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form new file mode 100644 index 0000000000..90d4aea1a1 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java new file mode 100644 index 0000000000..e09aec86e8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -0,0 +1,375 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.casemodule.datasourceSummary; + +import java.awt.event.ActionListener; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JOptionPane; +import javax.swing.event.ListSelectionEvent; +import javax.swing.table.AbstractTableModel; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.IngestJobInfo; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; + +public class DataSourceSummaryPanel extends javax.swing.JPanel { + + private final List allIngestJobs = new ArrayList<>(); + private List ingestJobs = new ArrayList<>(); + private DataSourceTableModel dataSourceTableModel = new DataSourceTableModel(); + private IngestJobTableModel ingestJobTableModel = new IngestJobTableModel(); + private final List dataSources = new ArrayList<>(); + private final DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + private static final Logger logger = Logger.getLogger(DataSourceSummaryPanel.class.getName()); + + /** + * Creates new form DataSourceSummary + */ + @Messages({"DataSourceSummaryPanel.getDataSources.error.text=Failed to get the list of datasources for the current case.", + "DataSourceSummaryPanel.getDataSources.error.title=Load Failure"}) + public DataSourceSummaryPanel() { + initComponents(); + ingestJobsTable.getTableHeader().setReorderingAllowed(false); + fileCountsTable.getTableHeader().setReorderingAllowed(false); + dataSourcesTable.getTableHeader().setReorderingAllowed(false); + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + allIngestJobs.addAll(skCase.getIngestJobs()); + dataSources.addAll(skCase.getDataSources()); + } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Failed to load ingest jobs.", ex); + JOptionPane.showMessageDialog(this, Bundle.DataSourceSummaryPanel_getDataSources_error_text(), Bundle.DataSourceSummaryPanel_getDataSources_error_title(), JOptionPane.ERROR_MESSAGE); + } + dataSourcesTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { + if (!e.getValueIsAdjusting()) { + updateIngestJobs(); + } + }); + } + + @Messages({"DataSourceSummaryPanel.loadIngestJob.error.text=Failed to load ingest jobs.", + "DataSourceSummaryPanel.loadIngestJob.error.title=Load Failure"}) + private void updateIngestJobs() { + Long selectedDataSourceId = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow()).getId()); + ingestJobs.clear(); + if (selectedDataSourceId != null) { + for (IngestJobInfo ingestJob : allIngestJobs) { + if (ingestJob.getObjectId() == selectedDataSourceId) { + ingestJobs.add(ingestJob); + } + } + } + ingestJobTableModel = new IngestJobTableModel(); + ingestJobsTable.setModel(ingestJobTableModel); + this.repaint(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jSeparator1 = new javax.swing.JSeparator(); + dataSourcesScrollPane = new javax.swing.JScrollPane(); + dataSourcesTable = new javax.swing.JTable(); + ingestJobsScrollPane = new javax.swing.JScrollPane(); + ingestJobsTable = new javax.swing.JTable(); + fileCountsScrollPane = new javax.swing.JScrollPane(); + fileCountsTable = new javax.swing.JTable(); + opperatingSystemLabel = new javax.swing.JLabel(); + opperatingSystemValueLabel = new javax.swing.JLabel(); + fileCountsLabel = new javax.swing.JLabel(); + ingestJobsLabel = new javax.swing.JLabel(); + ingestHistoryDetailsLabel = new javax.swing.JLabel(); + closeButton = new javax.swing.JButton(); + openButton = new javax.swing.JButton(); + ingestHistoryButton = new javax.swing.JButton(); + + dataSourcesTable.setModel(dataSourceTableModel); + dataSourcesScrollPane.setViewportView(dataSourcesTable); + + ingestJobsTable.setModel(ingestJobTableModel); + ingestJobsScrollPane.setViewportView(ingestJobsTable); + + fileCountsTable.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + {"Images", "0"}, + {"Videos", "0"}, + {"Audio", "0"}, + {"Documents", "0"}, + {"Executables", "0"} + }, + new String [] { + "File type", "Count" + } + )); + fileCountsScrollPane.setViewportView(fileCountsTable); + + org.openide.awt.Mnemonics.setLocalizedText(opperatingSystemLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.opperatingSystemLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(opperatingSystemValueLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.opperatingSystemValueLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(fileCountsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.fileCountsLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(ingestJobsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestJobsLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(ingestHistoryDetailsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestHistoryDetailsLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.closeButton.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(openButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.openButton.text")); // NOI18N + openButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + openButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(ingestHistoryButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestHistoryButton.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(openButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(closeButton)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(fileCountsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 140, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(opperatingSystemLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(ingestHistoryDetailsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ingestHistoryButton)) + .addComponent(ingestJobsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 474, Short.MAX_VALUE)))) + .addContainerGap()) + ); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {closeButton, ingestHistoryButton, openButton}); + + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(8, 8, 8) + .addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 102, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 5, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(fileCountsLabel) + .addComponent(ingestJobsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(opperatingSystemLabel) + .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(layout.createSequentialGroup() + .addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 105, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(ingestHistoryButton) + .addComponent(ingestHistoryDetailsLabel)) + .addGap(10, 10, 10))) + .addGap(0, 0, 0) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(closeButton) + .addComponent(openButton)) + .addContainerGap()) + ); + }// //GEN-END:initComponents + + /** + * Adds an action listener to the Close button of the panel. + * + * @param action + */ + void addCloseButtonAction(ActionListener action) { + this.closeButton.addActionListener(action); + } + + private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_openButtonActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton closeButton; + private javax.swing.JScrollPane dataSourcesScrollPane; + private javax.swing.JTable dataSourcesTable; + private javax.swing.JLabel fileCountsLabel; + private javax.swing.JScrollPane fileCountsScrollPane; + private javax.swing.JTable fileCountsTable; + private javax.swing.JButton ingestHistoryButton; + private javax.swing.JLabel ingestHistoryDetailsLabel; + private javax.swing.JLabel ingestJobsLabel; + private javax.swing.JScrollPane ingestJobsScrollPane; + private javax.swing.JTable ingestJobsTable; + private javax.swing.JSeparator jSeparator1; + private javax.swing.JButton openButton; + private javax.swing.JLabel opperatingSystemLabel; + private javax.swing.JLabel opperatingSystemValueLabel; + // End of variables declaration//GEN-END:variables + + @Messages({"DataSourceSummaryPanel.IngestJobTableModel.StartTime.header=Start Time", + "DataSourceSummaryPanel.IngestJobTableModel.EndTime.header=End Time", + "DataSourceSummaryPanel.IngestJobTableModel.IngestStatus.header=Ingest Status"}) + private class IngestJobTableModel extends AbstractTableModel { + + private final List columnHeaders = new ArrayList<>(); + + IngestJobTableModel() { + columnHeaders.add(Bundle.DataSourceSummaryPanel_IngestJobTableModel_StartTime_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_IngestJobTableModel_EndTime_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_IngestJobTableModel_IngestStatus_header()); + } + + @Override + public int getRowCount() { + return ingestJobs.size(); + } + + @Override + public int getColumnCount() { + return columnHeaders.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + IngestJobInfo currIngestJob = ingestJobs.get(rowIndex); + switch (columnIndex) { + case 0: + return datetimeFormat.format(currIngestJob.getStartDateTime()); + case 1: + Date endDate = currIngestJob.getEndDateTime(); + if (endDate.getTime() == 0) { + return "N/A"; + } + return datetimeFormat.format(currIngestJob.getEndDateTime()); + case 2: + return currIngestJob.getStatus().getDisplayName(); + default: + break; + } + return null; + } + + @Override + public String getColumnName(int column) { + return columnHeaders.get(column); + } + + } + + @Messages({"DataSourceSummaryPanel.DataSourceTableModel.dataSourceName.header=Data Source Name", + "DataSourceSummaryPanel.DataSourceTableModel.type.header=Type", + "DataSourceSummaryPanel.DataSourceTableModel.files.header=Files", + "DataSourceSummaryPanel.DataSourceTableModel.results.header=Results", + "DataSourceSummaryPanel.DataSourceTableModel.tags.header=Tags"}) + private class DataSourceTableModel extends AbstractTableModel { + + private final List columnHeaders = new ArrayList<>(); + + DataSourceTableModel() { + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_dataSourceName_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_type_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_files_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_results_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_tags_header()); + } + + @Override + public int getRowCount() { + return dataSources.size(); + } + + @Override + public int getColumnCount() { + return columnHeaders.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + DataSource currentDataSource = dataSources.get(rowIndex); + switch (columnIndex) { + case 0: + return currentDataSource.getName(); + case 1: + return ""; + case 2: { + return ""; +// try { +// return currentDataSource.getChildrenCount(); +// } catch (TskCoreException ex) { +// return "UNABLE TO GET DS CHILD SIZE"; +// } + } + case 3: { + return ""; +// try { +// return currentDataSource.getAllArtifactsCount(); +// } catch (TskCoreException ex) { +// return "UNABLE TO GET ARTIFACT COUNT"; +// } + } + case 4: + return ""; + default: + break; + } + return null; + } + + @Override + public String getColumnName(int column) { + return columnHeaders.get(column); + } + + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index 7fef77ee04..783aaf5b42 100644 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -48,6 +48,7 @@ + @@ -182,6 +183,10 @@ + + + + From 82bab1779564f8ebb8d9193e997b31cb3f74a9aa Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 3 Jan 2019 18:43:45 -0500 Subject: [PATCH 13/30] 4568 populate file/result/tag count columns for data sources --- .../datasourceSummary/Bundle.properties | 2 +- .../DataSourceSummaryPanel.form | 8 ++- .../DataSourceSummaryPanel.java | 61 +++++++++++++------ 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties index 2c7eea054f..982d7ee1ff 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties @@ -4,6 +4,6 @@ DataSourceSummaryPanel.opperatingSystemLabel.text=OS: DataSourceSummaryPanel.opperatingSystemValueLabel.text= DataSourceSummaryPanel.ingestHistoryDetailsLabel.text=View Ingest History for more details DataSourceSummaryPanel.ingestHistoryButton.text=Ingest History -DataSourceSummaryPanel.openButton.text=Goto Datasource +DataSourceSummaryPanel.openButton.text=Goto Data Source DataSourceSummaryPanel.ingestJobsLabel.text=Ingest Jobs DataSourceSummaryPanel.closeButton.text=Close diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form index 90d4aea1a1..cff9ef1929 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form @@ -1,6 +1,6 @@ -
+ @@ -110,6 +110,9 @@ + + + @@ -126,6 +129,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java index e09aec86e8..4c759befe3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -36,6 +36,7 @@ import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; public class DataSourceSummaryPanel extends javax.swing.JPanel { @@ -115,9 +116,11 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { ingestHistoryButton = new javax.swing.JButton(); dataSourcesTable.setModel(dataSourceTableModel); + dataSourcesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); dataSourcesScrollPane.setViewportView(dataSourcesTable); ingestJobsTable.setModel(ingestJobTableModel); + ingestJobsTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); ingestJobsScrollPane.setViewportView(ingestJobsTable); fileCountsTable.setModel(new javax.swing.table.DefaultTableModel( @@ -261,6 +264,8 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { "DataSourceSummaryPanel.IngestJobTableModel.IngestStatus.header=Ingest Status"}) private class IngestJobTableModel extends AbstractTableModel { + private static final long serialVersionUID = 1L; + private final List columnHeaders = new ArrayList<>(); IngestJobTableModel() { @@ -313,6 +318,8 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { "DataSourceSummaryPanel.DataSourceTableModel.tags.header=Tags"}) private class DataSourceTableModel extends AbstractTableModel { + private static final long serialVersionUID = 1L; + private final List columnHeaders = new ArrayList<>(); DataSourceTableModel() { @@ -341,30 +348,50 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { return currentDataSource.getName(); case 1: return ""; - case 2: { - return ""; -// try { -// return currentDataSource.getChildrenCount(); -// } catch (TskCoreException ex) { -// return "UNABLE TO GET DS CHILD SIZE"; -// } - } - case 3: { - return ""; -// try { -// return currentDataSource.getAllArtifactsCount(); -// } catch (TskCoreException ex) { -// return "UNABLE TO GET ARTIFACT COUNT"; -// } - } + case 2: + return getCountOfFiles(currentDataSource); + case 3: + return getCountOfArtifacts(currentDataSource); case 4: - return ""; + return getCountOfTags(currentDataSource); default: break; } return null; } + private long getCountOfFiles(DataSource currentDataSource) { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return skCase.countFilesWhere("data_source_obj_id=" + currentDataSource.getId() + + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() + + " AND name<>''"); + } catch (TskCoreException | NoCurrentCaseException ex) { + return 0; + } + } + + private long getCountOfArtifacts(DataSource currentDataSource) { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return skCase.getBlackboardArtifactsCountForDatasource(currentDataSource.getId()); + } catch (TskCoreException | NoCurrentCaseException ex) { + return 0; + } + } + + private long getCountOfTags(DataSource currentDataSource) { + long countOfTags = 0; + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + countOfTags = skCase.getBlackboardArtifactTagsCountForDataSource(currentDataSource.getId()); + countOfTags += skCase.getContentTagsCountForDataSource(currentDataSource.getId()); + } catch (TskCoreException | NoCurrentCaseException ex) { + } + return countOfTags; + } + @Override public String getColumnName(int column) { return columnHeaders.get(column); From 06d5c55fb2ade18c2cdf15413b28176637f74136 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 4 Jan 2019 10:57:13 -0500 Subject: [PATCH 14/30] 4568 add counts for file types to Data source summary --- .../DataSourceSummaryPanel.form | 19 +--- .../DataSourceSummaryPanel.java | 105 +++++++++++++++--- 2 files changed, 93 insertions(+), 31 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form index cff9ef1929..7c03337b7a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form @@ -145,23 +145,8 @@ - - - - - - - - - - - - - - - - -
+ +
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java index 4c759befe3..dea71e43f2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -24,6 +24,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; @@ -32,6 +33,7 @@ import javax.swing.table.AbstractTableModel; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.datamodel.utils.FileTypeUtils; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; import org.sleuthkit.datamodel.SleuthkitCase; @@ -44,6 +46,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private List ingestJobs = new ArrayList<>(); private DataSourceTableModel dataSourceTableModel = new DataSourceTableModel(); private IngestJobTableModel ingestJobTableModel = new IngestJobTableModel(); + private FilesTableModel filesTableModel = new FilesTableModel(); private final List dataSources = new ArrayList<>(); private final DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); private static final Logger logger = Logger.getLogger(DataSourceSummaryPanel.class.getName()); @@ -69,6 +72,9 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { dataSourcesTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { if (!e.getValueIsAdjusting()) { updateIngestJobs(); + filesTableModel = new FilesTableModel(); + fileCountsTable.setModel(filesTableModel); + this.repaint(); } }); } @@ -87,7 +93,6 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { } ingestJobTableModel = new IngestJobTableModel(); ingestJobsTable.setModel(ingestJobTableModel); - this.repaint(); } /** @@ -123,18 +128,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { ingestJobsTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); ingestJobsScrollPane.setViewportView(ingestJobsTable); - fileCountsTable.setModel(new javax.swing.table.DefaultTableModel( - new Object [][] { - {"Images", "0"}, - {"Videos", "0"}, - {"Audio", "0"}, - {"Documents", "0"}, - {"Executables", "0"} - }, - new String [] { - "File type", "Count" - } - )); + fileCountsTable.setModel(filesTableModel); fileCountsScrollPane.setViewportView(fileCountsTable); org.openide.awt.Mnemonics.setLocalizedText(opperatingSystemLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.opperatingSystemLabel.text")); // NOI18N @@ -311,6 +305,89 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { } + @Messages({"DataSourceSummaryPanel.FilesTableModel.type.header=File Type", + "DataSourceSummaryPanel.FilesTableModel.count.header=Count"}) + private class FilesTableModel extends AbstractTableModel { + + private static final long serialVersionUID = 1L; + + private final List columnHeaders = new ArrayList<>(); + + FilesTableModel() { + columnHeaders.add(Bundle.DataSourceSummaryPanel_FilesTableModel_type_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_FilesTableModel_count_header()); + } + + @Override + public int getRowCount() { + return 5; + } + + @Override + public int getColumnCount() { + return columnHeaders.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + if (columnIndex == 0) { + switch (rowIndex) { + case 0: + return "Images"; + case 1: + return "Videos"; + case 2: + return "Audio"; + case 3: + return "Documents"; + case 4: + return "Executables"; + default: + break; + } + } else if (columnIndex == 1) { + DataSource currentDataSource = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow())); + if (currentDataSource != null) { + switch (rowIndex) { + case 0: + return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.IMAGE.getMediaTypes()); + case 1: + return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.VIDEO.getMediaTypes()); + case 2: + return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.AUDIO.getMediaTypes()); + case 3: + return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.DOCUMENTS.getMediaTypes()); + case 4: + return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.EXECUTABLE.getMediaTypes()); + default: + break; + } + } + } + return null; + } + + private long getCountOfFiles(DataSource currentDataSource, Set setOfMimeTypes) { + try { + String inClause = String.join("', '", setOfMimeTypes); + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return skCase.countFilesWhere("data_source_obj_id=" + currentDataSource.getId() + + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() + + " AND mime_type IN ('" + inClause + "')" + + " AND name<>''"); + } catch (TskCoreException | NoCurrentCaseException ex) { + return 0; + } + } + + @Override + public String getColumnName(int column) { + return columnHeaders.get(column); + } + + } + @Messages({"DataSourceSummaryPanel.DataSourceTableModel.dataSourceName.header=Data Source Name", "DataSourceSummaryPanel.DataSourceTableModel.type.header=Type", "DataSourceSummaryPanel.DataSourceTableModel.files.header=Files", @@ -350,7 +427,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { return ""; case 2: return getCountOfFiles(currentDataSource); - case 3: + case 3: return getCountOfArtifacts(currentDataSource); case 4: return getCountOfTags(currentDataSource); From 2aa99083070fdc0f4c29039ee91a620ce4635a28 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 4 Jan 2019 13:39:55 -0500 Subject: [PATCH 15/30] 4568 make use of CaseDbAccessManager to eliminate need for datamodel changes --- .../DataSourceSummaryPanel.java | 99 ++++++++++++++++--- 1 file changed, 83 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java index dea71e43f2..40519ce6db 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -19,11 +19,16 @@ package org.sleuthkit.autopsy.casemodule.datasourceSummary; import java.awt.event.ActionListener; +import java.sql.ResultSet; +import java.sql.SQLException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -34,6 +39,8 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datamodel.utils.FileTypeUtils; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.CaseDbAccessManager.CaseDbAccessQueryCallback; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; import org.sleuthkit.datamodel.SleuthkitCase; @@ -398,6 +405,9 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; private final List columnHeaders = new ArrayList<>(); + private final Map fileCountsMap; + private final Map artifactCountsMap; + private final Map tagCountsMap; DataSourceTableModel() { columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_dataSourceName_header()); @@ -405,6 +415,10 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_files_header()); columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_results_header()); columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_tags_header()); + fileCountsMap = getCountsOfFiles(); + artifactCountsMap = getCountsOfArtifacts(); + tagCountsMap = getCountsOfTags(); + } @Override @@ -420,53 +434,79 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { @Override public Object getValueAt(int rowIndex, int columnIndex) { DataSource currentDataSource = dataSources.get(rowIndex); + Long count; switch (columnIndex) { case 0: return currentDataSource.getName(); case 1: return ""; case 2: - return getCountOfFiles(currentDataSource); + count = fileCountsMap.get(currentDataSource.getId()); + return count == null ? 0 : count; case 3: - return getCountOfArtifacts(currentDataSource); + count = artifactCountsMap.get(currentDataSource.getId()); + return count == null ? 0 : count; case 4: - return getCountOfTags(currentDataSource); + count = tagCountsMap.get(currentDataSource.getId()); + return count == null ? 0 : count; default: break; } return null; } - private long getCountOfFiles(DataSource currentDataSource) { + private Map getCountsOfFiles() { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return skCase.countFilesWhere("data_source_obj_id=" + currentDataSource.getId() - + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + DataSourceCountsCallback callback = new DataSourceCountsCallback(); + String countFilesQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM tsk_files WHERE type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() - + " AND name<>''"); + + " AND name<>'' GROUP BY data_source_obj_id"; + skCase.getCaseDbAccessManager().select(countFilesQuery, callback); + return callback.getMapOfCounts(); } catch (TskCoreException | NoCurrentCaseException ex) { - return 0; + return Collections.emptyMap(); } } - private long getCountOfArtifacts(DataSource currentDataSource) { + private Map getCountsOfArtifacts() { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return skCase.getBlackboardArtifactsCountForDatasource(currentDataSource.getId()); + DataSourceCountsCallback callback = new DataSourceCountsCallback(); + String countArtifactsQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM blackboard_artifacts WHERE review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID() + + " GROUP BY data_source_obj_id"; + skCase.getCaseDbAccessManager().select(countArtifactsQuery, callback); + return callback.getMapOfCounts(); } catch (TskCoreException | NoCurrentCaseException ex) { - return 0; + return Collections.emptyMap(); } } - private long getCountOfTags(DataSource currentDataSource) { - long countOfTags = 0; + private Map getCountsOfTags() { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - countOfTags = skCase.getBlackboardArtifactTagsCountForDataSource(currentDataSource.getId()); - countOfTags += skCase.getContentTagsCountForDataSource(currentDataSource.getId()); + DataSourceCountsCallback fileCountcallback = new DataSourceCountsCallback(); + String countFileTagsQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM content_tags as content_tags, tsk_files as tsk_files" + + " WHERE content_tags.obj_id = tsk_files.obj_id" + + " GROUP BY data_source_obj_id"; + skCase.getCaseDbAccessManager().select(countFileTagsQuery, fileCountcallback); + Map tagCountMap = new HashMap<>(fileCountcallback.getMapOfCounts()); + DataSourceCountsCallback artifactCountcallback = new DataSourceCountsCallback(); + String countArtifactTagsQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts" + + " WHERE artifact_tags.artifact_id = arts.artifact_id" + + " GROUP BY data_source_obj_id"; + skCase.getCaseDbAccessManager().select(countArtifactTagsQuery, artifactCountcallback); + //combine the results from the count artifact tags query into the copy of the mapped results from the count file tags query + artifactCountcallback.getMapOfCounts().forEach((key, value) -> tagCountMap.merge(key, value, (value1, value2) -> value1 + value2)); + return tagCountMap; } catch (TskCoreException | NoCurrentCaseException ex) { + return Collections.emptyMap(); } - return countOfTags; + } @Override @@ -474,6 +514,33 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { return columnHeaders.get(column); } + private class DataSourceCountsCallback implements CaseDbAccessQueryCallback { + + Map dataSourceObjIdCounts = new HashMap<>(); + + @Override + public void process(ResultSet rs) { + try { + while (rs.next()) { + try { + long dataSourceObjectId = rs.getLong("data_source_obj_id"); + long count = rs.getLong("count"); + dataSourceObjIdCounts.put(dataSourceObjectId, count); + } catch (SQLException ex) { + System.out.println("UNABLE TO GET COUNT FOR DS " + ex.getMessage()); + } + } + } catch (SQLException ex) { + System.out.println("Failed to get next result" + ex.getMessage()); + } + } + + Map getMapOfCounts() { + return Collections.unmodifiableMap(dataSourceObjIdCounts); + } + + } + } } From 1d5815030d3c16e55c11f78fff79bcc0e1798830 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Sat, 5 Jan 2019 01:51:57 -0500 Subject: [PATCH 16/30] Tweaked SevenZipExtractor; uncommented test. --- .../SevenZipExtractor.java | 4 +- .../autopsy/ingest/EmbeddedFileTest.java | 90 +++++++++---------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 8b55988fa7..1fb60cf0cb 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2018 Basis Technology Corp. + * Copyright 2013-2019 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -258,7 +258,7 @@ class SevenZipExtractor { 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); + BlackboardArtifact artifact = rootArchive.getArchiveFile().newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); artifact.addAttributes(attributes); try { diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java index af9266b36f..25d691ddbc 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java @@ -90,51 +90,51 @@ public class EmbeddedFileTest extends NbTestCase { CaseUtils.closeCurrentCase(); } -// public void testEncryptionAndZipBomb() { -// try { -// List results = openCase.getSleuthkitCase().findAllFilesWhere("name LIKE '%%'"); -// final String zipBombSetName = "Possible Zip Bomb"; -// final String protectedName1 = "password_protected.zip"; -// final String protectedName2 = "level1_protected.zip"; -// final String protectedName3 = "42.zip"; -// final String depthZipBomb = "DepthTriggerZipBomb.zip"; -// final String ratioZipBomb = "RatioTriggerZipBomb.zip"; -// int zipBombs = 0; -// assertEquals("The number of files in the test image has changed", 2221, results.size()); -// int passwdProtectedZips = 0; -// for (AbstractFile file : results) { -// //.zip file has artifact TSK_ENCRYPTION_DETECTED -// if (file.getName().equalsIgnoreCase(protectedName1) || file.getName().equalsIgnoreCase(protectedName2) || file.getName().equalsIgnoreCase(protectedName3)) { -// ArrayList artifacts = file.getAllArtifacts(); -// assertEquals("Password protected zip file " + file.getName() + " has incorrect number of artifacts", 1, artifacts.size()); -// for (BlackboardArtifact artifact : artifacts) { -// assertEquals("Artifact for password protected zip file " + file.getName() + " has incorrect type ID", artifact.getArtifactTypeID(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID()); -// passwdProtectedZips++; -// } -// } else if (file.getName().equalsIgnoreCase(depthZipBomb) || file.getName().equalsIgnoreCase(ratioZipBomb)) { -// ArrayList artifacts = file.getAllArtifacts(); -// assertEquals("Zip bomb " + file.getName() + " has incorrect number of artifacts", 1, artifacts.size()); -// for (BlackboardArtifact artifact : artifacts) { -// assertEquals("Artifact for Zip bomb " + file.getName() + " has incorrect type ID", artifact.getArtifactTypeID(), BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()); -// BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); -// assertNotNull("No attribute found for artifact on zip bomb " + file.getName(), attribute); -// assertEquals("Interesting artifact on file, " + file.getName() + ", does not reflect it being a zip bomb", zipBombSetName, attribute.getDisplayString()); -// zipBombs++; -// } -// } else {//No other files have artifact defined -// assertEquals("Unexpected file, " + file.getName() + ", has artifacts", 0, file.getAllArtifacts().size()); -// } -// -// } -// //Make sure 3 password protected zip files have been tested: password_protected.zip, level1_protected.zip and 42.zip that we download for bomb testing. -// assertEquals("Unexpected number of artifacts reflecting password protected zip files found", 3, passwdProtectedZips); -// //Make sure 2 zip bomb files have been tested: DepthTriggerZipBomb.zip and RatioTriggerZipBomb.zip. -// assertEquals("Unexpected number of artifacts reflecting zip bombs found", 2, zipBombs); -// } catch (TskCoreException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail(ex.getMessage()); -// } -// } + public void testEncryptionAndZipBomb() { + try { + List results = openCase.getSleuthkitCase().findAllFilesWhere("name LIKE '%%'"); + final String zipBombSetName = "Possible Zip Bomb"; + final String protectedName1 = "password_protected.zip"; + final String protectedName2 = "level1_protected.zip"; + final String protectedName3 = "42.zip"; + final String depthZipBomb = "DepthTriggerZipBomb.zip"; + final String ratioZipBomb = "RatioTriggerZipBomb.zip"; + int zipBombs = 0; + assertEquals("The number of files in the test image has changed", 2221, results.size()); + int passwdProtectedZips = 0; + for (AbstractFile file : results) { + //.zip file has artifact TSK_ENCRYPTION_DETECTED + if (file.getName().equalsIgnoreCase(protectedName1) || file.getName().equalsIgnoreCase(protectedName2) || file.getName().equalsIgnoreCase(protectedName3)) { + ArrayList artifacts = file.getAllArtifacts(); + assertEquals("Password protected zip file " + file.getName() + " has incorrect number of artifacts", 1, artifacts.size()); + for (BlackboardArtifact artifact : artifacts) { + assertEquals("Artifact for password protected zip file " + file.getName() + " has incorrect type ID", artifact.getArtifactTypeID(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID()); + passwdProtectedZips++; + } + } else if (file.getName().equalsIgnoreCase(depthZipBomb) || file.getName().equalsIgnoreCase(ratioZipBomb)) { + ArrayList artifacts = file.getAllArtifacts(); + assertEquals("Zip bomb " + file.getName() + " has incorrect number of artifacts", 1, artifacts.size()); + for (BlackboardArtifact artifact : artifacts) { + assertEquals("Artifact for Zip bomb " + file.getName() + " has incorrect type ID", artifact.getArtifactTypeID(), BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()); + BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); + assertNotNull("No attribute found for artifact on zip bomb " + file.getName(), attribute); + assertEquals("Interesting artifact on file, " + file.getName() + ", does not reflect it being a zip bomb", zipBombSetName, attribute.getDisplayString()); + zipBombs++; + } + } else {//No other files have artifact defined + assertEquals("Unexpected file, " + file.getName() + ", has artifacts", 0, file.getAllArtifacts().size()); + } + + } + //Make sure 3 password protected zip files have been tested: password_protected.zip, level1_protected.zip and 42.zip that we download for bomb testing. + assertEquals("Unexpected number of artifacts reflecting password protected zip files found", 3, passwdProtectedZips); + //Make sure 2 zip bomb files have been tested: DepthTriggerZipBomb.zip and RatioTriggerZipBomb.zip. + assertEquals("Unexpected number of artifacts reflecting zip bombs found", 2, zipBombs); + } catch (TskCoreException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex.getMessage()); + } + } public void testBigFolder() { final int numOfFilesToTest = 1000; From 3dffd34d1837f7c87e2687c6d21a92c38f341405 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 7 Jan 2019 09:03:40 -0500 Subject: [PATCH 17/30] Review changes --- .../corecomponents/DataContentViewerHex.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index d8368d75fc..861076505c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -39,6 +39,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; +import static org.sleuthkit.autopsy.corecomponents.Bundle.*; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.DataConversion; import org.sleuthkit.datamodel.Content; @@ -356,13 +357,13 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont } }//GEN-LAST:event_goToOffsetTextFieldActionPerformed + @NbBundle.Messages({"DataContentViewerHex.launchError=Unable to launch HxD Editor. " + + "Please set-up the HdX install location in Tools -> Options -> External Viewer"}) private void launchHxDButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_launchHxDButtonActionPerformed try { File HdXExecutable = new File(UserPreferences.getHdXEditorPath()); if(!HdXExecutable.exists() || !HdXExecutable.canExecute()) { - JOptionPane.showMessageDialog(null, "Unable to launch HxD Editor. " - + "Please set-up the HdX install location in Tools -> " - + "Options -> External Viewer"); + JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError()); return; } @@ -377,14 +378,12 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont dataSourceInTempDirectory.getAbsolutePath())); launchHdXExecutable.start(); } catch (IOException ex) { - JOptionPane.showMessageDialog(null, "Unable to launch HxD Editor. " - + "Please set-up the HdX install location in Tools -> " - + "Options -> External Viewer"); + JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError()); dataSourceInTempDirectory.delete(); } } catch (NoCurrentCaseException | IOException ex) { logger.log(Level.SEVERE, "Unable to copy file into temp directory", ex); - //Should we add a pop-up for this? + JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError()); } }//GEN-LAST:event_launchHxDButtonActionPerformed From d0eea2db857cb41953406e39cc9d4a49bae6eb6c Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 7 Jan 2019 09:31:52 -0500 Subject: [PATCH 18/30] External Rules bug fix --- .../directorytree/ExternalViewerGlobalSettingsPanel.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index cb30626845..704573fca9 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -43,7 +43,8 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme private ExternalViewerGlobalSettingsTableModel tableModel; public ExternalViewerGlobalSettingsPanel() { - this(new ExternalViewerGlobalSettingsTableModel(new String[] {"Mime type/Extension", "Application"})); + this(new ExternalViewerGlobalSettingsTableModel(new String[] { + "Mime type/Extension", "Application"})); } /** @@ -338,7 +339,11 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme @Override public void load() { List rules = ExternalViewerRulesManager.getInstance().getUserRules(); - rules.forEach((rule) -> tableModel.addRule(rule)); + for(ExternalViewerRule rule : rules) { + if(!tableModel.containsRule(rule)) { + tableModel.addRule(rule); + } + } String editorPath = UserPreferences.getHdXEditorPath(); File HdXExecutable = new File(editorPath); if(HdXExecutable.exists() || HdXExecutable.canExecute()) { From 9f97452c2cc501b3c83992cf78ab40a695f9e8d7 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 7 Jan 2019 10:18:11 -0500 Subject: [PATCH 19/30] Upgraded jar reference in ImageGallery, Core, and Keyword Search --- Core/build.xml | 4 ++-- Core/nbproject/project.xml | 4 ++-- ImageGallery/build.xml | 7 ------- ImageGallery/nbproject/project.xml | 4 ++-- KeywordSearch/nbproject/project.xml | 4 ++-- 5 files changed, 8 insertions(+), 15 deletions(-) diff --git a/Core/build.xml b/Core/build.xml index 2c461a5017..9b6fb0b2af 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -65,8 +65,8 @@ - + release/modules/ext/tika-parsers-1.17.jar - ext/sqlite-jdbc-3.8.11.jar - release/modules/ext/sqlite-jdbc-3.8.11.jar + ext/sqlite-jdbc-3.25.2.jar + release/modules/ext/sqlite-jdbc-3.25.2.jar ext/json-simple-1.1.1.jar diff --git a/ImageGallery/build.xml b/ImageGallery/build.xml index 725c11d0e1..92d809a96d 100644 --- a/ImageGallery/build.xml +++ b/ImageGallery/build.xml @@ -15,11 +15,4 @@ out-of-date/unneeded stuff in the installer--> - - - - - - - diff --git a/ImageGallery/nbproject/project.xml b/ImageGallery/nbproject/project.xml index 16e4146740..183a947954 100644 --- a/ImageGallery/nbproject/project.xml +++ b/ImageGallery/nbproject/project.xml @@ -142,8 +142,8 @@ - ext/sqlite-jdbc-3.7.8-SNAPSHOT.jar - release/modules/ext/sqlite-jdbc-3.7.8-SNAPSHOT.jar + ext/sqlite-jdbc-3.25.2.jar + release/modules/ext/sqlite-jdbc-3.25.2.jar diff --git a/KeywordSearch/nbproject/project.xml b/KeywordSearch/nbproject/project.xml index 47be03672b..c66ad369eb 100644 --- a/KeywordSearch/nbproject/project.xml +++ b/KeywordSearch/nbproject/project.xml @@ -206,8 +206,8 @@ release/modules/ext/quartz-2.2.0.jar - ext/sqlite-jdbc-3.19.3.jar - release/modules/ext/sqlite-jdbc-3.19.3.jar + ext/sqlite-jdbc-3.25.2.jar + release/modules/ext/sqlite-jdbc-3.25.2.jar ext/guava-17.0.jar From 3c24597fac87fca1e7cf9e97c02f78f9f14f7346 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Mon, 7 Jan 2019 12:00:31 -0500 Subject: [PATCH 20/30] Send event for verification failed artifact --- .../dataSourceIntegrity/DataSourceIntegrityIngestModule.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/modules/dataSourceIntegrity/DataSourceIntegrityIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/dataSourceIntegrity/DataSourceIntegrityIngestModule.java index 4389fe5bb7..fa8d70794a 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/dataSourceIntegrity/DataSourceIntegrityIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/dataSourceIntegrity/DataSourceIntegrityIngestModule.java @@ -32,6 +32,7 @@ import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestMessage; import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType; import org.sleuthkit.autopsy.ingest.IngestServices; +import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.TskCoreException; @@ -300,6 +301,8 @@ public class DataSourceIntegrityIngestModule implements DataSourceIngestModule { BlackboardArtifact verificationFailedArtifact = Case.getCurrentCase().getSleuthkitCase().newBlackboardArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_VERIFICATION_FAILED, img.getId()); verificationFailedArtifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, DataSourceIntegrityModuleFactory.getModuleName(), artifactComment)); + IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(DataSourceIntegrityModuleFactory.getModuleName(), + BlackboardArtifact.ARTIFACT_TYPE.TSK_VERIFICATION_FAILED)); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error creating verification failed artifact", ex); } From 783b1846cca28d9d91a9cf31f7753e52dc79d887 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 7 Jan 2019 12:16:47 -0500 Subject: [PATCH 21/30] 4568 add context menu action and selection of datasource --- .../datasourceSummary/Bundle.properties | 4 +- .../DataSourceSummaryAction.java | 17 +- .../DataSourceSummaryPanel.form | 65 ++---- .../DataSourceSummaryPanel.java | 210 ++++++++++-------- .../autopsy/datamodel/ImageNode.java | 2 + .../datamodel/SpecialDirectoryNode.java | 2 + 6 files changed, 160 insertions(+), 140 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties index 982d7ee1ff..90534d59ae 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties @@ -1,9 +1,7 @@ -CTL_DataSourceSummaryAction=Data Source Summary +CTL_DataSourceSummaryAction=View Summary Information DataSourceSummaryPanel.fileCountsLabel.text=Files (based on mimetype) DataSourceSummaryPanel.opperatingSystemLabel.text=OS: DataSourceSummaryPanel.opperatingSystemValueLabel.text= -DataSourceSummaryPanel.ingestHistoryDetailsLabel.text=View Ingest History for more details -DataSourceSummaryPanel.ingestHistoryButton.text=Ingest History DataSourceSummaryPanel.openButton.text=Goto Data Source DataSourceSummaryPanel.ingestJobsLabel.text=Ingest Jobs DataSourceSummaryPanel.closeButton.text=Close diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java index f33dada13c..6be01d62ce 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java @@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.casemodule.datasourceSummary; import java.awt.Frame; import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; +import java.util.EnumSet; import javax.swing.Action; import javax.swing.JDialog; import javax.swing.SwingUtilities; @@ -28,15 +30,27 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.casemodule.Case; public class DataSourceSummaryAction extends CallableSystemAction { private static final long serialVersionUID = 1L; private static JDialog dataSourceSummaryDialog; + private final Long selectDataSource; + @Messages({"DataSourceSummaryAction.caseMenuName.text=Data Source Summary"}) DataSourceSummaryAction() { + this(false, null); + putValue(Action.NAME, Bundle.DataSourceSummaryAction_caseMenuName_text()); + } + + public DataSourceSummaryAction(boolean enabled, Long selectedDataSource) { putValue(Action.NAME, NbBundle.getMessage(DataSourceSummaryAction.class, "CTL_DataSourceSummaryAction")); - this.setEnabled(false); + this.setEnabled(enabled); + selectDataSource = selectedDataSource; + Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { + setEnabled(null != evt.getNewValue()); + }); } @Messages({"DataSourceSummaryAction.window.title=Data Source Summary"}) @@ -50,6 +64,7 @@ public class DataSourceSummaryAction extends CallableSystemAction { dataSourceSummaryPanel.addCloseButtonAction((ActionEvent e) -> { dataSourceSummaryDialog.dispose(); }); + dataSourceSummaryPanel.selectDataSource(selectDataSource); dataSourceSummaryDialog.add(dataSourceSummaryPanel); dataSourceSummaryDialog.setResizable(true); dataSourceSummaryDialog.pack(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form index 7c03337b7a..b7c26d4c22 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form @@ -27,25 +27,20 @@ - + - - + + + + + + + + - - - - - - - - - - - @@ -57,7 +52,7 @@ - + @@ -67,25 +62,15 @@ - - - - - - - - - - - - - - - - - + + - + + + + + + @@ -180,13 +165,6 @@ - - - - - - - @@ -204,12 +182,5 @@ - - - - - - -
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java index 40519ce6db..63fa47c568 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.casemodule.datasourceSummary; +import java.awt.Rectangle; import java.awt.event.ActionListener; import java.sql.ResultSet; import java.sql.SQLException; @@ -39,10 +40,13 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.datamodel.utils.FileTypeUtils; +import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.CaseDbAccessManager.CaseDbAccessQueryCallback; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.IngestJobInfo; +import org.sleuthkit.datamodel.OSInfo; +import org.sleuthkit.datamodel.OSUtility; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -53,10 +57,11 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private List ingestJobs = new ArrayList<>(); private DataSourceTableModel dataSourceTableModel = new DataSourceTableModel(); private IngestJobTableModel ingestJobTableModel = new IngestJobTableModel(); - private FilesTableModel filesTableModel = new FilesTableModel(); + private FilesTableModel filesTableModel = new FilesTableModel(null); private final List dataSources = new ArrayList<>(); private final DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); private static final Logger logger = Logger.getLogger(DataSourceSummaryPanel.class.getName()); + private List osInfoList; /** * Creates new form DataSourceSummary @@ -72,28 +77,49 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); allIngestJobs.addAll(skCase.getIngestJobs()); dataSources.addAll(skCase.getDataSources()); + osInfoList = OSUtility.getOSInfo(skCase); } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Failed to load ingest jobs.", ex); JOptionPane.showMessageDialog(this, Bundle.DataSourceSummaryPanel_getDataSources_error_text(), Bundle.DataSourceSummaryPanel_getDataSources_error_title(), JOptionPane.ERROR_MESSAGE); } dataSourcesTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { if (!e.getValueIsAdjusting()) { - updateIngestJobs(); - filesTableModel = new FilesTableModel(); + DataSource selectedDataSource = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow())); + updateIngestJobs(selectedDataSource); + filesTableModel = new FilesTableModel(selectedDataSource); fileCountsTable.setModel(filesTableModel); + opperatingSystemValueLabel.setText(getOSName(selectedDataSource)); this.repaint(); } }); } + private String getOSName(DataSource selectedDataSource) { + String osName = ""; + if (selectedDataSource != null) { + for (OSInfo osInfo : osInfoList) { + try { + if (!osInfo.getArtifacts().isEmpty() && osInfo.getArtifacts().get(0).getDataSource().getId() == selectedDataSource.getId()) { + osName = osInfo.getOSName(); + if (!osName.isEmpty()) { + break; + } + } + } catch (TskCoreException ex) { + + } + } + } + return osName; + } + @Messages({"DataSourceSummaryPanel.loadIngestJob.error.text=Failed to load ingest jobs.", "DataSourceSummaryPanel.loadIngestJob.error.title=Load Failure"}) - private void updateIngestJobs() { - Long selectedDataSourceId = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow()).getId()); + private void updateIngestJobs(DataSource selectedDataSource) { ingestJobs.clear(); - if (selectedDataSourceId != null) { + if (selectedDataSource != null) { for (IngestJobInfo ingestJob : allIngestJobs) { - if (ingestJob.getObjectId() == selectedDataSourceId) { + if (ingestJob.getObjectId() == selectedDataSource.getId()) { ingestJobs.add(ingestJob); } } @@ -122,10 +148,8 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { opperatingSystemValueLabel = new javax.swing.JLabel(); fileCountsLabel = new javax.swing.JLabel(); ingestJobsLabel = new javax.swing.JLabel(); - ingestHistoryDetailsLabel = new javax.swing.JLabel(); closeButton = new javax.swing.JButton(); openButton = new javax.swing.JButton(); - ingestHistoryButton = new javax.swing.JButton(); dataSourcesTable.setModel(dataSourceTableModel); dataSourcesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); @@ -146,8 +170,6 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(ingestJobsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestJobsLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(ingestHistoryDetailsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestHistoryDetailsLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.closeButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(openButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.openButton.text")); // NOI18N @@ -157,8 +179,6 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { } }); - org.openide.awt.Mnemonics.setLocalizedText(ingestHistoryButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestHistoryButton.text")); // NOI18N - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -175,30 +195,26 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { .addComponent(closeButton)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(fileCountsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 140, Short.MAX_VALUE) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(opperatingSystemLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addComponent(fileCountsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(ingestHistoryDetailsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(ingestHistoryButton)) .addComponent(ingestJobsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 474, Short.MAX_VALUE)))) + .addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 474, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(opperatingSystemLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))) .addContainerGap()) ); - layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {closeButton, ingestHistoryButton, openButton}); + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {closeButton, openButton}); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(8, 8, 8) - .addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 102, Short.MAX_VALUE) + .addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 120, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 5, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -207,20 +223,13 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { .addComponent(ingestJobsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(opperatingSystemLabel) - .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGroup(layout.createSequentialGroup() - .addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 105, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(ingestHistoryButton) - .addComponent(ingestHistoryDetailsLabel)) - .addGap(10, 10, 10))) - .addGap(0, 0, 0) + .addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(opperatingSystemLabel) + .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(10, 10, 10) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(closeButton) .addComponent(openButton)) @@ -235,10 +244,29 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { */ void addCloseButtonAction(ActionListener action) { this.closeButton.addActionListener(action); + this.openButton.addActionListener(action); + } + + void selectDataSource(Long dataSourceID) { + if (dataSourceID != null) { + for (int i = 0; i < dataSources.size(); i++) { + if (dataSources.get(i).getId() == dataSourceID) { + dataSourcesTable.setRowSelectionInterval(i, i); + dataSourcesTable.scrollRectToVisible(new Rectangle(dataSourcesTable.getCellRect(i, 0, true))); + return; + } + } + } + if (!dataSources.isEmpty()) { + dataSourcesTable.setRowSelectionInterval(0, 0); + } } private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed - // TODO add your handling code here: + DataSource selectedDataSource = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow())); + if (selectedDataSource != null) { + new ViewContextAction("", selectedDataSource).actionPerformed(evt); + } }//GEN-LAST:event_openButtonActionPerformed @@ -249,8 +277,6 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private javax.swing.JLabel fileCountsLabel; private javax.swing.JScrollPane fileCountsScrollPane; private javax.swing.JTable fileCountsTable; - private javax.swing.JButton ingestHistoryButton; - private javax.swing.JLabel ingestHistoryDetailsLabel; private javax.swing.JLabel ingestJobsLabel; private javax.swing.JScrollPane ingestJobsScrollPane; private javax.swing.JTable ingestJobsTable; @@ -317,12 +343,13 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private class FilesTableModel extends AbstractTableModel { private static final long serialVersionUID = 1L; - + private final DataSource currentDataSource; private final List columnHeaders = new ArrayList<>(); - FilesTableModel() { + FilesTableModel(DataSource selectedDataSource) { columnHeaders.add(Bundle.DataSourceSummaryPanel_FilesTableModel_type_header()); columnHeaders.add(Bundle.DataSourceSummaryPanel_FilesTableModel_count_header()); + currentDataSource = selectedDataSource; } @Override @@ -335,57 +362,64 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { return columnHeaders.size(); } + @Messages({ + "DataSourceSummaryPanel.FilesTableModel.images.row=Images", + "DataSourceSummaryPanel.FilesTableModel.videos.row=Videos", + "DataSourceSummaryPanel.FilesTableModel.audio.row=Audio", + "DataSourceSummaryPanel.FilesTableModel.documents.row=Documents", + "DataSourceSummaryPanel.FilesTableModel.executables.row=Executables" + }) @Override public Object getValueAt(int rowIndex, int columnIndex) { if (columnIndex == 0) { switch (rowIndex) { case 0: - return "Images"; + return Bundle.DataSourceSummaryPanel_FilesTableModel_images_row(); case 1: - return "Videos"; + return Bundle.DataSourceSummaryPanel_FilesTableModel_videos_row(); case 2: - return "Audio"; + return Bundle.DataSourceSummaryPanel_FilesTableModel_audio_row(); case 3: - return "Documents"; + return Bundle.DataSourceSummaryPanel_FilesTableModel_documents_row(); case 4: - return "Executables"; + return Bundle.DataSourceSummaryPanel_FilesTableModel_executables_row(); default: break; } } else if (columnIndex == 1) { - DataSource currentDataSource = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow())); - if (currentDataSource != null) { - switch (rowIndex) { - case 0: - return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.IMAGE.getMediaTypes()); - case 1: - return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.VIDEO.getMediaTypes()); - case 2: - return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.AUDIO.getMediaTypes()); - case 3: - return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.DOCUMENTS.getMediaTypes()); - case 4: - return getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.EXECUTABLE.getMediaTypes()); - default: - break; - } + switch (rowIndex) { + case 0: + return getCountOfFiles(FileTypeUtils.FileTypeCategory.IMAGE.getMediaTypes()); + case 1: + return getCountOfFiles(FileTypeUtils.FileTypeCategory.VIDEO.getMediaTypes()); + case 2: + return getCountOfFiles(FileTypeUtils.FileTypeCategory.AUDIO.getMediaTypes()); + case 3: + return getCountOfFiles(FileTypeUtils.FileTypeCategory.DOCUMENTS.getMediaTypes()); + case 4: + return getCountOfFiles(FileTypeUtils.FileTypeCategory.EXECUTABLE.getMediaTypes()); + default: + break; } } return null; } - private long getCountOfFiles(DataSource currentDataSource, Set setOfMimeTypes) { - try { - String inClause = String.join("', '", setOfMimeTypes); - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - return skCase.countFilesWhere("data_source_obj_id=" + currentDataSource.getId() - + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() - + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() - + " AND mime_type IN ('" + inClause + "')" - + " AND name<>''"); - } catch (TskCoreException | NoCurrentCaseException ex) { - return 0; + private Long getCountOfFiles(Set setOfMimeTypes) { + if (currentDataSource != null) { + try { + String inClause = String.join("', '", setOfMimeTypes); + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + return skCase.countFilesWhere("data_source_obj_id=" + currentDataSource.getId() + + " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() + + " AND mime_type IN ('" + inClause + "')" + + " AND name<>''"); + } catch (TskCoreException | NoCurrentCaseException ex) { + + } } + return null; } @Override @@ -434,7 +468,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { @Override public Object getValueAt(int rowIndex, int columnIndex) { DataSource currentDataSource = dataSources.get(rowIndex); - Long count; + Long count; switch (columnIndex) { case 0: return currentDataSource.getName(); @@ -459,10 +493,10 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); DataSourceCountsCallback callback = new DataSourceCountsCallback(); - String countFilesQuery = "data_source_obj_id, COUNT(*) AS count" + final String countFilesQuery = "data_source_obj_id, COUNT(*) AS count" + " FROM tsk_files WHERE type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() - + " AND name<>'' GROUP BY data_source_obj_id"; + + " AND name<>'' GROUP BY data_source_obj_id"; //NON-NLS skCase.getCaseDbAccessManager().select(countFilesQuery, callback); return callback.getMapOfCounts(); } catch (TskCoreException | NoCurrentCaseException ex) { @@ -474,9 +508,9 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); DataSourceCountsCallback callback = new DataSourceCountsCallback(); - String countArtifactsQuery = "data_source_obj_id, COUNT(*) AS count" + final String countArtifactsQuery = "data_source_obj_id, COUNT(*) AS count" + " FROM blackboard_artifacts WHERE review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID() - + " GROUP BY data_source_obj_id"; + + " GROUP BY data_source_obj_id"; //NON-NLS skCase.getCaseDbAccessManager().select(countArtifactsQuery, callback); return callback.getMapOfCounts(); } catch (TskCoreException | NoCurrentCaseException ex) { @@ -488,17 +522,17 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); DataSourceCountsCallback fileCountcallback = new DataSourceCountsCallback(); - String countFileTagsQuery = "data_source_obj_id, COUNT(*) AS count" + final String countFileTagsQuery = "data_source_obj_id, COUNT(*) AS count" + " FROM content_tags as content_tags, tsk_files as tsk_files" + " WHERE content_tags.obj_id = tsk_files.obj_id" - + " GROUP BY data_source_obj_id"; + + " GROUP BY data_source_obj_id"; //NON-NLS skCase.getCaseDbAccessManager().select(countFileTagsQuery, fileCountcallback); Map tagCountMap = new HashMap<>(fileCountcallback.getMapOfCounts()); DataSourceCountsCallback artifactCountcallback = new DataSourceCountsCallback(); - String countArtifactTagsQuery = "data_source_obj_id, COUNT(*) AS count" + final String countArtifactTagsQuery = "data_source_obj_id, COUNT(*) AS count" + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts" + " WHERE artifact_tags.artifact_id = arts.artifact_id" - + " GROUP BY data_source_obj_id"; + + " GROUP BY data_source_obj_id"; //NON-NLS skCase.getCaseDbAccessManager().select(countArtifactTagsQuery, artifactCountcallback); //combine the results from the count artifact tags query into the copy of the mapped results from the count file tags query artifactCountcallback.getMapOfCounts().forEach((key, value) -> tagCountMap.merge(key, value, (value1, value2) -> value1 + value2)); @@ -523,9 +557,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { try { while (rs.next()) { try { - long dataSourceObjectId = rs.getLong("data_source_obj_id"); - long count = rs.getLong("count"); - dataSourceObjIdCounts.put(dataSourceObjectId, count); + dataSourceObjIdCounts.put(rs.getLong("data_source_obj_id"), rs.getLong("count")); } catch (SQLException ex) { System.out.println("UNABLE TO GET COUNT FOR DS " + ex.getMessage()); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index 0bb186d75e..e33099b2b3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -34,6 +34,7 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor; import org.sleuthkit.autopsy.directorytree.FileSearchAction; @@ -108,6 +109,7 @@ public class ImageNode extends AbstractContentNode { actionsList.addAll(ExplorerNodeActionVisitor.getActions(content)); actionsList.add(new FileSearchAction( Bundle.ImageNode_getActions_openFileSearchByAttr_text())); + actionsList.add(new DataSourceSummaryAction(true, content.getId())); actionsList.add(new RunIngestModulesAction(Collections.singletonList(content))); actionsList.add(new NewWindowViewAction( NbBundle.getMessage(this.getClass(), "ImageNode.getActions.viewInNewWin.text"), this)); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java index 7dc18a7394..a31f0932ae 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.List; import javax.swing.Action; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.FileSearchAction; @@ -63,6 +64,7 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNodesingletonList(content))); } else { actions.add(new RunIngestModulesAction(content)); From 9e298d608ec54cde4dc2abfba09c520337ac2d09 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 7 Jan 2019 13:48:04 -0500 Subject: [PATCH 22/30] 4568 create second action to avoid multiple instances of CallableSystemAction being created --- .../datasourceSummary/Bundle.properties | 2 - .../DataSourceSummaryAction.java | 55 +++++---------- .../DataSourceSummaryPanel.form | 5 -- .../DataSourceSummaryPanel.java | 2 - .../ViewSummaryInformationAction.java | 67 +++++++++++++++++++ .../autopsy/datamodel/ImageNode.java | 4 +- .../datamodel/SpecialDirectoryNode.java | 4 +- 7 files changed, 89 insertions(+), 50 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties index 90534d59ae..df9cb9a3bb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties @@ -1,7 +1,5 @@ -CTL_DataSourceSummaryAction=View Summary Information DataSourceSummaryPanel.fileCountsLabel.text=Files (based on mimetype) DataSourceSummaryPanel.opperatingSystemLabel.text=OS: -DataSourceSummaryPanel.opperatingSystemValueLabel.text= DataSourceSummaryPanel.openButton.text=Goto Data Source DataSourceSummaryPanel.ingestJobsLabel.text=Ingest Jobs DataSourceSummaryPanel.closeButton.text=Close diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java index 6be01d62ce..ae9980b357 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java @@ -18,70 +18,51 @@ */ package org.sleuthkit.autopsy.casemodule.datasourceSummary; -import java.awt.Frame; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.util.EnumSet; import javax.swing.Action; -import javax.swing.JDialog; -import javax.swing.SwingUtilities; +import org.openide.awt.ActionID; +import org.openide.awt.ActionRegistration; import org.openide.util.HelpCtx; -import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; -import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +@ActionID(category = "Case", id = "org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction") +@ActionRegistration(displayName = "#CTL_DataSourceSummaryAction", lazy = false) +@Messages({"CTL_DataSourceSummaryAction=Data Source Summary"}) public class DataSourceSummaryAction extends CallableSystemAction { private static final long serialVersionUID = 1L; - private static JDialog dataSourceSummaryDialog; - private final Long selectDataSource; - - @Messages({"DataSourceSummaryAction.caseMenuName.text=Data Source Summary"}) + DataSourceSummaryAction() { - this(false, null); - putValue(Action.NAME, Bundle.DataSourceSummaryAction_caseMenuName_text()); - } - - public DataSourceSummaryAction(boolean enabled, Long selectedDataSource) { - putValue(Action.NAME, NbBundle.getMessage(DataSourceSummaryAction.class, "CTL_DataSourceSummaryAction")); - this.setEnabled(enabled); - selectDataSource = selectedDataSource; + putValue(Action.NAME, Bundle.CTL_DataSourceSummaryAction()); + this.setEnabled(false); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { setEnabled(null != evt.getNewValue()); - }); + }); } - - @Messages({"DataSourceSummaryAction.window.title=Data Source Summary"}) + @Override public void performAction() { - SwingUtilities.invokeLater(() -> { - String title = NbBundle.getMessage(this.getClass(), "DataSourceSummaryAction.window.title"); - Frame mainWindow = WindowManager.getDefault().getMainWindow(); - dataSourceSummaryDialog = new JDialog(mainWindow, title, true); - DataSourceSummaryPanel dataSourceSummaryPanel = new DataSourceSummaryPanel(); - dataSourceSummaryPanel.addCloseButtonAction((ActionEvent e) -> { - dataSourceSummaryDialog.dispose(); - }); - dataSourceSummaryPanel.selectDataSource(selectDataSource); - dataSourceSummaryDialog.add(dataSourceSummaryPanel); - dataSourceSummaryDialog.setResizable(true); - dataSourceSummaryDialog.pack(); - dataSourceSummaryDialog.setLocationRelativeTo(mainWindow); - dataSourceSummaryDialog.setVisible(true); - dataSourceSummaryDialog.toFront(); - }); + //perform the action of a ViewSummaryInformationAction with a ActionEvent which will not be used + new ViewSummaryInformationAction(null).actionPerformed(new ActionEvent(Boolean.TRUE, 0, "")); } @Override public String getName() { - return NbBundle.getMessage(DataSourceSummaryAction.class, "CTL_DataSourceSummaryAction"); + return Bundle.CTL_DataSourceSummaryAction(); } @Override public HelpCtx getHelpCtx() { return HelpCtx.DEFAULT_HELP; } + + @Override + public boolean asynchronous(){ + return false; + } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form index b7c26d4c22..0ff4d08b72 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form @@ -145,11 +145,6 @@
- - - - - diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java index 63fa47c568..bd6a4dc457 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -164,8 +164,6 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(opperatingSystemLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.opperatingSystemLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(opperatingSystemValueLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.opperatingSystemValueLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(fileCountsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.fileCountsLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(ingestJobsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestJobsLabel.text")); // NOI18N diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java new file mode 100644 index 0000000000..400af48209 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java @@ -0,0 +1,67 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.casemodule.datasourceSummary; + +import java.awt.Frame; +import java.awt.event.ActionEvent; +import javax.swing.AbstractAction; +import javax.swing.JDialog; +import javax.swing.SwingUtilities; +import org.openide.util.NbBundle; +import org.openide.windows.WindowManager; + +/** + * + * @author wschaefer + */ +public final class ViewSummaryInformationAction extends AbstractAction { + + private static JDialog dataSourceSummaryDialog; + private static Long selectDataSource; + private static final long serialVersionUID = 1L; + + @NbBundle.Messages({"ViewSummaryInformationAction.name.text=View Summary Information"}) + public ViewSummaryInformationAction(Long selectedDataSource) { + super(Bundle.ViewSummaryInformationAction_name_text()); + this.setEnabled(true); + selectDataSource = selectedDataSource; + } + + @NbBundle.Messages({"ViewSummaryInformationAction.window.title=Data Source Summary"}) + @Override + public void actionPerformed(ActionEvent actionEvent) { + SwingUtilities.invokeLater(() -> { + String title = Bundle.ViewSummaryInformationAction_window_title(); + Frame mainWindow = WindowManager.getDefault().getMainWindow(); + dataSourceSummaryDialog = new JDialog(mainWindow, title, true); + DataSourceSummaryPanel dataSourceSummaryPanel = new DataSourceSummaryPanel(); + dataSourceSummaryPanel.addCloseButtonAction((ActionEvent event) -> { + dataSourceSummaryDialog.dispose(); + }); + dataSourceSummaryPanel.selectDataSource(selectDataSource); + dataSourceSummaryDialog.add(dataSourceSummaryPanel); + dataSourceSummaryDialog.setResizable(true); + dataSourceSummaryDialog.pack(); + dataSourceSummaryDialog.setLocationRelativeTo(mainWindow); + dataSourceSummaryDialog.setVisible(true); + dataSourceSummaryDialog.toFront(); + }); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index e33099b2b3..9025b325e3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -34,7 +34,7 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction; +import org.sleuthkit.autopsy.casemodule.datasourceSummary.ViewSummaryInformationAction; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor; import org.sleuthkit.autopsy.directorytree.FileSearchAction; @@ -109,7 +109,7 @@ public class ImageNode extends AbstractContentNode { actionsList.addAll(ExplorerNodeActionVisitor.getActions(content)); actionsList.add(new FileSearchAction( Bundle.ImageNode_getActions_openFileSearchByAttr_text())); - actionsList.add(new DataSourceSummaryAction(true, content.getId())); + actionsList.add(new ViewSummaryInformationAction(content.getId())); actionsList.add(new RunIngestModulesAction(Collections.singletonList(content))); actionsList.add(new NewWindowViewAction( NbBundle.getMessage(this.getClass(), "ImageNode.getActions.viewInNewWin.text"), this)); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java index a31f0932ae..9509ccb483 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java @@ -23,7 +23,7 @@ import java.util.Collections; import java.util.List; import javax.swing.Action; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction; +import org.sleuthkit.autopsy.casemodule.datasourceSummary.ViewSummaryInformationAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.FileSearchAction; @@ -64,7 +64,7 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNodesingletonList(content))); } else { actions.add(new RunIngestModulesAction(content)); From 97f5d1cd3e179dc1f5f84a05b5bf3e843829a17a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 7 Jan 2019 15:50:12 -0500 Subject: [PATCH 23/30] 4568 add comments and clean up classes in regards to data source summary --- .../datasourceSummary/Bundle.properties | 2 +- .../DataSourceSummaryAction.java | 23 +- .../DataSourceSummaryPanel.form | 16 +- .../DataSourceSummaryPanel.java | 452 +++++++++++------- .../ViewSummaryInformationAction.java | 22 +- 5 files changed, 322 insertions(+), 193 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties index df9cb9a3bb..855f75bd20 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties @@ -1,5 +1,5 @@ DataSourceSummaryPanel.fileCountsLabel.text=Files (based on mimetype) DataSourceSummaryPanel.opperatingSystemLabel.text=OS: -DataSourceSummaryPanel.openButton.text=Goto Data Source DataSourceSummaryPanel.ingestJobsLabel.text=Ingest Jobs DataSourceSummaryPanel.closeButton.text=Close +DataSourceSummaryPanel.gotoDataSourceButton.text=Goto Data Source diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java index ae9980b357..5dc3035867 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryAction.java @@ -32,22 +32,29 @@ import org.sleuthkit.autopsy.casemodule.Case; @ActionID(category = "Case", id = "org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction") @ActionRegistration(displayName = "#CTL_DataSourceSummaryAction", lazy = false) @Messages({"CTL_DataSourceSummaryAction=Data Source Summary"}) +/** + * DataSourceSummaryAction action for the Case menu to activate a ViewSummaryInformationAction selecting the first data source. + */ public class DataSourceSummaryAction extends CallableSystemAction { private static final long serialVersionUID = 1L; - + + /** + * Create a datasource summary action which will be disabled when no case is + * open. + */ DataSourceSummaryAction() { putValue(Action.NAME, Bundle.CTL_DataSourceSummaryAction()); this.setEnabled(false); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { setEnabled(null != evt.getNewValue()); - }); + }); } - + @Override public void performAction() { - //perform the action of a ViewSummaryInformationAction with a ActionEvent which will not be used - new ViewSummaryInformationAction(null).actionPerformed(new ActionEvent(Boolean.TRUE, 0, "")); + //perform the action of a ViewSummaryInformationAction with a ActionEvent which will not be used + new ViewSummaryInformationAction(null).actionPerformed(new ActionEvent(Boolean.TRUE, 0, "")); } @Override @@ -59,10 +66,4 @@ public class DataSourceSummaryAction extends CallableSystemAction { public HelpCtx getHelpCtx() { return HelpCtx.DEFAULT_HELP; } - - @Override - public boolean asynchronous(){ - return false; - } - } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form index 0ff4d08b72..16fa26c1a0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form @@ -23,7 +23,7 @@ - + @@ -66,14 +66,16 @@ - + - + + + - + @@ -167,14 +169,14 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java index bd6a4dc457..5f7315a566 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -51,8 +51,9 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; -public class DataSourceSummaryPanel extends javax.swing.JPanel { +final class DataSourceSummaryPanel extends javax.swing.JPanel { + private static final long serialVersionUID = 1L; private final List allIngestJobs = new ArrayList<>(); private List ingestJobs = new ArrayList<>(); private DataSourceTableModel dataSourceTableModel = new DataSourceTableModel(); @@ -64,11 +65,13 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private List osInfoList; /** - * Creates new form DataSourceSummary + * Creates new form DataSourceSummaryPanel for displaying a summary of the + * data sources for the fcurrent case and the contents found for each + * datasource. */ @Messages({"DataSourceSummaryPanel.getDataSources.error.text=Failed to get the list of datasources for the current case.", "DataSourceSummaryPanel.getDataSources.error.title=Load Failure"}) - public DataSourceSummaryPanel() { + DataSourceSummaryPanel() { initComponents(); ingestJobsTable.getTableHeader().setReorderingAllowed(false); fileCountsTable.getTableHeader().setReorderingAllowed(false); @@ -94,25 +97,44 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { }); } + /** + * Get the name of the operating system if it is available. Otherwise get + * and empty string. + * + * @param selectedDataSource the datasource to get the OS information for + * + * @return the name of the opperating system on the specified datasource, + * empty string if no opperating system info found + */ private String getOSName(DataSource selectedDataSource) { String osName = ""; if (selectedDataSource != null) { for (OSInfo osInfo : osInfoList) { try { + //assumes only one Opperating System per datasource + //get the datasource id from the OSInfo's first artifact if it has artifacts if (!osInfo.getArtifacts().isEmpty() && osInfo.getArtifacts().get(0).getDataSource().getId() == selectedDataSource.getId()) { osName = osInfo.getOSName(); + //if this OSInfo object has a name use it otherwise keep checking OSInfo objects if (!osName.isEmpty()) { break; } } - } catch (TskCoreException ex) { - + } catch (TskCoreException ignored) { + //unable to get datasource for the OSInfo Object + //continue checking for OSInfo objects which we can get the desired information from } } } return osName; } + /** + * Update the ingestJobs list with the ingest jobs for the + * selectedDataSource + * + * @param selectedDataSource the datasource to find the ingest jobs for + */ @Messages({"DataSourceSummaryPanel.loadIngestJob.error.text=Failed to load ingest jobs.", "DataSourceSummaryPanel.loadIngestJob.error.title=Load Failure"}) private void updateIngestJobs(DataSource selectedDataSource) { @@ -149,7 +171,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { fileCountsLabel = new javax.swing.JLabel(); ingestJobsLabel = new javax.swing.JLabel(); closeButton = new javax.swing.JButton(); - openButton = new javax.swing.JButton(); + gotoDataSourceButton = new javax.swing.JButton(); dataSourcesTable.setModel(dataSourceTableModel); dataSourcesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); @@ -170,10 +192,10 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.closeButton.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(openButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.openButton.text")); // NOI18N - openButton.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(gotoDataSourceButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.gotoDataSourceButton.text")); // NOI18N + gotoDataSourceButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - openButtonActionPerformed(evt); + gotoDataSourceButtonActionPerformed(evt); } }); @@ -188,7 +210,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { .addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) - .addComponent(openButton) + .addComponent(gotoDataSourceButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(closeButton)) .addGroup(layout.createSequentialGroup() @@ -206,7 +228,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { .addContainerGap()) ); - layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {closeButton, openButton}); + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {closeButton, gotoDataSourceButton}); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -224,13 +246,14 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { .addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(opperatingSystemLabel) - .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(opperatingSystemLabel, javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))) .addGap(10, 10, 10) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(closeButton) - .addComponent(openButton)) + .addComponent(gotoDataSourceButton)) .addContainerGap()) ); }// //GEN-END:initComponents @@ -242,30 +265,46 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { */ void addCloseButtonAction(ActionListener action) { this.closeButton.addActionListener(action); - this.openButton.addActionListener(action); + //the gotoDataSourceButton should also close the dialog + this.gotoDataSourceButton.addActionListener(action); } + /** + * Select the data source with the specicied data source id. If no data + * source matches the dataSourceID it will select the first datasource. + * + * @param dataSourceID the ID of the datasource to select, null will cause + * the first datasource to be selected + */ void selectDataSource(Long dataSourceID) { if (dataSourceID != null) { for (int i = 0; i < dataSources.size(); i++) { if (dataSources.get(i).getId() == dataSourceID) { dataSourcesTable.setRowSelectionInterval(i, i); + //scroll down from top of table to where selected datasource is dataSourcesTable.scrollRectToVisible(new Rectangle(dataSourcesTable.getCellRect(i, 0, true))); return; } } - } + } + //if there are data sources in the list and none were found that matched the specied dataSourceID select the first one if (!dataSources.isEmpty()) { dataSourcesTable.setRowSelectionInterval(0, 0); } } - private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed + /** + * Performed when the Goto Data Source button is clicked, will cause the + * window to be closed and the data source which was selected to be + * navigated to in the tree. + */ + private void gotoDataSourceButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gotoDataSourceButtonActionPerformed + //the dialog will be closed due to the action listener added in addCloseButtonAction DataSource selectedDataSource = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow())); if (selectedDataSource != null) { new ViewContextAction("", selectedDataSource).actionPerformed(evt); } - }//GEN-LAST:event_openButtonActionPerformed + }//GEN-LAST:event_gotoDataSourceButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables @@ -275,15 +314,214 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private javax.swing.JLabel fileCountsLabel; private javax.swing.JScrollPane fileCountsScrollPane; private javax.swing.JTable fileCountsTable; + private javax.swing.JButton gotoDataSourceButton; private javax.swing.JLabel ingestJobsLabel; private javax.swing.JScrollPane ingestJobsScrollPane; private javax.swing.JTable ingestJobsTable; private javax.swing.JSeparator jSeparator1; - private javax.swing.JButton openButton; private javax.swing.JLabel opperatingSystemLabel; private javax.swing.JLabel opperatingSystemValueLabel; // End of variables declaration//GEN-END:variables + /** + * Table model for the Data source table, to display all data sources for + * the current case. + */ + @Messages({"DataSourceSummaryPanel.DataSourceTableModel.dataSourceName.header=Data Source Name", + "DataSourceSummaryPanel.DataSourceTableModel.type.header=Type", + "DataSourceSummaryPanel.DataSourceTableModel.files.header=Files", + "DataSourceSummaryPanel.DataSourceTableModel.results.header=Results", + "DataSourceSummaryPanel.DataSourceTableModel.tags.header=Tags"}) + private class DataSourceTableModel extends AbstractTableModel { + + private static final long serialVersionUID = 1L; + + private final List columnHeaders = new ArrayList<>(); + private final Map fileCountsMap; + private final Map artifactCountsMap; + private final Map tagCountsMap; + + /** + * Create a new DataSourceTableModel for the current case. + */ + DataSourceTableModel() { + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_dataSourceName_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_type_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_files_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_results_header()); + columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_tags_header()); + fileCountsMap = getCountsOfFiles(); + artifactCountsMap = getCountsOfArtifacts(); + tagCountsMap = getCountsOfTags(); + + } + + @Override + public int getRowCount() { + return dataSources.size(); + } + + @Override + public int getColumnCount() { + return columnHeaders.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + DataSource currentDataSource = dataSources.get(rowIndex); + Long count; + switch (columnIndex) { + case 0: + return currentDataSource.getName(); + case 1: + return ""; + case 2: + //display 0 if no count is found + count = fileCountsMap.get(currentDataSource.getId()); + return count == null ? 0 : count; + case 3: + //display 0 if no count is found + count = artifactCountsMap.get(currentDataSource.getId()); + return count == null ? 0 : count; + case 4: + //display 0 if no count is found + count = tagCountsMap.get(currentDataSource.getId()); + return count == null ? 0 : count; + default: + break; + } + return null; + } + + /** + * Get a map containing the number of files in each data source in the + * current case. + * + * @return Collection which maps datasource id to a count for the number + * of files in the datasource, will only contain entries for + * datasources which have at least 1 file + */ + private Map getCountsOfFiles() { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + DataSourceCountsCallback callback = new DataSourceCountsCallback(); + final String countFilesQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM tsk_files WHERE type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() + + " AND name<>'' GROUP BY data_source_obj_id"; //NON-NLS + skCase.getCaseDbAccessManager().select(countFilesQuery, callback); + return callback.getMapOfCounts(); + } catch (TskCoreException | NoCurrentCaseException ex) { + return Collections.emptyMap(); + } + } + + /** + * Get a map containing the number of artifacts in each data source in + * the current case. + * + * @return Collection which maps datasource id to a count for the number + * of artifacts in the datasource, will only contain entries for + * datasources which have at least 1 artifact + */ + private Map getCountsOfArtifacts() { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + DataSourceCountsCallback callback = new DataSourceCountsCallback(); + final String countArtifactsQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM blackboard_artifacts WHERE review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID() + + " GROUP BY data_source_obj_id"; //NON-NLS + skCase.getCaseDbAccessManager().select(countArtifactsQuery, callback); + return callback.getMapOfCounts(); + } catch (TskCoreException | NoCurrentCaseException ex) { + return Collections.emptyMap(); + } + } + + /** + * Get a map containing the number of tags which have been applied in + * each data source in the current case. Not necessarily the same as the + * number of items tagged, as an item can have any number of tags. + * + * @return Collection which maps datasource id to a count for the number + * of tags which have been applied in the datasource, will only + * contain entries for datasources which have at least 1 item + * tagged. + */ + private Map getCountsOfTags() { + try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + DataSourceCountsCallback fileCountcallback = new DataSourceCountsCallback(); + final String countFileTagsQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM content_tags as content_tags, tsk_files as tsk_files" + + " WHERE content_tags.obj_id = tsk_files.obj_id" + + " GROUP BY data_source_obj_id"; //NON-NLS + skCase.getCaseDbAccessManager().select(countFileTagsQuery, fileCountcallback); + Map tagCountMap = new HashMap<>(fileCountcallback.getMapOfCounts()); + DataSourceCountsCallback artifactCountcallback = new DataSourceCountsCallback(); + final String countArtifactTagsQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts" + + " WHERE artifact_tags.artifact_id = arts.artifact_id" + + " GROUP BY data_source_obj_id"; //NON-NLS + skCase.getCaseDbAccessManager().select(countArtifactTagsQuery, artifactCountcallback); + //combine the results from the count artifact tags query into the copy of the mapped results from the count file tags query + artifactCountcallback.getMapOfCounts().forEach((key, value) -> tagCountMap.merge(key, value, (value1, value2) -> value1 + value2)); + return tagCountMap; + } catch (TskCoreException | NoCurrentCaseException ex) { + return Collections.emptyMap(); + } + + } + + @Override + public String getColumnName(int column) { + return columnHeaders.get(column); + } + + /** + * Get the map of Data Source ID to counts of items found for a query + * which selects data_source_obj_id and count(*) with a group by + * data_source_obj_id clause. + */ + private class DataSourceCountsCallback implements CaseDbAccessQueryCallback { + + Map dataSourceObjIdCounts = new HashMap<>(); + + @Override + public void process(ResultSet rs) { + try { + while (rs.next()) { + try { + dataSourceObjIdCounts.put(rs.getLong("data_source_obj_id"), rs.getLong("count")); + } catch (SQLException ex) { + System.out.println("UNABLE TO GET COUNT FOR DS " + ex.getMessage()); + } + } + } catch (SQLException ex) { + System.out.println("Failed to get next result" + ex.getMessage()); + } + } + + /** + * Get the processed results + * + * @return Collection which maps datasource id to a count for the + * number of items found with that datasource id, only + * contains entries for datasources with at least 1 item + * found. + */ + Map getMapOfCounts() { + return Collections.unmodifiableMap(dataSourceObjIdCounts); + } + + } + + } + + /** + * Table model for the Ingest Job table to display ingest jobs for the + * selected datasource. + */ @Messages({"DataSourceSummaryPanel.IngestJobTableModel.StartTime.header=Start Time", "DataSourceSummaryPanel.IngestJobTableModel.EndTime.header=End Time", "DataSourceSummaryPanel.IngestJobTableModel.IngestStatus.header=Ingest Status"}) @@ -293,6 +531,9 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private final List columnHeaders = new ArrayList<>(); + /** + * Create a new IngestJobTableModel + */ IngestJobTableModel() { columnHeaders.add(Bundle.DataSourceSummaryPanel_IngestJobTableModel_StartTime_header()); columnHeaders.add(Bundle.DataSourceSummaryPanel_IngestJobTableModel_EndTime_header()); @@ -336,6 +577,10 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { } + /** + * Table model for the files table model to display counts of specific file + * types found in the currently selected data source. + */ @Messages({"DataSourceSummaryPanel.FilesTableModel.type.header=File Type", "DataSourceSummaryPanel.FilesTableModel.count.header=Count"}) private class FilesTableModel extends AbstractTableModel { @@ -344,6 +589,12 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { private final DataSource currentDataSource; private final List columnHeaders = new ArrayList<>(); + /** + * Create a FilesTableModel for the speicified datasource. + * + * @param selectedDataSource the datasource which this filesTablemodel + * will represent + */ FilesTableModel(DataSource selectedDataSource) { columnHeaders.add(Bundle.DataSourceSummaryPanel_FilesTableModel_type_header()); columnHeaders.add(Bundle.DataSourceSummaryPanel_FilesTableModel_count_header()); @@ -352,6 +603,7 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { @Override public int getRowCount() { + //should be kept equal to the number of types we are displaying in the tables return 5; } @@ -403,6 +655,17 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { return null; } + /** + * Get the number of files in the case database for the current data + * source which have the specified mimetypes. + * + * @param setOfMimeTypes the set of mime types which we are finding the + * number of occurences of + * + * @return a Long value which represents the number of occurrences of + * the specified mime types in the current case for the + * specified data source, null if no count was retrieved + */ private Long getCountOfFiles(Set setOfMimeTypes) { if (currentDataSource != null) { try { @@ -414,7 +677,8 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { + " AND mime_type IN ('" + inClause + "')" + " AND name<>''"); } catch (TskCoreException | NoCurrentCaseException ex) { - + logger.log(Level.INFO, "Unable to get count of files for specified mime types", ex); + //unable to get count of files for the specified mimetypes cell will be displayed as empty } } return null; @@ -427,150 +691,4 @@ public class DataSourceSummaryPanel extends javax.swing.JPanel { } - @Messages({"DataSourceSummaryPanel.DataSourceTableModel.dataSourceName.header=Data Source Name", - "DataSourceSummaryPanel.DataSourceTableModel.type.header=Type", - "DataSourceSummaryPanel.DataSourceTableModel.files.header=Files", - "DataSourceSummaryPanel.DataSourceTableModel.results.header=Results", - "DataSourceSummaryPanel.DataSourceTableModel.tags.header=Tags"}) - private class DataSourceTableModel extends AbstractTableModel { - - private static final long serialVersionUID = 1L; - - private final List columnHeaders = new ArrayList<>(); - private final Map fileCountsMap; - private final Map artifactCountsMap; - private final Map tagCountsMap; - - DataSourceTableModel() { - columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_dataSourceName_header()); - columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_type_header()); - columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_files_header()); - columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_results_header()); - columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_tags_header()); - fileCountsMap = getCountsOfFiles(); - artifactCountsMap = getCountsOfArtifacts(); - tagCountsMap = getCountsOfTags(); - - } - - @Override - public int getRowCount() { - return dataSources.size(); - } - - @Override - public int getColumnCount() { - return columnHeaders.size(); - } - - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - DataSource currentDataSource = dataSources.get(rowIndex); - Long count; - switch (columnIndex) { - case 0: - return currentDataSource.getName(); - case 1: - return ""; - case 2: - count = fileCountsMap.get(currentDataSource.getId()); - return count == null ? 0 : count; - case 3: - count = artifactCountsMap.get(currentDataSource.getId()); - return count == null ? 0 : count; - case 4: - count = tagCountsMap.get(currentDataSource.getId()); - return count == null ? 0 : count; - default: - break; - } - return null; - } - - private Map getCountsOfFiles() { - try { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - DataSourceCountsCallback callback = new DataSourceCountsCallback(); - final String countFilesQuery = "data_source_obj_id, COUNT(*) AS count" - + " FROM tsk_files WHERE type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() - + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() - + " AND name<>'' GROUP BY data_source_obj_id"; //NON-NLS - skCase.getCaseDbAccessManager().select(countFilesQuery, callback); - return callback.getMapOfCounts(); - } catch (TskCoreException | NoCurrentCaseException ex) { - return Collections.emptyMap(); - } - } - - private Map getCountsOfArtifacts() { - try { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - DataSourceCountsCallback callback = new DataSourceCountsCallback(); - final String countArtifactsQuery = "data_source_obj_id, COUNT(*) AS count" - + " FROM blackboard_artifacts WHERE review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID() - + " GROUP BY data_source_obj_id"; //NON-NLS - skCase.getCaseDbAccessManager().select(countArtifactsQuery, callback); - return callback.getMapOfCounts(); - } catch (TskCoreException | NoCurrentCaseException ex) { - return Collections.emptyMap(); - } - } - - private Map getCountsOfTags() { - try { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - DataSourceCountsCallback fileCountcallback = new DataSourceCountsCallback(); - final String countFileTagsQuery = "data_source_obj_id, COUNT(*) AS count" - + " FROM content_tags as content_tags, tsk_files as tsk_files" - + " WHERE content_tags.obj_id = tsk_files.obj_id" - + " GROUP BY data_source_obj_id"; //NON-NLS - skCase.getCaseDbAccessManager().select(countFileTagsQuery, fileCountcallback); - Map tagCountMap = new HashMap<>(fileCountcallback.getMapOfCounts()); - DataSourceCountsCallback artifactCountcallback = new DataSourceCountsCallback(); - final String countArtifactTagsQuery = "data_source_obj_id, COUNT(*) AS count" - + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts" - + " WHERE artifact_tags.artifact_id = arts.artifact_id" - + " GROUP BY data_source_obj_id"; //NON-NLS - skCase.getCaseDbAccessManager().select(countArtifactTagsQuery, artifactCountcallback); - //combine the results from the count artifact tags query into the copy of the mapped results from the count file tags query - artifactCountcallback.getMapOfCounts().forEach((key, value) -> tagCountMap.merge(key, value, (value1, value2) -> value1 + value2)); - return tagCountMap; - } catch (TskCoreException | NoCurrentCaseException ex) { - return Collections.emptyMap(); - } - - } - - @Override - public String getColumnName(int column) { - return columnHeaders.get(column); - } - - private class DataSourceCountsCallback implements CaseDbAccessQueryCallback { - - Map dataSourceObjIdCounts = new HashMap<>(); - - @Override - public void process(ResultSet rs) { - try { - while (rs.next()) { - try { - dataSourceObjIdCounts.put(rs.getLong("data_source_obj_id"), rs.getLong("count")); - } catch (SQLException ex) { - System.out.println("UNABLE TO GET COUNT FOR DS " + ex.getMessage()); - } - } - } catch (SQLException ex) { - System.out.println("Failed to get next result" + ex.getMessage()); - } - } - - Map getMapOfCounts() { - return Collections.unmodifiableMap(dataSourceObjIdCounts); - } - - } - - } - } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java index 400af48209..96572fbf51 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/ViewSummaryInformationAction.java @@ -23,12 +23,12 @@ import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.JDialog; import javax.swing.SwingUtilities; -import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; /** - * - * @author wschaefer + * ViewSummaryInformationAction action for opening a Data Source Summary Panel + * with the specified data source selected if it is present. */ public final class ViewSummaryInformationAction extends AbstractAction { @@ -36,14 +36,20 @@ public final class ViewSummaryInformationAction extends AbstractAction { private static Long selectDataSource; private static final long serialVersionUID = 1L; - @NbBundle.Messages({"ViewSummaryInformationAction.name.text=View Summary Information"}) + /** + * Create a ViewSummaryInformationAction for the selected datasource. + * + * @param selectedDataSource - the data source which is currently selected + * and will be selected initially when the + * DataSourceSummaryPanel opens. + */ + @Messages({"ViewSummaryInformationAction.name.text=View Summary Information"}) public ViewSummaryInformationAction(Long selectedDataSource) { super(Bundle.ViewSummaryInformationAction_name_text()); - this.setEnabled(true); selectDataSource = selectedDataSource; } - - @NbBundle.Messages({"ViewSummaryInformationAction.window.title=Data Source Summary"}) + + @Messages({"ViewSummaryInformationAction.window.title=Data Source Summary"}) @Override public void actionPerformed(ActionEvent actionEvent) { SwingUtilities.invokeLater(() -> { @@ -51,9 +57,11 @@ public final class ViewSummaryInformationAction extends AbstractAction { Frame mainWindow = WindowManager.getDefault().getMainWindow(); dataSourceSummaryDialog = new JDialog(mainWindow, title, true); DataSourceSummaryPanel dataSourceSummaryPanel = new DataSourceSummaryPanel(); + //allow the buttons in DataSourceSummaryPanel to close this dialog dataSourceSummaryPanel.addCloseButtonAction((ActionEvent event) -> { dataSourceSummaryDialog.dispose(); }); + //select the specifed data source dataSourceSummaryPanel.selectDataSource(selectDataSource); dataSourceSummaryDialog.add(dataSourceSummaryPanel); dataSourceSummaryDialog.setResizable(true); From 72046156c831dcade654ede54dc806f285dbef3b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 7 Jan 2019 16:01:52 -0500 Subject: [PATCH 24/30] 4568 add exception logging and disable goto datasource button when no datasource selected --- .../DataSourceSummaryPanel.form | 5 ++--- .../DataSourceSummaryPanel.java | 16 ++++++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form index 16fa26c1a0..255af69ffa 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.form @@ -68,9 +68,7 @@ - - - + @@ -174,6 +172,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java index 5f7315a566..6fc2ca56e5 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryPanel.java @@ -88,6 +88,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { dataSourcesTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { if (!e.getValueIsAdjusting()) { DataSource selectedDataSource = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow())); + gotoDataSourceButton.setEnabled(selectedDataSource != null); updateIngestJobs(selectedDataSource); filesTableModel = new FilesTableModel(selectedDataSource); fileCountsTable.setModel(filesTableModel); @@ -122,7 +123,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { } } catch (TskCoreException ignored) { //unable to get datasource for the OSInfo Object - //continue checking for OSInfo objects which we can get the desired information from + //continue checking for OSInfo objects to try and get get the desired information } } } @@ -193,6 +194,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.closeButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(gotoDataSourceButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.gotoDataSourceButton.text")); // NOI18N + gotoDataSourceButton.setEnabled(false); gotoDataSourceButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { gotoDataSourceButtonActionPerformed(evt); @@ -248,8 +250,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(opperatingSystemLabel, javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(10, 10, 10) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(closeButton) @@ -412,6 +413,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { skCase.getCaseDbAccessManager().select(countFilesQuery, callback); return callback.getMapOfCounts(); } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Unable to get counts of files for all datasources, providing empty results", ex); return Collections.emptyMap(); } } @@ -434,6 +436,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { skCase.getCaseDbAccessManager().select(countArtifactsQuery, callback); return callback.getMapOfCounts(); } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Unable to get counts of artifacts for all datasources, providing empty results", ex); return Collections.emptyMap(); } } @@ -468,6 +471,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { artifactCountcallback.getMapOfCounts().forEach((key, value) -> tagCountMap.merge(key, value, (value1, value2) -> value1 + value2)); return tagCountMap; } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Unable to get counts of tags for all datasources, providing empty results", ex); return Collections.emptyMap(); } @@ -494,11 +498,11 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { try { dataSourceObjIdCounts.put(rs.getLong("data_source_obj_id"), rs.getLong("count")); } catch (SQLException ex) { - System.out.println("UNABLE TO GET COUNT FOR DS " + ex.getMessage()); + logger.log(Level.WARNING, "Unable to get data_source_obj_id or count from result set", ex); } } } catch (SQLException ex) { - System.out.println("Failed to get next result" + ex.getMessage()); + logger.log(Level.WARNING, "Failed to get next result for counts by datasource", ex); } } @@ -677,7 +681,7 @@ final class DataSourceSummaryPanel extends javax.swing.JPanel { + " AND mime_type IN ('" + inClause + "')" + " AND name<>''"); } catch (TskCoreException | NoCurrentCaseException ex) { - logger.log(Level.INFO, "Unable to get count of files for specified mime types", ex); + logger.log(Level.WARNING, "Unable to get count of files for specified mime types", ex); //unable to get count of files for the specified mimetypes cell will be displayed as empty } } From 6b2736a4ecca670ce8490b915aa33c8a373aeef0 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Tue, 8 Jan 2019 09:18:57 -0500 Subject: [PATCH 25/30] Bug fixes and update to tests --- .../corecomponents/DataContentViewerHex.java | 4 +++- .../ExternalViewerGlobalSettingsPanel.java | 21 +++++++++++++++++-- ...ExternalViewerGlobalSettingsPanelTest.java | 13 ++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index 861076505c..db4fa74c6e 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -40,6 +40,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import static org.sleuthkit.autopsy.corecomponents.Bundle.*; +import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.DataConversion; import org.sleuthkit.datamodel.Content; @@ -368,7 +369,8 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont } String tempDirectory = Case.getCurrentCaseThrows().getTempDirectory(); - File dataSourceInTempDirectory = Paths.get(tempDirectory, dataSource.getId() + dataSource.getName()).toFile(); + File dataSourceInTempDirectory = Paths.get(tempDirectory, + FileUtil.escapeFileName(dataSource.getId() + dataSource.getName())).toFile(); ContentUtils.writeToFile(dataSource, dataSourceInTempDirectory); try { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index 704573fca9..a72a223a26 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -26,6 +26,8 @@ import java.util.List; import javax.swing.JFileChooser; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import javax.swing.JOptionPane; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; import org.openide.util.NbBundle; import org.netbeans.spi.options.OptionsPanelController; import org.sleuthkit.autopsy.casemodule.GeneralFilter; @@ -62,6 +64,12 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme private void customizeComponents(ExternalViewerGlobalSettingsTableModel tableModel) { ExternalViewerRulesTable.setModel(tableModel); ExternalViewerRulesTable.setAutoCreateRowSorter(true); + ExternalViewerRulesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + ListSelectionModel selectionModel = ExternalViewerRulesTable.getSelectionModel(); + + selectionModel.addListSelectionListener((ListSelectionEvent e) -> { + enableButtons(); + }); } /** @@ -70,9 +78,18 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme * @param selectedIndex Index to delete in JTable */ public void deleteRuleButtonClick(int selectedIndex) { - ExternalViewerRulesTable.getSelectionModel().setSelectionInterval(selectedIndex, selectedIndex); + selectRowIndex(selectedIndex); deleteRuleButton.getListeners(ActionListener.class)[0].actionPerformed(null); } + + /** + * Simulate selecting an entry in the JTable. + * + * @param rowIndex Index to select + */ + public void selectRowIndex(int rowIndex) { + ExternalViewerRulesTable.getSelectionModel().setSelectionInterval(rowIndex, rowIndex); + } /** * This method is called from within the constructor to initialize the form. @@ -359,7 +376,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme * Enable edit and delete buttons if there is a rule selected. */ boolean enableButtons() { - boolean ruleIsSelected = ExternalViewerRulesTable.getRowCount() > 0; + boolean ruleIsSelected = ExternalViewerRulesTable.getSelectedRow() >= 0; editRuleButton.setEnabled(ruleIsSelected); deleteRuleButton.setEnabled(ruleIsSelected); return ruleIsSelected; diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java index e24884e3b7..475d1cda5d 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java @@ -44,6 +44,8 @@ public class ExternalViewerGlobalSettingsPanelTest { testModel.addRule(new ExternalViewerRule("image/png", "fake.exe", RuleType.MIME)); + Assert.assertFalse(panel.enableButtons()); + panel.selectRowIndex(0); Assert.assertTrue(panel.enableButtons()); } @@ -53,6 +55,8 @@ public class ExternalViewerGlobalSettingsPanelTest { ExternalViewerGlobalSettingsPanel panel = new ExternalViewerGlobalSettingsPanel(testModel); testModel.addRule(new ExternalViewerRule("image/png", "fake.exe", RuleType.MIME)); + Assert.assertFalse(panel.enableButtons()); + panel.selectRowIndex(0); Assert.assertTrue(panel.enableButtons()); testModel.removeRule(0); @@ -66,6 +70,7 @@ public class ExternalViewerGlobalSettingsPanelTest { Assert.assertFalse(testPanel.enableButtons()); testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); + testPanel.selectRowIndex(0); Assert.assertTrue(testPanel.enableButtons()); Assert.assertEquals(1, testModel.getRowCount()); @@ -74,4 +79,12 @@ public class ExternalViewerGlobalSettingsPanelTest { Assert.assertFalse(testPanel.enableButtons()); Assert.assertEquals(0, testModel.getRowCount()); } + + @Test(expected = IndexOutOfBoundsException.class) + public void testDeleteButtonClickFail() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + ExternalViewerGlobalSettingsPanel testPanel = new ExternalViewerGlobalSettingsPanel(testModel); + + testPanel.deleteRuleButtonClick(-1); + } } From dfbfeb6ea5106ade254a8cf21a3d06e6273ce947 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Tue, 8 Jan 2019 09:31:27 -0500 Subject: [PATCH 26/30] Added a test for ensuring single selection --- .../ExternalViewerGlobalSettingsPanel.java | 18 ++++++++++++--- ...ExternalViewerGlobalSettingsPanelTest.java | 23 ++++++++++++++++--- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index a72a223a26..ef0cc08b8f 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -78,17 +78,29 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme * @param selectedIndex Index to delete in JTable */ public void deleteRuleButtonClick(int selectedIndex) { - selectRowIndex(selectedIndex); + setSelectionInterval(selectedIndex, selectedIndex); deleteRuleButton.getListeners(ActionListener.class)[0].actionPerformed(null); } /** * Simulate selecting an entry in the JTable. * + * In single selection mode, only the endIndex is used. + * * @param rowIndex Index to select */ - public void selectRowIndex(int rowIndex) { - ExternalViewerRulesTable.getSelectionModel().setSelectionInterval(rowIndex, rowIndex); + public void setSelectionInterval(int startingIndex, int endIndex) { + ExternalViewerRulesTable.getSelectionModel().setSelectionInterval(startingIndex, endIndex); + } + + /** + * Tests whether the index is selected. + * + * @param index + * @return + */ + public boolean isSelected(int index) { + return ExternalViewerRulesTable.getSelectionModel().isSelectedIndex(index); } /** diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java index 475d1cda5d..cfbc5e0cf6 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java @@ -45,7 +45,7 @@ public class ExternalViewerGlobalSettingsPanelTest { testModel.addRule(new ExternalViewerRule("image/png", "fake.exe", RuleType.MIME)); Assert.assertFalse(panel.enableButtons()); - panel.selectRowIndex(0); + panel.setSelectionInterval(0, 0); Assert.assertTrue(panel.enableButtons()); } @@ -56,7 +56,7 @@ public class ExternalViewerGlobalSettingsPanelTest { testModel.addRule(new ExternalViewerRule("image/png", "fake.exe", RuleType.MIME)); Assert.assertFalse(panel.enableButtons()); - panel.selectRowIndex(0); + panel.setSelectionInterval(0, 0); Assert.assertTrue(panel.enableButtons()); testModel.removeRule(0); @@ -70,7 +70,7 @@ public class ExternalViewerGlobalSettingsPanelTest { Assert.assertFalse(testPanel.enableButtons()); testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); - testPanel.selectRowIndex(0); + testPanel.setSelectionInterval(0, 0); Assert.assertTrue(testPanel.enableButtons()); Assert.assertEquals(1, testModel.getRowCount()); @@ -87,4 +87,21 @@ public class ExternalViewerGlobalSettingsPanelTest { testPanel.deleteRuleButtonClick(-1); } + + @Test + public void testSingleSelection() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + ExternalViewerGlobalSettingsPanel testPanel = new ExternalViewerGlobalSettingsPanel(testModel); + testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); + testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); + testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); + testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); + testModel.addRule(new ExternalViewerRule(".txt", "notepad.exe", RuleType.EXT)); + + testPanel.setSelectionInterval(0, 2); + + Assert.assertFalse(testPanel.isSelected(0)); + Assert.assertFalse(testPanel.isSelected(1)); + Assert.assertTrue(testPanel.isSelected(2)); + } } From 055f9f70b525b030f6f51dcb7897a55f1adc6621 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Tue, 8 Jan 2019 12:27:47 -0500 Subject: [PATCH 27/30] Update main.dox --- docs/doxygen-user/main.dox | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/doxygen-user/main.dox b/docs/doxygen-user/main.dox index 7a06942ab2..e22d5fb20e 100644 --- a/docs/doxygen-user/main.dox +++ b/docs/doxygen-user/main.dox @@ -4,9 +4,7 @@ Overview ----- -This is the User's Guide for the open source Autopsy platform. Autopsy allows you to examine a hard drive or mobile device and recover evidence from it. This guide should help you with using Autopsy. The developer's guide will help you develop your own Autopsy modules. - -Autopsy 4 (and 3) are a complete rewrite from Autopsy 2, and none of this document is relevant to Autopsy 2. +This is the User's Guide for the open source Autopsy platform. Autopsy allows you to examine a hard drive or mobile device and recover evidence from it. This guide should help you with using Autopsy. The developer's guide will help you develop your own Autopsy modules. Help Topics ------- From 94e4b1042af47908dd4a0b2959b3f6c3d4afc826 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Tue, 8 Jan 2019 22:56:09 -0500 Subject: [PATCH 28/30] update to quick start --- docs/doxygen-user/quick_start_guide.dox | 68 ++++++++++++++----------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/docs/doxygen-user/quick_start_guide.dox b/docs/doxygen-user/quick_start_guide.dox index 1b5cf41234..0a279244cf 100644 --- a/docs/doxygen-user/quick_start_guide.dox +++ b/docs/doxygen-user/quick_start_guide.dox @@ -1,28 +1,36 @@ /*! \page quick_start_guide Quick Start Guide -\section s1 Adding a Data Source (image, local disk, logical files) +\section s1 Cases and Data Sources -Data sources are added to a case. A case can have a single data source or it can have multiple data sources. Currently, a single report is generated for an entire case, so if you need to report on individual data sources, then you should use one data source per case. If there are many drives/phones/other data sources for one investigation, then your case should have multiple data sources. +Autopsy organizes data by case. Each case can have one or more data sources, which can be a disk image, a set of logical files, a USB-connected device, etc. -\subsection s2 Creating a Case +Cases can either be single-user or multi-user. Multi-user cases allow several examiners to review the data at the same time and collaborate, but require some additional open source servers to be configured. + +When you have several data sources and are deciding about creating creating a case, consider: +- You can have only one case open at a time +- Reports are generated at a case-level +- The application can slow down when there are many large data sources in the same case + +\subsection s1a Creating a Case To create a case, use either the "Create New Case" option on the Welcome screen or from the "Case" menu. This will start the New Case Wizard. You will need to supply it with the name of the case and a directory to store the case results into. You can optionally provide case numbers and reviewer names. -\subsection s3 Adding a Data Source +\subsection s1b Adding a Data Source The next step is to add an input data source to the case. The Add Data Source Wizard will start automatically after the case is created or you can manually start it from the "Case" menu or toolbar. You will need to choose the type of input data source to add (image, local disk, or logical files and folders). Next, supply it with the location of the source to add. - For a disk image, browse to the first file in the set (Autopsy will find the rest of the files). Autopsy currently supports E01 and raw (dd) files. -- For local disk, select one of the detected disks. Autopsy will add the current view of the disk to the case (i.e. snapshot of the meta-data). However, the individual file content (not meta-data) does get updated with the changes made to the disk. Note, you may need run Autopsy as an Administrator to detect all disks. +- For local disk, select one of the detected disks. Autopsy will add the current view of the disk to the case (i.e. snapshot of the meta-data). However, the individual file content (not meta-data) does get updated with the changes made to the disk. You can optionally create a copy of all data read from the local disk to a VHD file, which can be useful for triage situations. Note, you may need run Autopsy as an Administrator to detect all disks. - For logical files (a single file or folder of files), use the "Add" button to add one or more files or folders on your system to the case. Folders will be recursively added to the case. -There are a couple of options in the wizard that will allow you to make the ingest process faster. These typically deal with deleted files. It will take longer if unallocated space is analyzed and the entire drive is searched for deleted files. In some scenarios, these recovery steps must be performed and in other scenarios these steps are not needed and instead fast results on the allocated files are needed. Use these options to control how long the analysis will take. -Autopsy will start to analyze these data sources and add them to the case and the internal database. While it is doing that, it will prompt you to configure the Ingest Modules. +After supplying the needed data, Autopsy will quickly review the data sources and add minimal metadata to the case databases so that it can schedule the files for analysis. While it is doing that, it will prompt you to configure the Ingest Modules. -\subsection s4 Ingest Modules +\subsection s1c Ingest Modules -You will next be prompted to configure the Ingest Modules. Ingest modules will run in the background and perform specific tasks. The Ingest Modules analyze files in a prioritized order so that files in a user's directory are analyzed before files in other folders. Ingest modules can be developed by third-parties. The standard ingest modules included with Autopsy are: +Ingest modules are responsible for analyzing the data source contents and will run in the background. The Ingest Modules analyze files in a prioritized order so that files in a user's directory are analyzed before files in other folders. Ingest modules can be developed by third-parties. + +The standard ingest modules included with Autopsy are: - \subpage recent_activity_page extracts user activity as saved by web browsers and the OS. Also runs Regripper on the registry hive. - \subpage hash_db_page uses hash sets to ignore known files from the NIST NSRL and flag known bad files. Use the "Advanced" button to add and configure the hash sets to use during this process. You will get updates on known bad file hits as the ingest occurs. You can later add hash sets via the Tools -> Options menu in the main UI. You can download an index of the NIST NSRL from http://sourceforge.net/projects/autopsy/files/NSRL/ @@ -36,7 +44,7 @@ You will next be prompted to configure the Ingest Modules. Ingest modules will r - \subpage android_analyzer_page allows you to parse common items from Android devices. Places artifacts into the BlackBoard. - \subpage interesting_files_identifier_page searches for files and directories based on user-specified rules in Tools, Options, Interesting Files. It works as a "File Alerting Module". It generates messages in the inbox when specified files are found. - \subpage photorec_carver_page carves files from unallocated space and sends them through the file processing chain. -- \subpage cr_ingest_module adds file hashes and other extracted properties to a central repository. +- \subpage cr_ingest_module adds file hashes and other extracted properties to a central repository for future correlation and to flag previously notable files. - \subpage encryption_page looks for encrypted files. - \subpage vm_extractor_page extracts data from virtual machine files @@ -44,7 +52,9 @@ When you select a module, you will have the option to change its settings. For While ingest modules are running in the background, you will see a progress bar in the lower right. You can use the GUI to review incoming results and perform other tasks while ingesting at the same time. -\section s1a Analysis Basics +\section s2 Analysis Basics + +After the ingest modules start to analyze the data source, you'll see the main analysis interface. You can choose to search for specific items, browse to specific folders, or review ingest module results. \image html screenshot.PNG @@ -53,7 +63,7 @@ You will start all of your analysis techniques from the tree on the left. - The Data Sources root node shows all data in the case. - The individual image nodes show the file system structure of the disk images or local disks in the case. - The LogicalFileSet nodes show the logical files in the case. -- The Views node shows the same data from a file type or timeline perspective. +- The Views node shows the same data from a different perspective, such as organized by file type. - The Results node shows the output from the ingest modules. When you select a node from the tree on the left, a list of files will be shown in the upper right. You can use the Thumbnail view in the upper right to view the pictures. When you select a file from the upper right, its contents will be shown in the lower right. You can use the tabs in the lower right to view the text of the file, an image, or the hex data. @@ -66,23 +76,23 @@ The tree on the left as well as the table on the right have a \ref ui_quick_sear You can tag (bookmark) arbitrary files so that you can more quickly find them later or so that you can include them specifically in a report. -\subsection s2a Ingest Inbox -As you are going through the results in the tree, the ingest modules are running in the background. -The results are shown in the tree as soon as the ingest modules find them and report them. +\section s3 Other Analysis Interfaces -The Ingest Inbox receives messages from the ingest modules as they find results. -You can open the inbox to see what has been recently found. -It keeps track of what messages you have read. +In addition to the 3-panel UI with the tree on the left, there are other interfaces that are more specialized. -The intended use of this inbox is that you can focus on some data for a while and then check back on the inbox at a time that is convenient for them. -You can then see what else was found while you were focused on the previous task. -You may learn that a known bad file was found or that a file was found with a relevant keyword and then decide to focus on that for a while. +\subsection s3a Timeline -When you select a message, you can then jump to the Results tree where more details can be found or jump to the file's location in the filesystem. +The timeline feature can be opened from the "Tools" menu or the toolbar. This will show you file system and other events organized by time using various display techniques. See the \subpage timeline_page section for more details. -\subsection s2b Timeline -There is a basic timeline view that you can access via the "Tools", "Make Timeline" feature. This will take a few minutes to create the timeline for analysis. Its features are still in development. + +\subsection s3b Image Gallery + +The Image Gallery focuses on showing the pictures and videos from the data source organized by folder. It will show you files as soon as they have been hashed and EXIF data extracted. You can open it from the "Tools" menu. See the \subpage image_gallery_page section for more details. + +\subsection s3c Communications + +The Communications interface focuses on showing which accounts were communicated with the most and what messages were sent. It allows you to focus on certain relationships or communications within a certain date rage. You can open it from the "Tools" menu. See the \subpage communications_page section for more details. \section s5 Example Use Cases @@ -110,16 +120,14 @@ If you want to see all images and video on the disk image, then go to the " Select either "Images" or "Videos". You can use the thumbnail option in the upper right to view thumbnails of all images. -Note: We are working on making this more efficient when there are lots of images. We are also working on the feature to display video thumbnails. You can select an image or video from the upper right and view the video or image in the lower right. Video will be played with sound. \section s6 Reporting -A final report can be generated that will include all analysis results. -Use the "Generate Report" button to create this. -It will create an HTML or XLS report in the Reports folder of the case folder. -If you forgot the location of your case folder, you can determine it using the "Case Properties" option in the "Case" menu. -There is also an option to export report files to a separate folder outside of the case folder. +A final report can be generated that will include all analysis results using the "Generate Report" toolbar button. Reports can be generated in HTML, XLS, KML, and other formats. + +You can later find your generated reports by going to the tree and opening the Reports node at the bottom. + */ \ No newline at end of file From 1756c1e0b74165107fbaa657a99defdcf2a867fc Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 10 Jan 2019 10:27:53 -0500 Subject: [PATCH 29/30] Changed the public API methods to be more generic --- .../org/sleuthkit/autopsy/core/UserPreferences.java | 11 +++++------ .../autopsy/corecomponents/DataContentViewerHex.java | 2 +- .../ExternalViewerGlobalSettingsPanel.java | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index f96cd05969..332a6d7ca7 100644 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -39,7 +39,6 @@ import org.sleuthkit.datamodel.TskData.DbType; */ public final class UserPreferences { - private static final boolean IS_WINDOWS_OS = PlatformUtil.isWindowsOS(); private static final Preferences preferences = NbPreferences.forModule(UserPreferences.class); public static final String KEEP_PREFERRED_VIEWER = "KeepPreferredViewer"; // NON-NLS public static final String HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE = "HideKnownFilesInDataSourcesTree"; //NON-NLS @@ -76,7 +75,7 @@ public final class UserPreferences { public static final String SHOW_ONLY_CURRENT_USER_TAGS = "ShowOnlyCurrentUserTags"; public static final String HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES = "HideCentralRepoCommentsAndOccurrences"; public static final String DISPLAY_TRANSLATED_NAMES = "DisplayTranslatedNames"; - public static final String HDX_EDITOR_PATH = "HdXEditorPath"; + public static final String EXTERNAL_HEX_EDITOR_PATH = "ExternalHexEditorPath"; // Prevent instantiation. private UserPreferences() { @@ -479,8 +478,8 @@ public final class UserPreferences { * * @param executablePath User-inputted path to HxD executable */ - public static void setHdXEditorPath(String executablePath) { - preferences.put(HDX_EDITOR_PATH, executablePath); + public static void setExternalHexEditorPath(String executablePath) { + preferences.put(EXTERNAL_HEX_EDITOR_PATH, executablePath); } /** @@ -489,7 +488,7 @@ public final class UserPreferences { * * @return Path to HdX */ - public static String getHdXEditorPath() { - return preferences.get(HDX_EDITOR_PATH, Paths.get("C:", "Program Files", "HxD", "HxD.exe").toString()); + public static String getExternalHexEditorPath() { + return preferences.get(EXTERNAL_HEX_EDITOR_PATH, Paths.get("C:", "Program Files", "HxD", "HxD.exe").toString()); } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index db4fa74c6e..82c7df497a 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -362,7 +362,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont + "Please set-up the HdX install location in Tools -> Options -> External Viewer"}) private void launchHxDButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_launchHxDButtonActionPerformed try { - File HdXExecutable = new File(UserPreferences.getHdXEditorPath()); + File HdXExecutable = new File(UserPreferences.getExternalHexEditorPath()); if(!HdXExecutable.exists() || !HdXExecutable.canExecute()) { JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError()); return; diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index ef0cc08b8f..2d5439cf69 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -362,7 +362,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme rules.add(tableModel.getRuleAt(i)); } ExternalViewerRulesManager.getInstance().setUserRules(rules); - UserPreferences.setHdXEditorPath(HxDPath.getText()); + UserPreferences.setExternalHexEditorPath(HxDPath.getText()); } @Override @@ -373,7 +373,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme tableModel.addRule(rule); } } - String editorPath = UserPreferences.getHdXEditorPath(); + String editorPath = UserPreferences.getExternalHexEditorPath(); File HdXExecutable = new File(editorPath); if(HdXExecutable.exists() || HdXExecutable.canExecute()) { HxDPath.setText(editorPath); From 35408cfcf35132729ae90aca2a5943abd3b68a28 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 10 Jan 2019 10:59:51 -0500 Subject: [PATCH 30/30] Small codacy suggestion --- .../directorytree/ExternalViewerGlobalSettingsPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index 2d5439cf69..0cfbd7d5e5 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -67,7 +67,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme ExternalViewerRulesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); ListSelectionModel selectionModel = ExternalViewerRulesTable.getSelectionModel(); - selectionModel.addListSelectionListener((ListSelectionEvent e) -> { + selectionModel.addListSelectionListener((ListSelectionEvent selection) -> { enableButtons(); }); }