diff --git a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/AddEditCategoryDialog.form b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/AddEditCategoryDialog.form index f757d05f25..08f9a45535 100644 --- a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/AddEditCategoryDialog.form +++ b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/AddEditCategoryDialog.form @@ -26,24 +26,24 @@ - + + + + + + + - - - + + + - - - - - - @@ -53,39 +53,31 @@ - - - - - - - - - - + + + - - + + + + + + + - + - - - - - - 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 54135baf14..65017ffad0 100644 --- a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/AddEditCategoryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/AddEditCategoryDialog.java @@ -19,6 +19,8 @@ package org.sleuthkit.autopsy.url.analytics.domaincategorization; import java.util.Set; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.url.analytics.DomainCategory; @@ -35,6 +37,23 @@ class AddEditCategoryDialog extends javax.swing.JDialog { private final Set currentSuffixes; private final DomainCategory currentDomainCategory; + // listens for document updates + private final DocumentListener updateListener = new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + onValueUpdate(domainSuffixTextField.getText(), categoryTextField.getText()); + } + + @Override + public void removeUpdate(DocumentEvent e) { + onValueUpdate(domainSuffixTextField.getText(), categoryTextField.getText()); + } + + @Override + public void changedUpdate(DocumentEvent e) { + onValueUpdate(domainSuffixTextField.getText(), categoryTextField.getText()); + } + }; /** * Main constructor if adding a new domain suffix. * @@ -58,6 +77,8 @@ class AddEditCategoryDialog extends javax.swing.JDialog { initComponents(); this.currentSuffixes = currentSuffixes; this.currentDomainCategory = currentDomainCategory; + + // set title based on whether or not we are editing or adding // also don't allow editing of domain suffix if editing @@ -65,11 +86,18 @@ class AddEditCategoryDialog extends javax.swing.JDialog { setTitle(Bundle.AddEditCategoryDialog_Add()); domainSuffixTextField.setEditable(true); domainSuffixTextField.setEnabled(true); + onValueUpdate(null, null); } else { setTitle(Bundle.AddEditCategoryDialog_Edit()); domainSuffixTextField.setEditable(false); domainSuffixTextField.setEnabled(false); + onValueUpdate(currentDomainCategory.getHostSuffix(), currentDomainCategory.getCategory()); } + + validationLabel.setText(""); + + categoryTextField.getDocument().addDocumentListener(updateListener); + domainSuffixTextField.getDocument().addDocumentListener(updateListener); } /** @@ -100,12 +128,13 @@ class AddEditCategoryDialog extends javax.swing.JDialog { "# {0} - maxSuffixLen", "AddEditCategoryDialog_onValueUpdate_badSuffix=Please provide a domain suffix that is no more than {0} characters.", "# {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.", "AddEditCategoryDialog_onValueUpdate_suffixRepeat=Please provide a unique domain suffix.", "AddEditCategoryDialog_onValueUpdate_sameCategory=Please provide a new category for this domain suffix.",}) void onValueUpdate(String suffixStr, String categoryStr) { String safeSuffixStr = suffixStr == null ? "" : suffixStr; + String normalizedSuffix = WebCategoriesDataModel.getNormalizedSuffix(safeSuffixStr); String safeCategoryStr = categoryStr == null ? "" : categoryStr; // update input text field if it is not the same. @@ -122,9 +151,12 @@ class AddEditCategoryDialog extends javax.swing.JDialog { validationMessage = Bundle.AddEditCategoryDialog_onValueUpdate_badSuffix(WebCategoriesDataModel.getMaxCategoryLength()); } else if (safeCategoryStr.trim().length() == 0 || safeCategoryStr.trim().length() > WebCategoriesDataModel.getMaxCategoryLength()) { - validationMessage = Bundle.AddEditCategoryDialog_onValueUpdate_badCategory(WebCategoriesDataModel.getMaxDomainSuffixLength()); + validationMessage = Bundle.AddEditCategoryDialog_onValueUpdate_badCategory(WebCategoriesDataModel.getMaxCategoryLength()); - } else if (currentSuffixes.contains(WebCategoriesDataModel.getNormalizedSuffix(safeSuffixStr))) { + } else if (currentSuffixes.contains(normalizedSuffix) && + currentDomainCategory != null && + !normalizedSuffix.equals(currentDomainCategory.getHostSuffix())) { + validationMessage = Bundle.AddEditCategoryDialog_onValueUpdate_suffixRepeat(); } else if (currentDomainCategory != null @@ -157,18 +189,6 @@ class AddEditCategoryDialog extends javax.swing.JDialog { setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - categoryTextField.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - categoryTextFieldActionPerformed(evt); - } - }); - - domainSuffixTextField.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - domainSuffixTextFieldActionPerformed(evt); - } - }); - categoryLabel.setText(org.openide.util.NbBundle.getMessage(AddEditCategoryDialog.class, "AddEditCategoryDialog.categoryLabel.text")); // NOI18N domainSuffixLabel.setText(org.openide.util.NbBundle.getMessage(AddEditCategoryDialog.class, "AddEditCategoryDialog.domainSuffixLabel.text")); // NOI18N @@ -198,41 +218,40 @@ class AddEditCategoryDialog extends javax.swing.JDialog { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(validationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(saveButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelButton)) + .addComponent(validationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(domainSuffixLabel) .addComponent(categoryLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(categoryTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 272, Short.MAX_VALUE) - .addComponent(domainSuffixTextField))) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 216, Short.MAX_VALUE) - .addComponent(saveButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cancelButton))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(categoryTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 276, Short.MAX_VALUE) + .addComponent(domainSuffixTextField)))) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(categoryLabel) - .addComponent(categoryTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(18, 18, 18) - .addComponent(domainSuffixTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(domainSuffixTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(domainSuffixLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(validationLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(categoryTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(categoryLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(validationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(saveButton) .addComponent(cancelButton)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(12, Short.MAX_VALUE)) ); pack(); @@ -248,14 +267,6 @@ class AddEditCategoryDialog extends javax.swing.JDialog { dispose(); }//GEN-LAST:event_cancelButtonActionPerformed - private void domainSuffixTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_domainSuffixTextFieldActionPerformed - onValueUpdate(domainSuffixTextField.getText(), categoryTextField.getText()); - }//GEN-LAST:event_domainSuffixTextFieldActionPerformed - - private void categoryTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_categoryTextFieldActionPerformed - onValueUpdate(domainSuffixTextField.getText(), categoryTextField.getText()); - }//GEN-LAST:event_categoryTextFieldActionPerformed - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JTextField categoryTextField; 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 f97c373c6f..945213e4a4 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,9 +1,17 @@ +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. # {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_errorMessage=There was an error exporting. +WebCategoriesOptionsPanel_exportSetButtonActionPerformed_errorTitle=Export Error +WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorMessage=There was an error importing this json file. +WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorTitle=Import Error WebCategoryOptionsController_title=Custom Web Categories WebCategoryOptionsController_keywords=Custom Web Categories AddEditCategoryDialog.categoryLabel.text=Category: @@ -17,3 +25,4 @@ WebCategoriesOptionsPanel.editEntryButton.text=Edit Entry WebCategoriesOptionsPanel.deleteEntryButton.text=Delete Entry WebCategoriesOptionsPanel.importSetButton.text=Import Set WebCategoriesOptionsPanel.exportSetButton.text=Export Set +WebCategoriesOptionsPanel.ingestRunningWarning.text=Ingest is currently running. No editing can take place at this time. diff --git a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/CustomWebCategorizer.java b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/CustomWebCategorizer.java index e8f88bc8cb..d661385f35 100644 --- a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/CustomWebCategorizer.java +++ b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/CustomWebCategorizer.java @@ -85,7 +85,7 @@ public class CustomWebCategorizer implements DomainCategorizer { } @Override - public void close() throws Exception { + public void close() throws SQLException { dataModel.close(); } } 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 89523abd59..5852a6535e 100644 --- a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesDataModel.java +++ b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesDataModel.java @@ -340,7 +340,7 @@ class WebCategoriesDataModel implements AutoCloseable { // write to disk ObjectMapper mapper = new ObjectMapper(); - mapper.writeValue(jsonOutput, categories); + mapper.writerWithDefaultPrettyPrinter().writeValue(jsonOutput, categories); } /** @@ -391,7 +391,7 @@ class WebCategoriesDataModel implements AutoCloseable { Statement.RETURN_GENERATED_KEYS)) { insertUpdate.setString(1, getNormalizedSuffix(entry.getHostSuffix())); - insertUpdate.setString(1, getNormalizedCategory(entry.getCategory())); + insertUpdate.setString(2, getNormalizedCategory(entry.getCategory())); return insertUpdate.executeUpdate() > 0; } } @@ -503,7 +503,7 @@ class WebCategoriesDataModel implements AutoCloseable { } @Override - public synchronized void close() throws Exception { + public synchronized void close() throws SQLException { dbConn.close(); dbConn = null; } diff --git a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesOptionsController.java b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesOptionsController.java index 85e19afb02..aa1d6b0956 100644 --- a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesOptionsController.java +++ b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesOptionsController.java @@ -29,7 +29,7 @@ import org.openide.util.Lookup; * custom web categories. */ @OptionsPanelController.TopLevelRegistration(categoryName = "#WebCategoryOptionsController_title", - iconBase = "org/sleuthkit/autopsy/corecomponents/checkbox32.png", + iconBase = "org/sleuthkit/autopsy/images/domain-32.png", position = 21, keywords = "#WebCategoryOptionsController_keywords", keywordsCategory = "Custom Web Categories") 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 4dfb179690..6ef0426f90 100644 --- a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesOptionsPanel.java @@ -326,7 +326,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i try { dataModel.deleteRecord(selected.getHostSuffix()); refresh(); - } catch (SQLException ex) { + } catch (IllegalArgumentException | SQLException ex) { logger.log(Level.WARNING, "There was an error while deleting: " + selected.getHostSuffix(), ex); } } @@ -338,7 +338,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i try { dataModel.insertUpdateSuffix(newCategory); refresh(); - } catch (SQLException ex) { + } catch (IllegalArgumentException | SQLException ex) { logger.log(Level.WARNING, "There was an error while adding new record: " + newCategory.getHostSuffix(), ex); } } @@ -353,7 +353,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i dataModel.insertUpdateSuffix(newCategory); refresh(); } - } catch (SQLException ex) { + } catch (IllegalArgumentException | SQLException ex) { logger.log(Level.WARNING, "There was an error while editing: " + selected.getHostSuffix(), ex); } } @@ -389,7 +389,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i int result = fileChooser.showSaveDialog(this); if (result == JFileChooser.APPROVE_OPTION) { File selectedFile = fileChooser.getSelectedFile(); - if (selectedFile != null && selectedFile.exists()) { + if (selectedFile != null) { try { dataModel.exportToJson(selectedFile); } catch (SQLException | IOException ex) { @@ -430,7 +430,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i } @Override - public void close() throws Exception { + public void close() { IngestManager.getInstance().removeIngestJobEventListener(weakIngestListener); } }