From ccf2a66c8197adf36e178e00e6e850fdc6e93aee Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 11 Mar 2021 12:51:28 -0500 Subject: [PATCH] bug fixes --- .../AddEditCategoryDialog.java | 4 +- .../Bundle.properties-MERGED | 3 +- .../WebCategoriesDataModel.java | 5 +- .../WebCategoriesOptionsPanel.form | 71 +++++---- .../WebCategoriesOptionsPanel.java | 140 +++++++++++++----- 5 files changed, 146 insertions(+), 77 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/AddEditCategoryDialog.java b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/AddEditCategoryDialog.java index 65017ffad0..7f1fdff3bf 100644 --- a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/AddEditCategoryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/AddEditCategoryDialog.java @@ -154,8 +154,8 @@ class AddEditCategoryDialog extends javax.swing.JDialog { validationMessage = Bundle.AddEditCategoryDialog_onValueUpdate_badCategory(WebCategoriesDataModel.getMaxCategoryLength()); } else if (currentSuffixes.contains(normalizedSuffix) && - currentDomainCategory != null && - !normalizedSuffix.equals(currentDomainCategory.getHostSuffix())) { + (currentDomainCategory == null || + !normalizedSuffix.equals(currentDomainCategory.getHostSuffix()))) { validationMessage = Bundle.AddEditCategoryDialog_onValueUpdate_suffixRepeat(); diff --git a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/Bundle.properties-MERGED index 945213e4a4..cfa7939abf 100644 --- a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/Bundle.properties-MERGED @@ -1,13 +1,14 @@ AddEditCategoryDialog_Add=Add Entry AddEditCategoryDialog_Edit=Edit Entry # {0} - maxCategoryLen -AddEditCategoryDialog_onValueUpdate_badCategory=Please provide a domain suffix that is no more than {0} characters. +AddEditCategoryDialog_onValueUpdate_badCategory=Please provide a category that is no more than {0} characters. # {0} - maxSuffixLen AddEditCategoryDialog_onValueUpdate_badSuffix=Please provide a domain suffix that is no more than {0} characters. AddEditCategoryDialog_onValueUpdate_sameCategory=Please provide a new category for this domain suffix. AddEditCategoryDialog_onValueUpdate_suffixRepeat=Please provide a unique domain suffix. WebCategoriesOptionsPanel_categoryTable_categoryColumnName=Category WebCategoriesOptionsPanel_categoryTable_suffixColumnName=Domain Suffix +WebCategoriesOptionsPanel_exportSetButtonActionPerformed_defaultFileName=Custom Categories Export WebCategoriesOptionsPanel_exportSetButtonActionPerformed_errorMessage=There was an error exporting. WebCategoriesOptionsPanel_exportSetButtonActionPerformed_errorTitle=Export Error WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorMessage=There was an error importing this json file. diff --git a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesDataModel.java b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesDataModel.java index 5852a6535e..2912018c85 100644 --- a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesDataModel.java +++ b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesDataModel.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.url.analytics.domaincategorization; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.type.TypeReference; @@ -81,6 +82,7 @@ class WebCategoriesDataModel implements AutoCloseable { * * @return The category. */ + @JsonGetter("category") String getCategory() { return category; } @@ -90,6 +92,7 @@ class WebCategoriesDataModel implements AutoCloseable { * * @return The list of domain suffixes in this category. */ + @JsonGetter("domains") List getDomains() { return domains; } @@ -278,7 +281,7 @@ class WebCategoriesDataModel implements AutoCloseable { String categoryStr = getNormalizedCategory(category.getCategory()); - for (int listIdx = 0; listIdx < category.getDomains().size(); i++) { + for (int listIdx = 0; listIdx < category.getDomains().size(); listIdx++) { String domain = category.getDomains().get(listIdx); if (domain == null) { logger.log(Level.WARNING, String.format("Could not process domain at idx: %d in category %s for file %s", diff --git a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesOptionsPanel.form index a6a3670fe7..5cead0d5a8 100644 --- a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesOptionsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesOptionsPanel.form @@ -18,6 +18,7 @@ + @@ -40,7 +41,7 @@ - + @@ -60,6 +61,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -71,7 +98,7 @@ - + @@ -86,7 +113,7 @@ - + @@ -116,7 +143,7 @@ - + @@ -136,28 +163,9 @@ - - - - - - - - - - - - - - - - - - - - + @@ -166,22 +174,11 @@ - + - - - - - - - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesOptionsPanel.java index 6ef0426f90..e5a32860f3 100644 --- a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesOptionsPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.url.analytics.domaincategorization; +import java.awt.Cursor; import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; @@ -32,6 +33,7 @@ import java.util.stream.Collectors; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; import javax.swing.filechooser.FileNameExtensionFilter; import org.openide.util.NbBundle.Messages; import org.openide.util.WeakListeners; @@ -94,6 +96,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i fileChooser.setFileFilter(DB_FILTER); categoryTable.setCellListener((evt) -> refreshComponentStates()); IngestManager.getInstance().addIngestJobEventListener(weakIngestListener); + setDefaultCursor(); refresh(); } @@ -154,15 +157,17 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i newEntryButton.setEnabled(operationsPermitted); exportSetButton.setEnabled(operationsPermitted); importSetButton.setEnabled(operationsPermitted); - ingestRunningWarning.setEnabled(operationsPermitted); - + ingestRunningWarning.setVisible(isIngestRunning); } /** - * Shows the AddEditCategoryDialog to the user and returns the user-inputted DomainCategory or null if nothing was saved. - * @param original If editing a value, this is the original value being edited. If adding a new value, this should be null. - * @return + * Shows the AddEditCategoryDialog to the user and returns the user-inputted + * DomainCategory or null if nothing was saved. + * + * @param original If editing a value, this is the original value being + * edited. If adding a new value, this should be null. + * @return */ private DomainCategory getAddEditValue(DomainCategory original) { JFrame parent = (this.getRootPane() != null && this.getRootPane().getParent() instanceof JFrame) @@ -182,6 +187,51 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i } } + /** + * Set cursor to waiting. + */ + private void setWaitingCursor() { + SwingUtilities.invokeLater(() -> this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))); + } + + /** + * Set cursor to default. + */ + private void setDefaultCursor() { + SwingUtilities.invokeLater(() -> this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR))); + } + + /** + * An action for updating or altering data in the custom configuration. + */ + private interface UpdateAction { + + /** + * A runnable action to update custom configuration. + * + * @throws IllegalArgumentException + * @throws IOException + * @throws SQLException + */ + void run() throws IllegalArgumentException, IOException, SQLException; + } + + /** + * Runs an action to update the state of the configuration and runs refresh + * when complete. + * + * @param runnable The runnable action. + * @throws IllegalArgumentException + * @throws IOException + * @throws SQLException + */ + private void runUpdateAction(UpdateAction runnable) throws IllegalArgumentException, IOException, SQLException { + setWaitingCursor(); + runnable.run(); + setDefaultCursor(); + refresh(); + } + /** * 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 @@ -194,23 +244,23 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i javax.swing.JLabel panelDescription = new javax.swing.JLabel(); javax.swing.JLabel categoriesTitle = new javax.swing.JLabel(); + javax.swing.JPanel categoryTablePanel = categoryTable; newEntryButton = new javax.swing.JButton(); editEntryButton = new javax.swing.JButton(); deleteEntryButton = new javax.swing.JButton(); importSetButton = new javax.swing.JButton(); exportSetButton = new javax.swing.JButton(); javax.swing.JPanel bottomStrut = new javax.swing.JPanel(); - javax.swing.JScrollPane tableScrollPane = new javax.swing.JScrollPane(); - javax.swing.JPanel categoryTablePanel = categoryTable; ingestRunningWarning = new javax.swing.JLabel(); setLayout(new java.awt.GridBagLayout()); + panelDescription.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); panelDescription.setText(org.openide.util.NbBundle.getMessage(WebCategoriesOptionsPanel.class, "WebCategoriesOptionsPanel.panelDescription.text")); // NOI18N panelDescription.setBorder(javax.swing.BorderFactory.createCompoundBorder(javax.swing.BorderFactory.createEtchedBorder(), javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5))); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridwidth = 3; - gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 0); add(panelDescription, gridBagConstraints); @@ -224,6 +274,19 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0); add(categoriesTitle, gridBagConstraints); + categoryTablePanel.setAutoscrolls(true); + categoryTablePanel.setMaximumSize(new java.awt.Dimension(400, 32767)); + categoryTablePanel.setMinimumSize(new java.awt.Dimension(400, 300)); + categoryTablePanel.setPreferredSize(new java.awt.Dimension(400, 600)); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 2; + gridBagConstraints.gridwidth = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.weighty = 1.0; + gridBagConstraints.insets = new java.awt.Insets(2, 10, 10, 0); + add(categoryTablePanel, gridBagConstraints); + newEntryButton.setText(org.openide.util.NbBundle.getMessage(WebCategoriesOptionsPanel.class, "WebCategoriesOptionsPanel.newEntryButton.text")); // NOI18N newEntryButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -233,6 +296,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 10, 5, 5); add(newEntryButton, gridBagConstraints); @@ -246,6 +310,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5); add(editEntryButton, gridBagConstraints); @@ -272,6 +337,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 10, 5, 5); add(importSetButton, gridBagConstraints); @@ -288,27 +354,15 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5); add(exportSetButton, gridBagConstraints); + + bottomStrut.setPreferredSize(new java.awt.Dimension(10, 0)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 6; - gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; - gridBagConstraints.weighty = 1.0; add(bottomStrut, gridBagConstraints); - tableScrollPane.setMaximumSize(new java.awt.Dimension(325, 32767)); - tableScrollPane.setMinimumSize(new java.awt.Dimension(500, 300)); - tableScrollPane.setPreferredSize(new java.awt.Dimension(500, 400)); - tableScrollPane.setViewportView(categoryTablePanel); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 2; - gridBagConstraints.gridwidth = 3; - gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - gridBagConstraints.insets = new java.awt.Insets(2, 10, 5, 0); - add(tableScrollPane, gridBagConstraints); - ingestRunningWarning.setForeground(java.awt.Color.RED); ingestRunningWarning.setText(org.openide.util.NbBundle.getMessage(WebCategoriesOptionsPanel.class, "WebCategoriesOptionsPanel.ingestRunningWarning.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); @@ -324,9 +378,9 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i DomainCategory selected = getSelected(); if (selected != null && selected.getHostSuffix() != null) { try { - dataModel.deleteRecord(selected.getHostSuffix()); - refresh(); - } catch (IllegalArgumentException | SQLException ex) { + runUpdateAction(() -> dataModel.deleteRecord(selected.getHostSuffix())); + } catch (IllegalArgumentException | SQLException | IOException ex) { + setDefaultCursor(); logger.log(Level.WARNING, "There was an error while deleting: " + selected.getHostSuffix(), ex); } } @@ -336,9 +390,9 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i DomainCategory newCategory = getAddEditValue(null); if (newCategory != null) { try { - dataModel.insertUpdateSuffix(newCategory); - refresh(); - } catch (IllegalArgumentException | SQLException ex) { + runUpdateAction(() -> dataModel.insertUpdateSuffix(newCategory)); + } catch (IllegalArgumentException | SQLException | IOException ex) { + setDefaultCursor(); logger.log(Level.WARNING, "There was an error while adding new record: " + newCategory.getHostSuffix(), ex); } } @@ -350,10 +404,10 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i try { DomainCategory newCategory = getAddEditValue(selected); if (newCategory != null) { - dataModel.insertUpdateSuffix(newCategory); - refresh(); + runUpdateAction(() -> dataModel.insertUpdateSuffix(newCategory)); } - } catch (IllegalArgumentException | SQLException ex) { + } catch (IllegalArgumentException | SQLException | IOException ex) { + setDefaultCursor(); logger.log(Level.WARNING, "There was an error while editing: " + selected.getHostSuffix(), ex); } } @@ -363,14 +417,15 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i "WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorMessage=There was an error importing this json file.", "WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorTitle=Import Error",}) private void importSetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importSetButtonActionPerformed + fileChooser.setSelectedFile(null); int result = fileChooser.showOpenDialog(this); if (result == JFileChooser.APPROVE_OPTION) { File selectedFile = fileChooser.getSelectedFile(); if (selectedFile != null && selectedFile.exists()) { try { - dataModel.importJson(selectedFile); - refresh(); - } catch (SQLException | IOException ex) { + runUpdateAction(() -> dataModel.importJson(selectedFile)); + } catch (IllegalArgumentException | SQLException | IOException ex) { + setDefaultCursor(); JOptionPane.showMessageDialog( this, Bundle.WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorMessage(), @@ -384,15 +439,28 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i @Messages({ "WebCategoriesOptionsPanel_exportSetButtonActionPerformed_errorMessage=There was an error exporting.", - "WebCategoriesOptionsPanel_exportSetButtonActionPerformed_errorTitle=Export Error",}) + "WebCategoriesOptionsPanel_exportSetButtonActionPerformed_errorTitle=Export Error", + "WebCategoriesOptionsPanel_exportSetButtonActionPerformed_defaultFileName=Custom Categories Export" + }) private void exportSetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportSetButtonActionPerformed + fileChooser.setSelectedFile(new File(String.format("%s.json", Bundle.WebCategoriesOptionsPanel_exportSetButtonActionPerformed_defaultFileName()))); int result = fileChooser.showSaveDialog(this); if (result == JFileChooser.APPROVE_OPTION) { File selectedFile = fileChooser.getSelectedFile(); if (selectedFile != null) { + if (selectedFile.exists()) { + JOptionPane.showMessageDialog( + this, + Bundle.WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorMessage(), + Bundle.WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorTitle(), + JOptionPane.ERROR); + } try { + setWaitingCursor(); dataModel.exportToJson(selectedFile); + setDefaultCursor(); } catch (SQLException | IOException ex) { + setDefaultCursor(); JOptionPane.showMessageDialog( this, Bundle.WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorMessage(),