diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index 2be9a9b447..332a6d7ca7 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; @@ -38,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 @@ -75,6 +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 EXTERNAL_HEX_EDITOR_PATH = "ExternalHexEditorPath"; // Prevent instantiation. private UserPreferences() { @@ -471,4 +472,23 @@ public final class UserPreferences { public static void setLogFileCount(int count) { preferences.putInt(MAX_NUM_OF_LOG_FILE, count); } + + /** + * Set the HdX path. + * + * @param executablePath User-inputted path to HxD executable + */ + public static void setExternalHexEditorPath(String executablePath) { + preferences.put(EXTERNAL_HEX_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 Path to HdX + */ + 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/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 299b0e18d4..d91a751a1a 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -193,3 +193,34 @@ 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 +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.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form index 745c862756..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 @@ - + @@ -120,7 +120,9 @@ - + + + @@ -140,7 +142,10 @@ - + + + + @@ -289,6 +294,19 @@ + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index 6639856099..82c7df497a 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -21,7 +21,11 @@ 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.sleuthkit.autopsy.coreutils.PlatformUtil; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; @@ -31,7 +35,13 @@ import javax.swing.text.BadLocationException; import javax.swing.text.Utilities; 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 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; import org.sleuthkit.datamodel.TskException; @@ -105,6 +115,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 +198,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 +232,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(146, Short.MAX_VALUE)) ); hexViewerPanelLayout.setVerticalGroup( hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -231,17 +251,21 @@ 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)) ); + 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, 100, 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( @@ -249,7 +273,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, 239, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -334,6 +358,37 @@ 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.getExternalHexEditorPath()); + if(!HdXExecutable.exists() || !HdXExecutable.canExecute()) { + JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError()); + return; + } + + String tempDirectory = Case.getCurrentCaseThrows().getTempDirectory(); + File dataSourceInTempDirectory = Paths.get(tempDirectory, + FileUtil.escapeFileName(dataSource.getId() + dataSource.getName())).toFile(); + ContentUtils.writeToFile(dataSource, dataSourceInTempDirectory); + + try { + ProcessBuilder launchHdXExecutable = new ProcessBuilder(); + launchHdXExecutable.command(String.format("\"%s\" \"%s\"", + HdXExecutable.getAbsolutePath(), + dataSourceInTempDirectory.getAbsolutePath())); + launchHdXExecutable.start(); + } catch (IOException ex) { + JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError()); + dataSourceInTempDirectory.delete(); + } + } catch (NoCurrentCaseException | IOException ex) { + logger.log(Level.SEVERE, "Unable to copy file into temp directory", ex); + JOptionPane.showMessageDialog(null, DataContentViewerHex_launchError()); + } + }//GEN-LAST:event_launchHxDButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JMenuItem copyMenuItem; private javax.swing.JLabel currentPageLabel; @@ -344,6 +399,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; @@ -504,6 +560,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont goToPageLabel.setVisible(isVisible); goToOffsetTextField.setVisible(isVisible); goToOffsetLabel.setVisible(isVisible); + launchHxDButton.setVisible(isVisible); } @Override @@ -528,17 +585,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); - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties index 26c970b2b3..c1939adf6c 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,16 @@ 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=Add your custom rules for external viewers: +ExternalViewerGlobalSettingsPanel.newRuleButton.text=New Rule +ExternalViewerGlobalSettingsPanel.jButton2.text=jButton2 +ExternalViewerGlobalSettingsPanel.browseHxDDirectory.text=Browse +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 e04dc19270..fde8a99209 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,251 @@ - - - - - - - - - - + + + + + + + + - - - - - - - - - - + + + + + - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + <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.ExternalViewerRulesTable.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..0cfbd7d5e5 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. @@ -18,16 +18,21 @@ */ 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.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 java.util.List; +import javax.swing.JFileChooser; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; -import org.sleuthkit.autopsy.coreutils.Logger; +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; +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 @@ -37,39 +42,67 @@ 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 java.util.List rules; + private ExternalViewerGlobalSettingsTableModel tableModel; + public ExternalViewerGlobalSettingsPanel() { + this(new ExternalViewerGlobalSettingsTableModel(new String[] { + "Mime type/Extension", "Application"})); + } + /** * Creates new form ExternalViewerGlobalSettingsPanel */ - public ExternalViewerGlobalSettingsPanel() { + 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() { - 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(); - } - } - } + private void customizeComponents(ExternalViewerGlobalSettingsTableModel tableModel) { + ExternalViewerRulesTable.setModel(tableModel); + ExternalViewerRulesTable.setAutoCreateRowSorter(true); + ExternalViewerRulesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + ListSelectionModel selectionModel = ExternalViewerRulesTable.getSelectionModel(); + + selectionModel.addListSelectionListener((ListSelectionEvent selection) -> { + enableButtons(); }); } - + + /** + * Simulate the delete rule button click action. + * + * @param selectedIndex Index to delete in JTable + */ + public void deleteRuleButtonClick(int 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 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); + } + /** * 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 @@ -79,60 +112,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(); + ExternalViewerRulesTable = 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(); + HxDPath = new javax.swing.JTextField(); + 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 + 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 +149,26 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme } }); + jScrollPane4.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(204, 204, 204))); + + 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 + + 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,91 +179,112 @@ 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); + HxDPath.setEditable(false); - jScrollPane1.setViewportView(jSplitPane1); + org.openide.awt.Mnemonics.setLocalizedText(HxDLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.HxDLabel.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() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseHxDDirectoryActionPerformed(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(ContentViewerExtensionLabel) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(jPanel3Layout.createSequentialGroup() + .addGap(21, 21, 21) + .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) + .addComponent(browseHxDDirectory, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .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(HxDLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseHxDDirectory)) + .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( 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 @@ -247,16 +294,13 @@ 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); - updateRulesListModel(); - int index = rules.indexOf(newRule); - rulesList.setSelectedIndex(index); + tableModel.addRule(newRule); enableButtons(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } @@ -264,113 +308,107 @@ 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())); + int selectedIndex = ExternalViewerRulesTable.convertRowIndexToModel(ExternalViewerRulesTable.getSelectedRow()); + ExternalViewerRule selectedRule = tableModel.getRuleAt(selectedIndex); + AddExternalViewerRuleDialog dialog = new AddExternalViewerRuleDialog(selectedRule); 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)) { + 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(selected, dialog.getRule()); - updateRulesListModel(); + tableModel.setRule(selectedIndex, dialog.getRule()); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } } - rulesList.setSelectedIndex(selected); - enableButtons(); }//GEN-LAST:event_editRuleButtonActionPerformed private void deleteRuleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteRuleButtonActionPerformed - ExternalViewerRule rule = rulesList.getSelectedValue(); - rules.remove(rule); - updateRulesListModel(); + tableModel.removeRule(ExternalViewerRulesTable.convertRowIndexToModel(ExternalViewerRulesTable.getSelectedRow())); + ExternalViewerRulesTable.getSelectionModel().clearSelection(); + enableButtons(); 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() { + //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.setExternalHexEditorPath(HxDPath.getText()); } @Override public void load() { - rules = ExternalViewerRulesManager.getInstance().getUserRules(); - updateRulesListModel(); + List rules = ExternalViewerRulesManager.getInstance().getUserRules(); + for(ExternalViewerRule rule : rules) { + if(!tableModel.containsRule(rule)) { + tableModel.addRule(rule); + } + } + String editorPath = UserPreferences.getExternalHexEditorPath(); + File HdXExecutable = new File(editorPath); + if(HdXExecutable.exists() || HdXExecutable.canExecute()) { + HxDPath.setText(editorPath); + } else { + HxDPath.setForeground(Color.RED); + HxDPath.setText(editorPath); + } enableButtons(); } /** * Enable edit and delete buttons if there is a rule selected. */ - private void enableButtons() { - boolean ruleIsSelected = rulesList.getSelectedIndex() != -1; + boolean enableButtons() { + boolean ruleIsSelected = ExternalViewerRulesTable.getSelectedRow() >= 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 updateRulesListModel() { - rulesListModel.clear(); - 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(); + 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.JPanel exePanel; - private javax.swing.JLabel exePathLabel; - private javax.swing.JLabel exePathNameLabel; private javax.swing.JLabel externalViewerTitleLabel; + private javax.swing.JButton jButton2; 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.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 } 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..5662e0cd84 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModel.java @@ -0,0 +1,166 @@ +/* + * 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.Arrays; +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 { + + private final List rules; + private final String[] columnNames; + + public ExternalViewerGlobalSettingsTableModel(String... columnNames) { + this.columnNames = Arrays.copyOf(columnNames, columnNames.length); + 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) { + return rules.get(rowIndex).getName(); + } else { + return rules.get(rowIndex).getExePath(); + } + } + + /** + * 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; + } + + /** + * 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/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); } 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; 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..cfbc5e0cf6 --- /dev/null +++ b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanelTest.java @@ -0,0 +1,107 @@ +/* + * 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; + +/** + * 72% code coverage of ExternalViewerGlobalSettingsPanel + */ +public class ExternalViewerGlobalSettingsPanelTest { + + static final String[] testColumnNames = {"A", "B"}; + + /** + * Default constructor for JUnit + */ + public ExternalViewerGlobalSettingsPanelTest(){ + //Codacy complains if there is no comment here + } + + @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.assertFalse(panel.enableButtons()); + panel.setSelectionInterval(0, 0); + 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.assertFalse(panel.enableButtons()); + panel.setSelectionInterval(0, 0); + 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)); + testPanel.setSelectionInterval(0, 0); + Assert.assertTrue(testPanel.enableButtons()); + Assert.assertEquals(1, testModel.getRowCount()); + + testPanel.deleteRuleButtonClick(0); + + 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); + } + + @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)); + } +} 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..72118c7e3e --- /dev/null +++ b/Core/test/unit/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsTableModelTest.java @@ -0,0 +1,217 @@ +/* + * 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.Before; +import org.junit.Test; +import org.sleuthkit.autopsy.directorytree.ExternalViewerRule.RuleType; + +/** + * 100% code coverage of ExternalViewerGlobalSettingsTableModel + */ +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); + } + + /** + * Test of addRule method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testAddRule() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + testModel.addRule(pngMime); + + Assert.assertEquals(1, testModel.getRowCount()); + + ExternalViewerRule rule = testModel.getRuleAt(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(pngMime); + testModel.addRule(txtExt); + testModel.addRule(wavExt); + + 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(pngMime); + testModel.addRule(txtExt); + testModel.addRule(wavExt); + + 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(pngMime); + testModel.addRule(txtExt); + testModel.addRule(wavExt); + + 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(pngMime); + testModel.addRule(txtExt); + testModel.addRule(wavExt); + + 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, pngMime); + 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); + testModel.addRule(pngMime); + Assert.assertEquals(1, testModel.getRowCount()); + + testModel.removeRule(0); + Assert.assertEquals(0, testModel.getRowCount()); + Assert.assertFalse(testModel.containsRule(pngMime)); + } + + /** + * Test of isCellEditable method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testIsCellEditable() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + Assert.assertFalse(testModel.isCellEditable(0, 0)); + } + + /** + * Test of containsRule method, of class ExternalViewerGlobalSettingsTableModel. + */ + @Test + public void testContainsRule() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + testModel.addRule(pngMime); + Assert.assertTrue(testModel.containsRule(pngMime)); + } + + @Test + public void testNotContains() { + ExternalViewerGlobalSettingsTableModel testModel = new ExternalViewerGlobalSettingsTableModel(testColumnNames); + testModel.addRule(pngMime); + Assert.assertFalse(testModel.containsRule(new ExternalViewerRule("not", "a rule", RuleType.EXT))); + Assert.assertFalse(testModel.containsRule(null)); + } +} \ No newline at end of file