From 365a5165819b085ae4c0db630f7fb5573955e904 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Tue, 23 Aug 2016 10:59:37 -0400 Subject: [PATCH 01/54] Edited TagsManager to include deletion and created TagsManagerPanel --- .../casemodule/services/TagsManager.java | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index e8d61bdeba..318b4ce75f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -184,6 +184,28 @@ public class TagsManager implements Closeable { return newTagName; } + + /** + * Deletes a tag name from the tags settings. + * + * @param displayName The display name for the tag name to be deleted. + * + * @throws TagNameDoesNotExistException + * + * @throws TskCoreException + */ + public synchronized void deleteTagName(String displayName) throws TagNameDoesNotExistException, TskCoreException { + if (null == caseDb) { + throw new TskCoreException("Tags manager has been closed"); + } + lazyLoadExistingTagNames(); + if (!uniqueTagNames.containsKey(displayName)) { + throw new TagNameDoesNotExistException(); + } else { + uniqueTagNames.remove(displayName); + saveTagNamesToTagsSettings(); + } + } /** * Tags a content object. @@ -582,7 +604,7 @@ public class TagsManager implements Closeable { */ private void lazyLoadExistingTagNames() { if (!tagNamesLoaded) { - addTagNamesFromCurrentCase(); + //addTagNamesFromCurrentCase(); addTagNamesFromTagsSettings(); addPredefinedTagNames(); saveTagNamesToTagsSettings(); @@ -673,5 +695,12 @@ public class TagsManager implements Closeable { private static final long serialVersionUID = 1L; } + + /** + * Exception thrown if there is an attempt to delete a nonexistent tag name. + */ + public static class TagNameDoesNotExistException extends Exception { + + } } From 395a8da587e73e20cc47793fc1487138eb25f26a Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Tue, 23 Aug 2016 15:14:00 -0400 Subject: [PATCH 02/54] Implemented basic methods in TagsManagerPanel --- .../casemodule/services/TagsManagerPanel.form | 224 ++++++++++++ .../casemodule/services/TagsManagerPanel.java | 333 ++++++++++++++++++ 2 files changed, 557 insertions(+) create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerPanel.form create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerPanel.form new file mode 100755 index 0000000000..572b3b37c8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerPanel.form @@ -0,0 +1,224 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerPanel.java new file mode 100755 index 0000000000..dc828dec3f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerPanel.java @@ -0,0 +1,333 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.casemodule.services; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.Level; +import javax.swing.DefaultListModel; +import org.netbeans.spi.options.OptionsPanelController; +import org.sleuthkit.autopsy.corecomponents.OptionsPanel; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; + +/** + * + * @author smori + */ +public class TagsManagerPanel extends javax.swing.JPanel implements OptionsPanel { + + private static final String TAG_NAME_EMPTY = "Tag name text is empty."; + private static final String TAG_NAME_ALREADY_EXISTS = "Tag name already exists."; + private static final String TAG_NAME_COMMA = "Tag name may not contain commas."; + + private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS + private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS + + private static final String DEFAULT_DESCRIPTION = ""; + private static final String DEFAULT_COLOR_STRING = "NONE"; + + private final DefaultListModel tagNamesListModel; + private final Set tagNames; + + /** + * Creates new form TagsManagerPanel + */ + public TagsManagerPanel() { + tagNamesListModel = new DefaultListModel<>(); + tagNamesList.setModel(tagNamesListModel); + tagNames = new TreeSet<>(); + + initComponents(); + customizeComponents(); + } + + private void customizeComponents() { + addTagNamesFromTagsSettings(); + + } + + private void addTagNamesFromTagsSettings() { + String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); + if ((setting != null) && !setting.isEmpty()) { + List tagNameTuples = Arrays.asList(setting.split(";")); + for (String tagNameTuple : tagNameTuples) { + String[] tagNameAttributes = tagNameTuple.split(","); + CustomTagName tagName = new CustomTagName(tagNameAttributes[0], tagNameAttributes[1], tagNameAttributes[2]); + tagNames.add(tagName); + } + } + } + + private void updateTagNamesListModel() { + tagNamesListModel.clear(); + tagNames.stream().forEach((tagName) -> { + tagNamesListModel.addElement(tagName); + }); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jPanel1 = new javax.swing.JPanel(); + jLabel1 = new javax.swing.JLabel(); + jSplitPane1 = new javax.swing.JSplitPane(); + jPanel2 = new javax.swing.JPanel(); + tagNamesListLabel = new javax.swing.JLabel(); + jScrollPane1 = new javax.swing.JScrollPane(); + tagNamesList = new javax.swing.JList<>(); + userTagNameTextField = new javax.swing.JTextField(); + addTagNameButton = new javax.swing.JButton(); + deleteTagNameButton = new javax.swing.JButton(); + tagNameErrLabel = new javax.swing.JLabel(); + jPanel3 = new javax.swing.JPanel(); + + jPanel1.setPreferredSize(new java.awt.Dimension(750, 500)); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(TagsManagerPanel.class, "TagsManagerPanel.jLabel1.text")); // NOI18N + + jSplitPane1.setDividerLocation(-100); + jSplitPane1.setDividerSize(1); + + org.openide.awt.Mnemonics.setLocalizedText(tagNamesListLabel, org.openide.util.NbBundle.getMessage(TagsManagerPanel.class, "TagsManagerPanel.tagNamesListLabel.text")); // NOI18N + + jScrollPane1.setViewportView(tagNamesList); + + userTagNameTextField.setText(org.openide.util.NbBundle.getMessage(TagsManagerPanel.class, "TagsManagerPanel.userTagNameTextField.text")); // NOI18N + + addTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(addTagNameButton, org.openide.util.NbBundle.getMessage(TagsManagerPanel.class, "TagsManagerPanel.addTagNameButton.text")); // NOI18N + addTagNameButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + addTagNameButtonActionPerformed(evt); + } + }); + + deleteTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteTagNameButton, org.openide.util.NbBundle.getMessage(TagsManagerPanel.class, "TagsManagerPanel.deleteTagNameButton.text")); // NOI18N + deleteTagNameButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + deleteTagNameButtonActionPerformed(evt); + } + }); + + tagNameErrLabel.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(tagNameErrLabel, org.openide.util.NbBundle.getMessage(TagsManagerPanel.class, "TagsManagerPanel.tagNameErrLabel.text")); // NOI18N + + 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(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(tagNameErrLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jScrollPane1) + .addComponent(tagNamesListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup() + .addComponent(userTagNameTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 135, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(addTagNameButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deleteTagNameButton))) + .addContainerGap()) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addComponent(tagNamesListLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 374, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(userTagNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(addTagNameButton) + .addComponent(deleteTagNameButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(tagNameErrLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + + jSplitPane1.setLeftComponent(jPanel2); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 330, Short.MAX_VALUE) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 456, Short.MAX_VALUE) + ); + + jSplitPane1.setRightComponent(jPanel3); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jSplitPane1) + .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jSplitPane1) + .addContainerGap()) + ); + + 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.DEFAULT_SIZE, 778, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void addTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addTagNameButtonActionPerformed + String newTagName = userTagNameTextField.getText(); + + if (newTagName.isEmpty()) { + tagNameErrLabel.setText(TAG_NAME_EMPTY); + return; + } + if (newTagName.contains(",")) { + tagNameErrLabel.setText(TAG_NAME_COMMA); + return; + } + + CustomTagName tagName = new CustomTagName(newTagName, DEFAULT_DESCRIPTION, DEFAULT_COLOR_STRING); + boolean added = tagNames.add(tagName); + if (!added) { + tagNameErrLabel.setText(TAG_NAME_ALREADY_EXISTS); + return; + } + + updateTagNamesListModel(); + userTagNameTextField.setText(""); + tagNameErrLabel.setText(""); + + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + }//GEN-LAST:event_addTagNameButtonActionPerformed + + private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagNameButtonActionPerformed + CustomTagName tagName = tagNamesList.getSelectedValue(); + tagNames.remove(tagName); + updateTagNamesListModel(); + + if (!tagNamesListModel.isEmpty()) { + tagNamesList.setSelectedIndex(0); + } + + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + }//GEN-LAST:event_deleteTagNameButtonActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton addTagNameButton; + private javax.swing.JButton deleteTagNameButton; + private javax.swing.JLabel jLabel1; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JSplitPane jSplitPane1; + private javax.swing.JLabel tagNameErrLabel; + private javax.swing.JList tagNamesList; + private javax.swing.JLabel tagNamesListLabel; + private javax.swing.JTextField userTagNameTextField; + // End of variables declaration//GEN-END:variables + + @Override + public void store() { + if (!tagNames.isEmpty()) { + StringBuilder builder = new StringBuilder(); + for (CustomTagName tagName : tagNames) { + if (builder.length() != 0) { + builder.append(";"); + } + builder.append(tagName.toString()); + } + ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, builder.toString()); + } + } + + @Override + public void load() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + /** + * TagName constructor is not public, CustomTagName is for the purposes of + * preserving description and color information that may be in the user tags + * settings files. + */ + private class CustomTagName implements Comparable { + private final String displayName; + private final String description; + private final String colorName; + + private CustomTagName(String displayName, String description, String colorName) { + this.displayName = displayName; + this.description = description; + this.colorName = colorName; + } + + private String getDisplayName() { + return displayName; + } + + @Override + public int compareTo(CustomTagName other) { + return this.getDisplayName().compareTo(other.getDisplayName()); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 83 * hash + Objects.hashCode(this.displayName); + hash = 83 * hash + Objects.hashCode(this.description); + hash = 83 * hash + Objects.hashCode(this.colorName); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof CustomTagName)) return false; + CustomTagName thatTagName = (CustomTagName) obj; + return this.getDisplayName().equals(thatTagName.getDisplayName()); + } + + @Override + public String toString() { + return displayName + "," + description + "," + colorName; + } + + } +} From 0c484350ebb025ac3e1db8fe1c90c21ca1626fdb Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Tue, 23 Aug 2016 15:24:07 -0400 Subject: [PATCH 03/54] Renamed TagsManagerPanel to TagsManagerOptionsPanel --- ...anel.form => TagsManagerOptionsPanel.form} | 12 +++++----- ...anel.java => TagsManagerOptionsPanel.java} | 22 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) rename Core/src/org/sleuthkit/autopsy/casemodule/services/{TagsManagerPanel.form => TagsManagerOptionsPanel.form} (91%) rename Core/src/org/sleuthkit/autopsy/casemodule/services/{TagsManagerPanel.java => TagsManagerOptionsPanel.java} (92%) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.form similarity index 91% rename from Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerPanel.form rename to Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.form index 572b3b37c8..a0ea7e8def 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.form @@ -65,7 +65,7 @@ - + @@ -128,7 +128,7 @@ - + @@ -154,7 +154,7 @@ - + @@ -164,7 +164,7 @@ - + @@ -177,7 +177,7 @@ - + @@ -190,7 +190,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java similarity index 92% rename from Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerPanel.java rename to Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java index dc828dec3f..19ec12c104 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java @@ -21,7 +21,7 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; * * @author smori */ -public class TagsManagerPanel extends javax.swing.JPanel implements OptionsPanel { +public class TagsManagerOptionsPanel extends javax.swing.JPanel implements OptionsPanel { private static final String TAG_NAME_EMPTY = "Tag name text is empty."; private static final String TAG_NAME_ALREADY_EXISTS = "Tag name already exists."; @@ -39,7 +39,7 @@ public class TagsManagerPanel extends javax.swing.JPanel implements OptionsPanel /** * Creates new form TagsManagerPanel */ - public TagsManagerPanel() { + public TagsManagerOptionsPanel() { tagNamesListModel = new DefaultListModel<>(); tagNamesList.setModel(tagNamesListModel); tagNames = new TreeSet<>(); @@ -96,19 +96,19 @@ public class TagsManagerPanel extends javax.swing.JPanel implements OptionsPanel jPanel1.setPreferredSize(new java.awt.Dimension(750, 500)); - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(TagsManagerPanel.class, "TagsManagerPanel.jLabel1.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.jLabel1.text")); // NOI18N jSplitPane1.setDividerLocation(-100); jSplitPane1.setDividerSize(1); - org.openide.awt.Mnemonics.setLocalizedText(tagNamesListLabel, org.openide.util.NbBundle.getMessage(TagsManagerPanel.class, "TagsManagerPanel.tagNamesListLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(tagNamesListLabel, org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.tagNamesListLabel.text")); // NOI18N jScrollPane1.setViewportView(tagNamesList); - userTagNameTextField.setText(org.openide.util.NbBundle.getMessage(TagsManagerPanel.class, "TagsManagerPanel.userTagNameTextField.text")); // NOI18N + userTagNameTextField.setText(org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.userTagNameTextField.text")); // NOI18N addTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(addTagNameButton, org.openide.util.NbBundle.getMessage(TagsManagerPanel.class, "TagsManagerPanel.addTagNameButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(addTagNameButton, org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.text")); // NOI18N addTagNameButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { addTagNameButtonActionPerformed(evt); @@ -116,7 +116,7 @@ public class TagsManagerPanel extends javax.swing.JPanel implements OptionsPanel }); deleteTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(deleteTagNameButton, org.openide.util.NbBundle.getMessage(TagsManagerPanel.class, "TagsManagerPanel.deleteTagNameButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteTagNameButton, org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.deleteTagNameButton.text")); // NOI18N deleteTagNameButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { deleteTagNameButtonActionPerformed(evt); @@ -124,7 +124,7 @@ public class TagsManagerPanel extends javax.swing.JPanel implements OptionsPanel }); tagNameErrLabel.setForeground(new java.awt.Color(255, 0, 0)); - org.openide.awt.Mnemonics.setLocalizedText(tagNameErrLabel, org.openide.util.NbBundle.getMessage(TagsManagerPanel.class, "TagsManagerPanel.tagNameErrLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(tagNameErrLabel, org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.tagNameErrLabel.text")); // NOI18N javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); jPanel2.setLayout(jPanel2Layout); @@ -284,9 +284,9 @@ public class TagsManagerPanel extends javax.swing.JPanel implements OptionsPanel } /** - * TagName constructor is not public, CustomTagName is for the purposes of - * preserving description and color information that may be in the user tags - * settings files. + * Because TagName constructor is not public, CustomTagName is used in this + * tags managers panel for the purpose of preserving description and color + * information that is tracked by the user tag settings file. */ private class CustomTagName implements Comparable { private final String displayName; From 791135b6d869d9c4a6c66bcb843280918eae79fd Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Tue, 23 Aug 2016 17:22:12 -0400 Subject: [PATCH 04/54] Added PanelController, fixed messages and text, fixed mismatching bugs --- .../casemodule/services/Bundle.properties | 11 ++ .../services/TagsManagerOptionsPanel.java | 43 ++++---- .../TagsManagerOptionsPanelController.java | 101 ++++++++++++++++++ 3 files changed, 137 insertions(+), 18 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index 1a3be9454f..cfaaa7bb20 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -1,3 +1,5 @@ +OptionsCategory_Name_TagsManager=Tags Manager +OptionsCategory_Keywords_TagsManager=TagsManager TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0} out of content size range (0 - {1}) TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} out of content size range (0 - {1}) TagsManager.addContentTag.exception.endLTbegin.msg=endByteOffset < beginByteOffset @@ -7,3 +9,12 @@ TagsManager.deleteContentTag.noCaseWarning=Failed to publish content tag deleted TagsManager.addBlackboardArtifactTag.noCaseWarning=Failed to publish new blackboard artifact tag event. There is no case open. TagsManager.deleteBlackboardArtifactTag.noCaseWarning=Failed to publish blackboard artifact tag deleted event. There is no case open. Blackboard.unableToIndexArtifact.error.msg=Unable to index blackboard artifact {0} +TagsManagerOptionsPanel.addTagNameButton.empty=Tag name text is empty. +TagsManagerOptionsPanel.addTagNameButton.containComma=Tag name may not contain commas. +TagsManagerOptionsPanel.addTagNameButton.alreadyExists=Tag name already exists. +TagsManagerOptionsPanel.jLabel1.text=Autopsy keeps a list of the tag names you have used in the past. Add more or delete them here. +TagsManagerOptionsPanel.tagNamesListLabel.text=\ +TagsManagerOptionsPanel.userTagNameTextField.text=\ +TagsManagerOptionsPanel.addTagNameButton.text=Add Tag Name +TagsManagerOptionsPanel.deleteTagNameButton.text=Delete Tag Name +TagsManagerOptionsPanel.tagNameErrLabel.text=\ \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java index 19ec12c104..e0c90f8eee 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java @@ -13,6 +13,7 @@ import java.util.TreeSet; import java.util.logging.Level; import javax.swing.DefaultListModel; import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; @@ -23,10 +24,6 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; */ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements OptionsPanel { - private static final String TAG_NAME_EMPTY = "Tag name text is empty."; - private static final String TAG_NAME_ALREADY_EXISTS = "Tag name already exists."; - private static final String TAG_NAME_COMMA = "Tag name may not contain commas."; - private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS @@ -40,17 +37,19 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio * Creates new form TagsManagerPanel */ public TagsManagerOptionsPanel() { + initComponents(); + tagNamesListModel = new DefaultListModel<>(); tagNamesList.setModel(tagNamesListModel); tagNames = new TreeSet<>(); - initComponents(); customizeComponents(); } private void customizeComponents() { addTagNamesFromTagsSettings(); + tagNameErrLabel.setText(""); } private void addTagNamesFromTagsSettings() { @@ -214,18 +213,18 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio String newTagName = userTagNameTextField.getText(); if (newTagName.isEmpty()) { - tagNameErrLabel.setText(TAG_NAME_EMPTY); + tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.empty")); return; } if (newTagName.contains(",")) { - tagNameErrLabel.setText(TAG_NAME_COMMA); + tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.containComma")); return; } CustomTagName tagName = new CustomTagName(newTagName, DEFAULT_DESCRIPTION, DEFAULT_COLOR_STRING); boolean added = tagNames.add(tagName); if (!added) { - tagNameErrLabel.setText(TAG_NAME_ALREADY_EXISTS); + tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.alreadyExists")); return; } @@ -238,14 +237,16 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagNameButtonActionPerformed CustomTagName tagName = tagNamesList.getSelectedValue(); - tagNames.remove(tagName); - updateTagNamesListModel(); - - if (!tagNamesListModel.isEmpty()) { - tagNamesList.setSelectedIndex(0); + if (tagName != null) { + tagNames.remove(tagName); + updateTagNamesListModel(); + + if (!tagNamesListModel.isEmpty()) { + tagNamesList.setSelectedIndex(0); + } + + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } - - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_deleteTagNameButtonActionPerformed @@ -272,7 +273,7 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio if (builder.length() != 0) { builder.append(";"); } - builder.append(tagName.toString()); + builder.append(tagName.toSettingsFormat()); } ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, builder.toString()); } @@ -280,7 +281,9 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio @Override public void load() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + addTagNamesFromTagsSettings(); + updateTagNamesListModel(); + //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /** @@ -305,7 +308,7 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio @Override public int compareTo(CustomTagName other) { - return this.getDisplayName().compareTo(other.getDisplayName()); + return this.getDisplayName().toLowerCase().compareTo(other.getDisplayName().toLowerCase()); } @Override @@ -326,6 +329,10 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio @Override public String toString() { + return displayName; + } + + public String toSettingsFormat() { return displayName + "," + description + "," + colorName; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java new file mode 100755 index 0000000000..00e461262d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java @@ -0,0 +1,101 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.casemodule.services; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import javax.swing.JComponent; +import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.HelpCtx; +import org.openide.util.Lookup; + +@OptionsPanelController.TopLevelRegistration( + categoryName = "#OptionsCategory_Name_TagsManager", + iconBase = "org/sleuthkit/autopsy/modules/filetypeid/user-defined-file-types-settings.png", + keywords = "#OptionsCategory_Keywords_TagsManager", + keywordsCategory = "TagsManager", + position = 10 +) +public final class TagsManagerOptionsPanelController extends OptionsPanelController { + + private TagsManagerOptionsPanel panel; + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + private boolean changed; + + @Override + public void update() { + getPanel().load(); + changed = false; + } + + @Override + public void applyChanges() { + if (changed) { + getPanel().store(); + changed = false; + } + } + + @Override + public void cancel() { + //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValid() { + return true; + //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isChanged() { + return changed; + } + + @Override + public JComponent getComponent(Lookup lkp) { + return getPanel(); + } + + @Override + public HelpCtx getHelpCtx() { + return null; + } + + @Override + public void addPropertyChangeListener(PropertyChangeListener l) { + pcs.addPropertyChangeListener(l); + } + + @Override + public void removePropertyChangeListener(PropertyChangeListener l) { + pcs.removePropertyChangeListener(l); + } + + private TagsManagerOptionsPanel getPanel() { + if (panel == null) { + panel = new TagsManagerOptionsPanel(); + panel.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals(OptionsPanelController.PROP_CHANGED)) { + changed(); + } + } + }); + } + return panel; + } + + void changed() { + if (!changed) { + changed = true; + pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true); + } + pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null); + } +} From 5faaeb06ef88c181566ff70f548dd3e0e628e8da Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Wed, 24 Aug 2016 14:38:52 -0400 Subject: [PATCH 05/54] Fixed properties file behavior, TODO: deleted tag names not appear in quick tag --- .../casemodule/services/Bundle.properties | 6 +- .../casemodule/services/TagsManager.java | 27 +++++++-- .../services/TagsManagerOptionsPanel.java | 55 +++++++++++-------- .../TagsManagerOptionsPanelController.java | 5 +- 4 files changed, 60 insertions(+), 33 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index cfaaa7bb20..6e35787c25 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -13,8 +13,8 @@ TagsManagerOptionsPanel.addTagNameButton.empty=Tag name text is empty. TagsManagerOptionsPanel.addTagNameButton.containComma=Tag name may not contain commas. TagsManagerOptionsPanel.addTagNameButton.alreadyExists=Tag name already exists. TagsManagerOptionsPanel.jLabel1.text=Autopsy keeps a list of the tag names you have used in the past. Add more or delete them here. -TagsManagerOptionsPanel.tagNamesListLabel.text=\ -TagsManagerOptionsPanel.userTagNameTextField.text=\ +TagsManagerOptionsPanel.tagNamesListLabel.text=Your tag names: +TagsManagerOptionsPanel.userTagNameTextField.text= TagsManagerOptionsPanel.addTagNameButton.text=Add Tag Name TagsManagerOptionsPanel.deleteTagNameButton.text=Delete Tag Name -TagsManagerOptionsPanel.tagNameErrLabel.text=\ \ No newline at end of file +TagsManagerOptionsPanel.tagNameErrLabel.text= \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 318b4ce75f..e120ca1361 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -180,8 +180,8 @@ public class TagsManager implements Closeable { * Add the tag name to the tags settings. */ uniqueTagNames.put(newTagName.getDisplayName(), newTagName); - saveTagNamesToTagsSettings(); - + addNewTagNameToTagsSettings(newTagName); + return newTagName; } @@ -585,7 +585,7 @@ public class TagsManager implements Closeable { } /** - * Closes the tags manager, saving the avaialble tag names to secondary + * Closes the tags manager, saving the available tag names to secondary * storage. * * @throws IOException If there is a problem closing the tags manager. @@ -594,7 +594,7 @@ public class TagsManager implements Closeable { @Override @Deprecated public synchronized void close() throws IOException { - saveTagNamesToTagsSettings(); + //saveTagNamesToTagsSettings(); caseDb = null; } @@ -604,10 +604,10 @@ public class TagsManager implements Closeable { */ private void lazyLoadExistingTagNames() { if (!tagNamesLoaded) { - //addTagNamesFromCurrentCase(); addTagNamesFromTagsSettings(); addPredefinedTagNames(); saveTagNamesToTagsSettings(); + addTagNamesFromCurrentCase(); tagNamesLoaded = true; } } @@ -687,7 +687,22 @@ public class TagsManager implements Closeable { ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); } } - + + /** + * + */ + private void addNewTagNameToTagsSettings(TagName tagName) { + String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); + if (setting == null || setting.isEmpty()) { + setting = ""; + } + else { + setting += ";"; + } + setting += tagName.getDisplayName() + "," + tagName.getDescription() + "," + tagName.getColor().name(); + ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting); + } + /** * Exception thrown if there is an attempt to add a duplicate tag name. */ diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java index e0c90f8eee..a603bb3c12 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java @@ -13,10 +13,13 @@ import java.util.TreeSet; import java.util.logging.Level; import javax.swing.DefaultListModel; import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.datamodel.TskCoreException; /** * @@ -31,7 +34,7 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio private static final String DEFAULT_COLOR_STRING = "NONE"; private final DefaultListModel tagNamesListModel; - private final Set tagNames; + private Set tagNames; /** * Creates new form TagsManagerPanel @@ -41,27 +44,23 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio tagNamesListModel = new DefaultListModel<>(); tagNamesList.setModel(tagNamesListModel); - tagNames = new TreeSet<>(); - - customizeComponents(); - } - - private void customizeComponents() { - addTagNamesFromTagsSettings(); - + tagNames = getTagNamesFromTagsSettings(); + userTagNameTextField.setText(""); tagNameErrLabel.setText(""); } - private void addTagNamesFromTagsSettings() { + private Set getTagNamesFromTagsSettings() { + Set tagNamesFromSettings = new TreeSet<>(); String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); if ((setting != null) && !setting.isEmpty()) { List tagNameTuples = Arrays.asList(setting.split(";")); for (String tagNameTuple : tagNameTuples) { String[] tagNameAttributes = tagNameTuple.split(","); CustomTagName tagName = new CustomTagName(tagNameAttributes[0], tagNameAttributes[1], tagNameAttributes[2]); - tagNames.add(tagName); + tagNamesFromSettings.add(tagName); } } + return tagNamesFromSettings; } private void updateTagNamesListModel() { @@ -222,8 +221,8 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio } CustomTagName tagName = new CustomTagName(newTagName, DEFAULT_DESCRIPTION, DEFAULT_COLOR_STRING); - boolean added = tagNames.add(tagName); - if (!added) { + boolean addedToTagNames = tagNames.add(tagName); + if (!addedToTagNames) { tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.alreadyExists")); return; } @@ -237,16 +236,19 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagNameButtonActionPerformed CustomTagName tagName = tagNamesList.getSelectedValue(); - if (tagName != null) { - tagNames.remove(tagName); - updateTagNamesListModel(); + if (tagName == null) { + tagNameErrLabel.setText("No tag name selected."); + } else { + tagNames.remove(tagName); + updateTagNamesListModel(); + + + if (!tagNamesListModel.isEmpty()) { + tagNamesList.setSelectedIndex(0); + } - if (!tagNamesListModel.isEmpty()) { - tagNamesList.setSelectedIndex(0); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } - - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - } }//GEN-LAST:event_deleteTagNameButtonActionPerformed @@ -281,9 +283,16 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio @Override public void load() { - addTagNamesFromTagsSettings(); + tagNames = getTagNamesFromTagsSettings(); updateTagNamesListModel(); - //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + if (!tagNamesListModel.isEmpty()) { + tagNamesList.setSelectedIndex(0); + } + tagNameErrLabel.setText(""); + } + + public void cancelChanges() { + tagNames = getTagNamesFromTagsSettings(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java index 00e461262d..bb876d82df 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java @@ -42,7 +42,10 @@ public final class TagsManagerOptionsPanelController extends OptionsPanelControl @Override public void cancel() { - //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + if (changed) { + getPanel().cancelChanges(); + changed = false; + } } @Override From c6d8f07ac5338c95c7db0e8602a9c2ec1c8e1bf2 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Wed, 24 Aug 2016 14:52:35 -0400 Subject: [PATCH 06/54] Edited minor space issues --- .../sleuthkit/autopsy/casemodule/services/Bundle.properties | 2 +- .../autopsy/casemodule/services/TagsManagerOptionsPanel.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index 6e35787c25..a40e1e200f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -10,7 +10,7 @@ TagsManager.addBlackboardArtifactTag.noCaseWarning=Failed to publish new blackbo TagsManager.deleteBlackboardArtifactTag.noCaseWarning=Failed to publish blackboard artifact tag deleted event. There is no case open. Blackboard.unableToIndexArtifact.error.msg=Unable to index blackboard artifact {0} TagsManagerOptionsPanel.addTagNameButton.empty=Tag name text is empty. -TagsManagerOptionsPanel.addTagNameButton.containComma=Tag name may not contain commas. +TagsManagerOptionsPanel.addTagNameButton.containCommaSemicolon=Tag name may not contain commas or semicolons. TagsManagerOptionsPanel.addTagNameButton.alreadyExists=Tag name already exists. TagsManagerOptionsPanel.jLabel1.text=Autopsy keeps a list of the tag names you have used in the past. Add more or delete them here. TagsManagerOptionsPanel.tagNamesListLabel.text=Your tag names: diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java index a603bb3c12..221d5f2a9f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java @@ -215,8 +215,8 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.empty")); return; } - if (newTagName.contains(",")) { - tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.containComma")); + if (newTagName.contains(",") || newTagName.contains(";")) { + tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.containCommaSemicolon")); return; } @@ -242,7 +242,6 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio tagNames.remove(tagName); updateTagNamesListModel(); - if (!tagNamesListModel.isEmpty()) { tagNamesList.setSelectedIndex(0); } From 452f4f66f87b10dcc6708a268173b6228e2a3880 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Thu, 25 Aug 2016 10:11:53 -0400 Subject: [PATCH 07/54] Some modifications --- .../casemodule/services/TagsManager.java | 30 +++++++- .../services/TagsManagerOptionsPanel.java | 76 +++++++++---------- 2 files changed, 67 insertions(+), 39 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index e120ca1361..413e1b1fe8 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -20,9 +20,13 @@ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; @@ -74,7 +78,11 @@ public class TagsManager implements Closeable { throw new TskCoreException("Tags manager has been closed"); } lazyLoadExistingTagNames(); - return caseDb.getAllTagNames(); + //return caseDb.getAllTagNames(); + Set tagNameSet = new HashSet<>(); + tagNameSet.addAll(getTagNamesInUse()); + tagNameSet.addAll(getTagNamesForPropertyFile()); + return new ArrayList<>(tagNameSet); } /** @@ -93,6 +101,26 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getTagNamesInUse(); } + + public synchronized List getTagNamesForPropertyFile() throws TskCoreException { + if (null == caseDb) { + throw new TskCoreException("Tags manager has been closed."); + } + lazyLoadExistingTagNames(); + addTagNamesFromTagsSettings(); + List propertyFileTagNames = new ArrayList<>(); + + String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); + if (null != setting && !setting.isEmpty()) { + List tagNameTuples = Arrays.asList(setting.split(";")); + for (String tagNameTuple : tagNameTuples) { + String[] tagNameAttributes = tagNameTuple.split(","); + String displayName = tagNameAttributes[0]; + propertyFileTagNames.add(uniqueTagNames.get(displayName)); + } + } + return propertyFileTagNames; + } /** * Checks whether a tag name with a given display name exists. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java index 221d5f2a9f..7d47fcbf8a 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java @@ -1,8 +1,8 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ +* To change this license header, choose License Headers in Project Properties. +* To change this template file, choose Tools | Templates +* and open the template in the editor. +*/ package org.sleuthkit.autopsy.casemodule.services; import java.util.Arrays; @@ -26,16 +26,17 @@ import org.sleuthkit.datamodel.TskCoreException; * @author smori */ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements OptionsPanel { - + private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS private static final String DEFAULT_DESCRIPTION = ""; private static final String DEFAULT_COLOR_STRING = "NONE"; - + private final DefaultListModel tagNamesListModel; private Set tagNames; + /** * Creates new form TagsManagerPanel */ @@ -69,7 +70,7 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio tagNamesListModel.addElement(tagName); }); } - + /** * 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 @@ -207,7 +208,7 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio .addGap(0, 0, Short.MAX_VALUE)) ); }// //GEN-END:initComponents - + private void addTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addTagNameButtonActionPerformed String newTagName = userTagNameTextField.getText(); @@ -226,31 +227,32 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.alreadyExists")); return; } - + updateTagNamesListModel(); + userTagNameTextField.setText(""); tagNameErrLabel.setText(""); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_addTagNameButtonActionPerformed - + private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagNameButtonActionPerformed CustomTagName tagName = tagNamesList.getSelectedValue(); - if (tagName == null) { - tagNameErrLabel.setText("No tag name selected."); - } else { - tagNames.remove(tagName); - updateTagNamesListModel(); - - if (!tagNamesListModel.isEmpty()) { - tagNamesList.setSelectedIndex(0); - } - - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + if (tagName == null) { + tagNameErrLabel.setText("No tag name selected."); + } else { + tagNames.remove(tagName); + updateTagNamesListModel(); + + if (!tagNamesListModel.isEmpty()) { + tagNamesList.setSelectedIndex(0); } + + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + } }//GEN-LAST:event_deleteTagNameButtonActionPerformed - - + + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton addTagNameButton; private javax.swing.JButton deleteTagNameButton; @@ -265,21 +267,19 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio private javax.swing.JLabel tagNamesListLabel; private javax.swing.JTextField userTagNameTextField; // End of variables declaration//GEN-END:variables - + @Override public void store() { - if (!tagNames.isEmpty()) { - StringBuilder builder = new StringBuilder(); - for (CustomTagName tagName : tagNames) { - if (builder.length() != 0) { - builder.append(";"); - } - builder.append(tagName.toSettingsFormat()); + StringBuilder builder = new StringBuilder(); + for (CustomTagName tagName : tagNames) { + if (builder.length() != 0) { + builder.append(";"); } - ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, builder.toString()); + builder.append(tagName.toSettingsFormat()); } + ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, builder.toString()); } - + @Override public void load() { tagNames = getTagNamesFromTagsSettings(); @@ -296,7 +296,7 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio /** * Because TagName constructor is not public, CustomTagName is used in this - * tags managers panel for the purpose of preserving description and color + * tags managers panel for the purpose of preserving description and color * information that is tracked by the user tag settings file. */ private class CustomTagName implements Comparable { @@ -315,9 +315,9 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio } @Override - public int compareTo(CustomTagName other) { - return this.getDisplayName().toLowerCase().compareTo(other.getDisplayName().toLowerCase()); - } + public int compareTo(CustomTagName other) { + return this.getDisplayName().toLowerCase().compareTo(other.getDisplayName().toLowerCase()); + } @Override public int hashCode() { @@ -334,7 +334,7 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio CustomTagName thatTagName = (CustomTagName) obj; return this.getDisplayName().equals(thatTagName.getDisplayName()); } - + @Override public String toString() { return displayName; From 5de32ba177912ae66725beea8a6a58d96b81d700 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Thu, 25 Aug 2016 15:06:02 -0400 Subject: [PATCH 08/54] Fixed deletion error and readdition error in the tags options panel, changed name of new tag button --- .../autopsy/actions/Bundle.properties | 2 +- .../actions/GetTagNameAndCommentDialog.form | 2 +- .../actions/GetTagNameAndCommentDialog.java | 2 +- .../casemodule/services/Bundle.properties | 4 +- .../casemodule/services/TagsManager.java | 195 +++++++++--------- .../services/TagsManagerOptionsPanel.form | 3 + .../services/TagsManagerOptionsPanel.java | 93 ++++++++- .../TagsManagerOptionsPanelController.java | 22 +- 8 files changed, 205 insertions(+), 118 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties index d9cc839467..71ce8a4504 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties @@ -4,7 +4,7 @@ GetTagNameDialog.okButton.text=OK GetTagNameDialog.preexistingLabel.text=Pre-existing Tags: GetTagNameDialog.newTagPanel.border.title=New Tag GetTagNameDialog.tagNameLabel.text=Tag Name: -GetTagNameAndCommentDialog.newTagButton.text=New Tag +GetTagNameAndCommentDialog.newTagButton.text=New Tag Name GetTagNameAndCommentDialog.okButton.text=OK GetTagNameAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank GetTagNameAndCommentDialog.commentText.text= diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form index 47ff059281..17a9738dbd 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form @@ -28,7 +28,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index eb4dbbab6b..9a82e445e1 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -197,7 +197,7 @@ public class GetTagNameAndCommentDialog extends JDialog { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addComponent(newTagButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 78, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 48, Short.MAX_VALUE) .addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(cancelButton)) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index a40e1e200f..638c8a8412 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -1,4 +1,4 @@ -OptionsCategory_Name_TagsManager=Tags Manager +OptionsCategory_Name_TagsManager=My Tags OptionsCategory_Keywords_TagsManager=TagsManager TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0} out of content size range (0 - {1}) TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} out of content size range (0 - {1}) @@ -12,7 +12,7 @@ Blackboard.unableToIndexArtifact.error.msg=Unable to index blackboard artifact { TagsManagerOptionsPanel.addTagNameButton.empty=Tag name text is empty. TagsManagerOptionsPanel.addTagNameButton.containCommaSemicolon=Tag name may not contain commas or semicolons. TagsManagerOptionsPanel.addTagNameButton.alreadyExists=Tag name already exists. -TagsManagerOptionsPanel.jLabel1.text=Autopsy keeps a list of the tag names you have used in the past. Add more or delete them here. +TagsManagerOptionsPanel.jLabel1.text=Autopsy keeps a list of the tag names you have created in the past. Add more or delete them here. TagsManagerOptionsPanel.tagNamesListLabel.text=Your tag names: TagsManagerOptionsPanel.userTagNameTextField.text= TagsManagerOptionsPanel.addTagNameButton.text=Add Tag Name diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 413e1b1fe8..bfb01e577c 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -1,21 +1,21 @@ /* - * Autopsy Forensic Browser - * - * Copyright 2011-2016 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. - */ +* Autopsy Forensic Browser +* +* Copyright 2011-2016 Basis Technology Corp. +* Contact: carrier sleuthkit org +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; @@ -45,29 +45,30 @@ import org.sleuthkit.datamodel.TskCoreException; * of tags applied to content and blackboard artifacts by users. */ public class TagsManager implements Closeable { - + private static final Logger logger = Logger.getLogger(TagsManager.class.getName()); private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS private SleuthkitCase caseDb; private final HashMap uniqueTagNames = new HashMap<>(); private boolean tagNamesLoaded = false; - + /** * Constructs a per case Autopsy service that manages the creation, * updating, and deletion of tags applied to content and blackboard * artifacts by users. - * + * * @param caseDb The case database. */ TagsManager(SleuthkitCase caseDb) { this.caseDb = caseDb; } - + /** * Gets a list of all tag names currently available for tagging content or - * artifacts. - * + * artifacts. Available tag names include tag names currently being used or + * tag names loaded from the properties file. + * * @return A list, possibly empty, of TagName data transfer objects (DTOs). * * @throws TskCoreException If there is an error reading from the case @@ -84,7 +85,7 @@ public class TagsManager implements Closeable { tagNameSet.addAll(getTagNamesForPropertyFile()); return new ArrayList<>(tagNameSet); } - + /** * Gets a list of all tag names currently in use for tagging content or * artifacts. @@ -102,12 +103,14 @@ public class TagsManager implements Closeable { return caseDb.getTagNamesInUse(); } - public synchronized List getTagNamesForPropertyFile() throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed."); - } + /** + * Gets a list of all tag names associated with the ones found in the + * properties file. + * + * @return A list, possibly empty, of TagName data transfer objects (DTOs). + */ + public synchronized List getTagNamesForPropertyFile() { lazyLoadExistingTagNames(); - addTagNamesFromTagsSettings(); List propertyFileTagNames = new ArrayList<>(); String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); @@ -115,13 +118,12 @@ public class TagsManager implements Closeable { List tagNameTuples = Arrays.asList(setting.split(";")); for (String tagNameTuple : tagNameTuples) { String[] tagNameAttributes = tagNameTuple.split(","); - String displayName = tagNameAttributes[0]; - propertyFileTagNames.add(uniqueTagNames.get(displayName)); + propertyFileTagNames.add(uniqueTagNames.get(tagNameAttributes[0])); } } return propertyFileTagNames; } - + /** * Checks whether a tag name with a given display name exists. * @@ -133,7 +135,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return uniqueTagNames.containsKey(tagDisplayName); } - + /** * Adds a new tag name to the current case and to the tags settings. * @@ -153,7 +155,7 @@ public class TagsManager implements Closeable { } return addTagName(displayName, "", TagName.HTML_COLOR.NONE); } - + /** * Adds a new tag name to the current case and to the tags settings. * @@ -174,7 +176,7 @@ public class TagsManager implements Closeable { } return addTagName(displayName, description, TagName.HTML_COLOR.NONE); } - + /** * Adds a new tag name to the current case and to the tags settings. * @@ -195,46 +197,34 @@ public class TagsManager implements Closeable { throw new TskCoreException("Tags manager has been closed"); } lazyLoadExistingTagNames(); + + //The tag name already exists in the database, user either + //1) adding it again by error -> throws TagNameAlreadyExistsException + //2) adding it after it was deleted at some point in the past if (uniqueTagNames.containsKey(displayName)) { - throw new TagNameAlreadyExistsException(); + TagName existingTagName = uniqueTagNames.get(displayName); + long tagNameCount = getContentTagsCountByTagName(existingTagName) + getBlackboardArtifactTagsCountByTagName(existingTagName); + if (tagNameCount > 0) { + throw new TagNameAlreadyExistsException(); + } else { + addNewTagNameToTagsSettings(existingTagName); + } + return existingTagName; } - /* - * Add the tag name to the case. - */ + * Add the tag name to the case. + */ TagName newTagName = caseDb.addTagName(displayName, description, color); - + /* - * Add the tag name to the tags settings. - */ + * Add the tag name to the tags settings. + */ uniqueTagNames.put(newTagName.getDisplayName(), newTagName); addNewTagNameToTagsSettings(newTagName); return newTagName; } - - /** - * Deletes a tag name from the tags settings. - * - * @param displayName The display name for the tag name to be deleted. - * - * @throws TagNameDoesNotExistException - * - * @throws TskCoreException - */ - public synchronized void deleteTagName(String displayName) throws TagNameDoesNotExistException, TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - lazyLoadExistingTagNames(); - if (!uniqueTagNames.containsKey(displayName)) { - throw new TagNameDoesNotExistException(); - } else { - uniqueTagNames.remove(displayName); - saveTagNamesToTagsSettings(); - } - } - + /** * Tags a content object. * @@ -252,7 +242,7 @@ public class TagsManager implements Closeable { } return addContentTag(content, tagName, "", -1, -1); } - + /** * Tags a content object. * @@ -271,7 +261,7 @@ public class TagsManager implements Closeable { } return addContentTag(content, tagName, comment, -1, -1); } - + /** * Tags a content object or a section of a content object. * @@ -295,33 +285,33 @@ public class TagsManager implements Closeable { ContentTag tag; synchronized (this) { lazyLoadExistingTagNames(); - + if (null == comment) { throw new IllegalArgumentException("Passed null comment argument"); } - + if (beginByteOffset >= 0 && endByteOffset >= 1) { if (beginByteOffset > content.getSize() - 1) { throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.beginByteOffsetOOR.msg", beginByteOffset, content.getSize() - 1)); } - + if (endByteOffset > content.getSize() - 1) { throw new IllegalArgumentException( NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endByteOffsetOOR.msg", endByteOffset, content.getSize() - 1)); } - + if (endByteOffset < beginByteOffset) { throw new IllegalArgumentException( NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endLTbegin.msg")); } } - + tag = caseDb.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); } - + try { Case.getCurrentCase().notifyContentTagAdded(tag); } catch (IllegalStateException ex) { @@ -329,7 +319,7 @@ public class TagsManager implements Closeable { } return tag; } - + /** * Deletes a content tag. * @@ -346,14 +336,14 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); caseDb.deleteContentTag(tag); } - + try { Case.getCurrentCase().notifyContentTagDeleted(tag); } catch (IllegalStateException ex) { logger.log(Level.SEVERE, NbBundle.getMessage(TagsManager.class, "TagsManager.deleteContentTag.noCaseWarning"), ex); } } - + /** * Gets all content tags for the current case. * @@ -369,7 +359,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getAllContentTags(); } - + /** * Gets content tags count by tag name. * @@ -387,7 +377,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getContentTagsCountByTagName(tagName); } - + /** * Gets a content tag by tag id. * @@ -405,7 +395,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getContentTagByID(tagID); } - + /** * Gets content tags by tag name. * @@ -424,7 +414,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getContentTagsByTagName(tagName); } - + /** * Gets content tags count by content. * @@ -443,7 +433,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getContentTagsByContent(content); } - + /** * Tags a blackboard artifact object. * @@ -462,7 +452,7 @@ public class TagsManager implements Closeable { } return addBlackboardArtifactTag(artifact, tagName, ""); } - + /** * Tags a blackboard artifact object. * @@ -488,7 +478,7 @@ public class TagsManager implements Closeable { } tag = caseDb.addBlackboardArtifactTag(artifact, tagName, comment); } - + try { Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(tag); } catch (IllegalStateException ex) { @@ -496,7 +486,7 @@ public class TagsManager implements Closeable { } return tag; } - + /** * Deletes a blackboard artifact tag. * @@ -513,14 +503,14 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); caseDb.deleteBlackboardArtifactTag(tag); } - + try { Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); } catch (IllegalStateException ex) { logger.log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.deleteBlackboardArtifactTag.noCaseWarning"), ex); } } - + /** * Gets all blackboard artifact tags for the current case. * @@ -536,7 +526,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getAllBlackboardArtifactTags(); } - + /** * Gets blackboard artifact tags count by tag name. * @@ -555,7 +545,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getBlackboardArtifactTagsCountByTagName(tagName); } - + /** * Gets a blackboard artifact tag by tag id. * @@ -573,7 +563,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getBlackboardArtifactTagByID(tagID); } - + /** * Gets blackboard artifact tags by tag name. * @@ -592,7 +582,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getBlackboardArtifactTagsByTagName(tagName); } - + /** * Gets blackboard artifact tags for a particular blackboard artifact. * @@ -611,7 +601,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getBlackboardArtifactTagsByArtifact(artifact); } - + /** * Closes the tags manager, saving the available tag names to secondary * storage. @@ -625,10 +615,12 @@ public class TagsManager implements Closeable { //saveTagNamesToTagsSettings(); caseDb = null; } - + /** * Populates the tag names collection and the tag names table in the case * database with the existing tag names from all sources. + * + * Tag names from current case are not saved into the settings file. */ private void lazyLoadExistingTagNames() { if (!tagNamesLoaded) { @@ -639,7 +631,7 @@ public class TagsManager implements Closeable { tagNamesLoaded = true; } } - + /** * Adds any tag names that are in the case database to the tag names * collection. @@ -654,7 +646,7 @@ public class TagsManager implements Closeable { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); //NON-NLS } } - + /** * Adds any tag names that are in the properties file to the tag names * collection and to the case database. The properties file is used to make @@ -665,7 +657,7 @@ public class TagsManager implements Closeable { if (null != setting && !setting.isEmpty()) { // Read the tag name setting and break it into tag name tuples. List tagNameTuples = Arrays.asList(setting.split(";")); - + // Parse each tuple and add the tag names to the current case, one // at a time to gracefully discard any duplicates or corrupt tuples. for (String tagNameTuple : tagNameTuples) { @@ -681,7 +673,7 @@ public class TagsManager implements Closeable { } } } - + /** * Adds the standard tag names to the tag names collection. */ @@ -696,7 +688,7 @@ public class TagsManager implements Closeable { } } } - + /** * Saves the tag names to a properties file. The properties file is used to * make it possible to use tag names across cases. @@ -717,7 +709,8 @@ public class TagsManager implements Closeable { } /** - * + * Adds a new tag name to the settings file, used when user creates a new + * tag name. */ private void addNewTagNameToTagsSettings(TagName tagName) { String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); @@ -727,7 +720,7 @@ public class TagsManager implements Closeable { else { setting += ";"; } - setting += tagName.getDisplayName() + "," + tagName.getDescription() + "," + tagName.getColor().name(); + setting += tagName.getDisplayName() + "," + tagName.getDescription() + "," + tagName.getColor().toString(); ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting); } @@ -735,7 +728,7 @@ public class TagsManager implements Closeable { * Exception thrown if there is an attempt to add a duplicate tag name. */ public static class TagNameAlreadyExistsException extends Exception { - + private static final long serialVersionUID = 1L; } @@ -745,5 +738,5 @@ public class TagsManager implements Closeable { public static class TagNameDoesNotExistException extends Exception { } - + } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.form index a0ea7e8def..1565b9671c 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.form @@ -157,6 +157,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java index 7d47fcbf8a..a8881657d7 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java @@ -5,6 +5,7 @@ */ package org.sleuthkit.autopsy.casemodule.services; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -22,8 +23,10 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.datamodel.TskCoreException; /** - * - * @author smori + * A panel to allow the user to create new tag names or to delete tag names that + * user has created in the past. List of user tag names is maintained in a + * properties file, able to be used across cases. + * Potentially room to add other tag name options in the future. */ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements OptionsPanel { @@ -35,10 +38,11 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio private final DefaultListModel tagNamesListModel; private Set tagNames; + private List newDisplayNames; /** - * Creates new form TagsManagerPanel + * Creates new form TagsManagerOptionsPanel */ public TagsManagerOptionsPanel() { initComponents(); @@ -46,10 +50,17 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio tagNamesListModel = new DefaultListModel<>(); tagNamesList.setModel(tagNamesListModel); tagNames = getTagNamesFromTagsSettings(); + newDisplayNames = new ArrayList(); + userTagNameTextField.setText(""); tagNameErrLabel.setText(""); } + /** + * Gets tag names from properties file. + * + * @return A set, possibly empty, of CustomTagName objects + */ private Set getTagNamesFromTagsSettings() { Set tagNamesFromSettings = new TreeSet<>(); String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); @@ -64,6 +75,9 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio return tagNamesFromSettings; } + /** + * Updates the tag names model for the tag names list component. + */ private void updateTagNamesListModel() { tagNamesListModel.clear(); tagNames.stream().forEach((tagName) -> { @@ -105,6 +119,11 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio jScrollPane1.setViewportView(tagNamesList); userTagNameTextField.setText(org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.userTagNameTextField.text")); // NOI18N + userTagNameTextField.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + userTagNameTextFieldActionPerformed(evt); + } + }); addTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(addTagNameButton, org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.text")); // NOI18N @@ -209,20 +228,28 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio ); }// //GEN-END:initComponents + /** + * Adds a new tag name to the tag names list component without necessarily + * saving the changes. + * + * @param evt ActionEvent generated by clicking the Add Tag Name button + */ private void addTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addTagNameButtonActionPerformed - String newTagName = userTagNameTextField.getText(); + String newDisplayName = userTagNameTextField.getText(); - if (newTagName.isEmpty()) { + if (newDisplayName.isEmpty()) { tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.empty")); return; } - if (newTagName.contains(",") || newTagName.contains(";")) { + if (newDisplayName.contains(",") || newDisplayName.contains(";")) { tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.containCommaSemicolon")); return; } - CustomTagName tagName = new CustomTagName(newTagName, DEFAULT_DESCRIPTION, DEFAULT_COLOR_STRING); + CustomTagName tagName = new CustomTagName(newDisplayName, DEFAULT_DESCRIPTION, DEFAULT_COLOR_STRING); + boolean addedToTagNames = tagNames.add(tagName); + if (!addedToTagNames) { tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.alreadyExists")); return; @@ -230,12 +257,19 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio updateTagNamesListModel(); + newDisplayNames.add(newDisplayName); userTagNameTextField.setText(""); tagNameErrLabel.setText(""); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_addTagNameButtonActionPerformed + /** + * Deletes a tag name from the tag names list component without saving the + * changes. + * + * @param evt ActionEvent generated by clicking the Delete Tag Name button + */ private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagNameButtonActionPerformed CustomTagName tagName = tagNamesList.getSelectedValue(); if (tagName == null) { @@ -251,6 +285,15 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } }//GEN-LAST:event_deleteTagNameButtonActionPerformed + + /** + * Activates addTagNameButtonActionPerformed instead of the OptionsPanel OK + * button when the userTagNameTextField experiences an action. + * @param evt ActionEvent + */ + private void userTagNameTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_userTagNameTextFieldActionPerformed + addTagNameButtonActionPerformed(evt); + }//GEN-LAST:event_userTagNameTextFieldActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables @@ -268,8 +311,25 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio private javax.swing.JTextField userTagNameTextField; // End of variables declaration//GEN-END:variables + /** + * Stores tag name changes in the properties file, called when OK or Apply + * is selected in the OptionsPanel. + * + * Adds all new tag names to the case database for use. + */ @Override public void store() { + for (String displayName : newDisplayNames) { + try { + Case.getCurrentCase().getServices().getTagsManager().addTagName(displayName); + } catch (TagsManager.TagNameAlreadyExistsException ex) { + //Do nothing, this is just to update the database + } catch (TskCoreException ex) { + Logger.getLogger(TagsManagerOptionsPanel.class.getName()).log(Level.SEVERE, "Error adding " + displayName + " tag name", ex); + } + } + newDisplayNames = new ArrayList<>(); + StringBuilder builder = new StringBuilder(); for (CustomTagName tagName : tagNames) { if (builder.length() != 0) { @@ -280,6 +340,10 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, builder.toString()); } + /** + * Updates the tag names list component with tag names from the properties + * file. + */ @Override public void load() { tagNames = getTagNamesFromTagsSettings(); @@ -290,14 +354,19 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio tagNameErrLabel.setText(""); } + /** + * Discards changes made to the tag names list component if Cancel button is + * selected in the OptionsPanel. + */ public void cancelChanges() { tagNames = getTagNamesFromTagsSettings(); + newDisplayNames = new ArrayList<>(); } /** - * Because TagName constructor is not public, CustomTagName is used in this - * tags managers panel for the purpose of preserving description and color - * information that is tracked by the user tag settings file. + * Because the DTO TagName constructor should not be called outside of its + * class package, CustomTagName is used in this tags managers panel for the + * purpose of tracking the description and color of each tag name. */ private class CustomTagName implements Comparable { private final String displayName; @@ -340,6 +409,10 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio return displayName; } + /** + * @return A String with of the tag name in the format that is used by + * the properties file. + */ public String toSettingsFormat() { return displayName + "," + description + "," + colorName; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java index bb876d82df..111daaeb68 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java @@ -18,7 +18,7 @@ import org.openide.util.Lookup; iconBase = "org/sleuthkit/autopsy/modules/filetypeid/user-defined-file-types-settings.png", keywords = "#OptionsCategory_Keywords_TagsManager", keywordsCategory = "TagsManager", - position = 10 + position = 8 ) public final class TagsManagerOptionsPanelController extends OptionsPanelController { @@ -26,12 +26,20 @@ public final class TagsManagerOptionsPanelController extends OptionsPanelControl private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private boolean changed; + /** + * Component should load its data here. + */ @Override public void update() { getPanel().load(); changed = false; } + /** + * This method is called when both the Ok and Apply buttons are pressed. It + * applies to any of the panels that have been opened in the process of + * using the options pane. + */ @Override public void applyChanges() { if (changed) { @@ -40,6 +48,11 @@ public final class TagsManagerOptionsPanelController extends OptionsPanelControl } } + /** + * This method is called when the Cancel button is pressed. It applies to + * any of the panels that have been opened in the process of using the + * options pane. + */ @Override public void cancel() { if (changed) { @@ -51,9 +64,14 @@ public final class TagsManagerOptionsPanelController extends OptionsPanelControl @Override public boolean isValid() { return true; - //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } + /** + * Used to determine whether any changes have been made to this controller's + * panel. + * + * @return Whether or not a change has been made. + */ @Override public boolean isChanged() { return changed; From 5cc160c2d5a6ad376085f9350f804d346997a935 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Thu, 25 Aug 2016 15:26:51 -0400 Subject: [PATCH 09/54] Removed unused import --- .../autopsy/casemodule/services/TagsManagerOptionsPanel.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java index a8881657d7..37bec75390 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java @@ -14,7 +14,6 @@ import java.util.TreeSet; import java.util.logging.Level; import javax.swing.DefaultListModel; import org.netbeans.spi.options.OptionsPanelController; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; From d06aab353254bb4619e3411dfda4995a85cd0ff2 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Thu, 25 Aug 2016 15:29:19 -0400 Subject: [PATCH 10/54] Removed another unused import --- .../org/sleuthkit/autopsy/casemodule/services/TagsManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index bfb01e577c..e838e24c7b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -22,7 +22,6 @@ import java.io.Closeable; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; From ac1b28ebe30ae2ce18643a8cb4268c8f5707403e Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Fri, 26 Aug 2016 10:13:28 -0400 Subject: [PATCH 11/54] Disallowed commas and semicolons as potential characters in tag names --- .../autopsy/actions/Bundle.properties | 2 +- .../autopsy/actions/GetTagNameDialog.java | 13 +-------- .../casemodule/services/Bundle.properties | 2 +- .../casemodule/services/TagsManager.java | 28 +++++++++++++++++-- .../services/TagsManagerOptionsPanel.java | 13 +++++---- 5 files changed, 36 insertions(+), 22 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties index 71ce8a4504..ba828aed5d 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties @@ -42,7 +42,7 @@ GetTagNameDialog.createTag=Create Tag GetTagNameDialog.cancelName=Cancel GetTagNameDialog.mustSupplyTtagName.msg=Must supply a tag name to continue. GetTagNameDialog.tagNameErr=Tag Name -GetTagNameDialog.illegalChars.msg=The tag name contains illegal characters.\nCannot contain any of the following symbols\: \\ \: * ? " < > | +GetTagNameDialog.illegalChars.msg=The tag name contains illegal characters.\nCannot contain any of the following symbols\: \\ \: * ? " < > | , ; GetTagNameDialog.illegalCharsErr=Illegal Characters GetTagNameDialog.unableToAddTagNameToCase.msg=Unable to add the {0} tag name to the case. GetTagNameDialog.taggingErr=Tagging Error diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index b24f69d757..9f6f23282f 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -122,17 +122,6 @@ public class GetTagNameDialog extends JDialog { setVisible(true); } - private boolean containsIllegalCharacters(String content) { - return (content.contains("\\") - || content.contains(":") - || content.contains("*") - || content.contains("?") - || content.contains("\"") - || content.contains("<") - || content.contains(">") - || content.contains("|")); - } - private class TagsTableModel extends AbstractTableModel { private final ArrayList tagNames = new ArrayList<>(); @@ -305,7 +294,7 @@ public class GetTagNameDialog extends JDialog { "GetTagNameDialog.mustSupplyTtagName.msg"), NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagNameErr"), JOptionPane.ERROR_MESSAGE); - } else if (containsIllegalCharacters(tagDisplayName)) { + } else if (TagsManager.containsIllegalCharacters(tagDisplayName)) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalChars.msg"), NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalCharsErr"), diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index 638c8a8412..a7425bfa0d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -10,7 +10,7 @@ TagsManager.addBlackboardArtifactTag.noCaseWarning=Failed to publish new blackbo TagsManager.deleteBlackboardArtifactTag.noCaseWarning=Failed to publish blackboard artifact tag deleted event. There is no case open. Blackboard.unableToIndexArtifact.error.msg=Unable to index blackboard artifact {0} TagsManagerOptionsPanel.addTagNameButton.empty=Tag name text is empty. -TagsManagerOptionsPanel.addTagNameButton.containCommaSemicolon=Tag name may not contain commas or semicolons. +TagsManagerOptionsPanel.addTagNameButton.containInvalidCharacter=Tag name may not contain any of the following symbols\: \\ \: * ? " < > | , ; TagsManagerOptionsPanel.addTagNameButton.alreadyExists=Tag name already exists. TagsManagerOptionsPanel.jLabel1.text=Autopsy keeps a list of the tag names you have created in the past. Add more or delete them here. TagsManagerOptionsPanel.tagNamesListLabel.text=Your tag names: diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index e838e24c7b..6848f5cb0a 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -143,7 +143,7 @@ public class TagsManager implements Closeable { * @return A TagName data transfer object (DTO) representing the new tag * name. * - * @throws TagNameAlreadyExistsException If the tag name would be a + * @throws TagNameAlreadyExistsException If the tag name would be a * duplicate. * @throws TskCoreException If there is an error adding the tag * to the case database. @@ -164,7 +164,7 @@ public class TagsManager implements Closeable { * @return A TagName data transfer object (DTO) representing the new tag * name. * - * @throws TagNameAlreadyExistsException If the tag name would be a + * @throws TagNameAlreadyExistsException If the tag name would be a * duplicate. * @throws TskCoreException If there is an error adding the tag * to the case database. @@ -186,7 +186,7 @@ public class TagsManager implements Closeable { * @return A TagName data transfer object (DTO) representing the new tag * name. * - * @throws TagNameAlreadyExistsException If the tag name would be a + * @throws TagNameAlreadyExistsException If the tag name would be a * duplicate. * @throws TskCoreException If there is an error adding the tag * to the case database. @@ -195,6 +195,7 @@ public class TagsManager implements Closeable { if (null == caseDb) { throw new TskCoreException("Tags manager has been closed"); } + lazyLoadExistingTagNames(); //The tag name already exists in the database, user either @@ -723,6 +724,26 @@ public class TagsManager implements Closeable { ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting); } + /** + * Returns true if the tag display name contains an illegal character. Used + * after a tag display name is retrieved from user input. + * + * @param content Display name of the tag being added. + * @return boolean indicating whether the name has an invalid character. + */ + public static boolean containsIllegalCharacters(String content) { + return (content.contains("\\") + || content.contains(":") + || content.contains("*") + || content.contains("?") + || content.contains("\"") + || content.contains("<") + || content.contains(">") + || content.contains("|") + || content.contains(",") + || content.contains(";")); + } + /** * Exception thrown if there is an attempt to add a duplicate tag name. */ @@ -733,6 +754,7 @@ public class TagsManager implements Closeable { /** * Exception thrown if there is an attempt to delete a nonexistent tag name. + * Unused for current implementation of tag name deletion. */ public static class TagNameDoesNotExistException extends Exception { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java index 37bec75390..f63059e85e 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java @@ -14,6 +14,7 @@ import java.util.TreeSet; import java.util.logging.Level; import javax.swing.DefaultListModel; import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; @@ -49,7 +50,7 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio tagNamesListModel = new DefaultListModel<>(); tagNamesList.setModel(tagNamesListModel); tagNames = getTagNamesFromTagsSettings(); - newDisplayNames = new ArrayList(); + newDisplayNames = new ArrayList<>(); userTagNameTextField.setText(""); tagNameErrLabel.setText(""); @@ -240,8 +241,8 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.empty")); return; } - if (newDisplayName.contains(",") || newDisplayName.contains(";")) { - tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.containCommaSemicolon")); + if (TagsManager.containsIllegalCharacters(newDisplayName)) { + tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.containInvalidCharacter")); return; } @@ -281,6 +282,8 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio tagNamesList.setSelectedIndex(0); } + newDisplayNames.remove(tagName.getDisplayName()); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } }//GEN-LAST:event_deleteTagNameButtonActionPerformed @@ -409,8 +412,8 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio } /** - * @return A String with of the tag name in the format that is used by - * the properties file. + * @return A string representation of the tag name in the format that is + * used by the properties file. */ public String toSettingsFormat() { return displayName + "," + description + "," + colorName; From bbd68e3f0efb4bbf3664da7d4ada584b8c4f9614 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Fri, 2 Sep 2016 13:04:05 -0400 Subject: [PATCH 12/54] Added appropriate icon images and reverted a public method change --- .../autopsy/actions/AddTagAction.java | 2 +- .../actions/GetTagNameAndCommentDialog.java | 2 +- .../autopsy/actions/GetTagNameDialog.java | 2 +- .../casemodule/services/TagsManager.java | 27 ++++++++++++++---- .../services/TagsManagerOptionsPanel.form | 4 +-- .../services/TagsManagerOptionsPanel.java | 10 +++++-- .../TagsManagerOptionsPanelController.java | 2 +- .../casemodule/services/tags-manager.png | Bin 0 -> 1215 bytes .../org/sleuthkit/autopsy/images/add-tag.png | Bin 0 -> 1658 bytes .../sleuthkit/autopsy/images/delete-tag.png | Bin 0 -> 1698 bytes .../org/sleuthkit/autopsy/images/edit-tag.png | Bin 0 -> 1755 bytes 11 files changed, 34 insertions(+), 15 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/tags-manager.png create mode 100755 Core/src/org/sleuthkit/autopsy/images/add-tag.png create mode 100755 Core/src/org/sleuthkit/autopsy/images/delete-tag.png create mode 100755 Core/src/org/sleuthkit/autopsy/images/edit-tag.png diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index 7f4f813495..7db5a5e0ee 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -89,7 +89,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); List tagNames = null; try { - tagNames = tagsManager.getAllTagNames(); + tagNames = tagsManager.getAllTagNamesForDisplay(); Collections.sort(tagNames); } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index 9a82e445e1..19b32e3905 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -117,7 +117,7 @@ public class GetTagNameAndCommentDialog extends JDialog { TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); List currentTagNames = null; try { - currentTagNames = tagsManager.getAllTagNames(); + currentTagNames = tagsManager.getAllTagNamesForDisplay(); } catch (TskCoreException ex) { Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index 9f6f23282f..fd8634e123 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -98,7 +98,7 @@ public class GetTagNameDialog extends JDialog { TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); List currentTagNames = null; try { - currentTagNames = tagsManager.getAllTagNames(); + currentTagNames = tagsManager.getAllTagNamesForDisplay(); } catch (TskCoreException ex) { Logger.getLogger(GetTagNameDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 6848f5cb0a..fcd7b051bd 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -62,12 +62,11 @@ public class TagsManager implements Closeable { TagsManager(SleuthkitCase caseDb) { this.caseDb = caseDb; } - + /** * Gets a list of all tag names currently available for tagging content or - * artifacts. Available tag names include tag names currently being used or - * tag names loaded from the properties file. - * + * artifacts. + * * @return A list, possibly empty, of TagName data transfer objects (DTOs). * * @throws TskCoreException If there is an error reading from the case @@ -78,7 +77,23 @@ public class TagsManager implements Closeable { throw new TskCoreException("Tags manager has been closed"); } lazyLoadExistingTagNames(); - //return caseDb.getAllTagNames(); + return caseDb.getAllTagNames(); + } + + /** + * Gets a list of all tag names currently being used or tag names loaded + * from the properties file. + * + * @return A list, possibly empty, of TagName data transfer objects (DTOs). + * + * @throws TskCoreException If there is an error reading from the case + * database. + */ + public synchronized List getAllTagNamesForDisplay() throws TskCoreException { + if (null == caseDb) { + throw new TskCoreException("Tags manager has been closed"); + } + lazyLoadExistingTagNames(); Set tagNameSet = new HashSet<>(); tagNameSet.addAll(getTagNamesInUse()); tagNameSet.addAll(getTagNamesForPropertyFile()); @@ -108,7 +123,7 @@ public class TagsManager implements Closeable { * * @return A list, possibly empty, of TagName data transfer objects (DTOs). */ - public synchronized List getTagNamesForPropertyFile() { + private synchronized List getTagNamesForPropertyFile() { lazyLoadExistingTagNames(); List propertyFileTagNames = new ArrayList<>(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.form index 1565b9671c..fc35b992fe 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.form @@ -164,7 +164,7 @@ - + @@ -177,7 +177,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java index f63059e85e..17343d9690 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java @@ -14,7 +14,6 @@ import java.util.TreeSet; import java.util.logging.Level; import javax.swing.DefaultListModel; import org.netbeans.spi.options.OptionsPanelController; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; @@ -33,6 +32,8 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS + private static final String TAG_BOOKMARK = "Bookmark"; + private static final String DEFAULT_DESCRIPTION = ""; private static final String DEFAULT_COLOR_STRING = "NONE"; @@ -71,7 +72,10 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio CustomTagName tagName = new CustomTagName(tagNameAttributes[0], tagNameAttributes[1], tagNameAttributes[2]); tagNamesFromSettings.add(tagName); } + } else { + tagNamesFromSettings.add(new CustomTagName(TAG_BOOKMARK, DEFAULT_DESCRIPTION, DEFAULT_COLOR_STRING)); } + return tagNamesFromSettings; } @@ -125,7 +129,7 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio } }); - addTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N + addTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add-tag.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(addTagNameButton, org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.text")); // NOI18N addTagNameButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -133,7 +137,7 @@ public class TagsManagerOptionsPanel extends javax.swing.JPanel implements Optio } }); - deleteTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete16.png"))); // NOI18N + deleteTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete-tag.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(deleteTagNameButton, org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.deleteTagNameButton.text")); // NOI18N deleteTagNameButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java index 111daaeb68..18c15f9c46 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java @@ -15,7 +15,7 @@ import org.openide.util.Lookup; @OptionsPanelController.TopLevelRegistration( categoryName = "#OptionsCategory_Name_TagsManager", - iconBase = "org/sleuthkit/autopsy/modules/filetypeid/user-defined-file-types-settings.png", + iconBase = "org/sleuthkit/autopsy/casemodule/services/tags-manager.png", keywords = "#OptionsCategory_Keywords_TagsManager", keywordsCategory = "TagsManager", position = 8 diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/tags-manager.png b/Core/src/org/sleuthkit/autopsy/casemodule/services/tags-manager.png new file mode 100755 index 0000000000000000000000000000000000000000..b782cfe010a80106eb4915832d74e7a18aaceeab GIT binary patch literal 1215 zcmV;w1VH5w5QqH~So^w9m=eg&e=Rpbt0`xr1z<*4Y zl@##%pLvn8>S`)qy_zJQjwDG^es(;n5ls90(&59`4gW=bX;qc{(*Yb~c0~4-OP!r3 zIl?T6O^O)s&Y?r^h9aQVY!ww$f~ds-hv7$#ob(~83iRgv`}Ehthg5?|HQDW?yn0On zR+g2Kt-L%DSb^IwA3Zwc^Z9~3{5sG$XJ*K3u}I@HGcpxp zeSHJ}Jb5Avdt|@CV4%0#+FCIB9-?qJ>L}J=YZ-p6zyIs``T5`pmn7`mrlh3Mrq*B!G3XtL74GkTi#&Nm?o`*M z%gM>f_`o=Q%hS{8jorK3Ww>5{OLaxG1n&2*`|0f2FD4#8j(fJp6Oq1R1--s&*N5o2 z4bR6km1HsShM&)!>vc{{s5)fWGBPsgwVgXVaCu7$JXSy>!rm}^{`}`or&HD0&TS^( z8+PpY2-lk7kpkAU=f7OI(Bl{%7lu8u-<+9AuWsM|F@}!;KB^YVIYE!pF(d%+#v2ze zb~_x7CB;M{5oWWQnzn5_s0GgXz=Tg!ZwLoo&V~s6=!UIZKgmV8M1pLlv=)nn)?+-+ z<9ah0m~+8$Y|=D*C6Vxu0A2(|0VC5l*S1Uq?Hv``M}N+VLRR+FCh dzvur7FaRGqTh2a`r+)wd002ovPDHLkV1oB1R%rkL literal 0 HcmV?d00001 diff --git a/Core/src/org/sleuthkit/autopsy/images/add-tag.png b/Core/src/org/sleuthkit/autopsy/images/add-tag.png new file mode 100755 index 0000000000000000000000000000000000000000..e60e692bacf25a4168180602ae858586113dea8f GIT binary patch literal 1658 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`Jj+tIX_n~5oC^DMQ#CujeSKy zVsdtBi9%9pdS;%jl7fPQl0s&Rtx~wDuYqrYb81GWM^#a3aFt(3a#eP+Wr~u$9hXgo z6;N|-YDuC(MQ%=Bu~mhw64*>DAR8pCucQE0Qj%?}1aWkPZ-9bxeo?A|iJqZuvVpOQ zf{B@)k-3qjxtWeaaAJvqS7M%mk-37AfdP;(vNANZGBE@?1`L$!xPY`xQA(Oskc%7C zP9V=#DWjyMz)D}gyu4hm+*mKaC|%#s($Z4jz)0W7NEfI=x41H|B(Xv_uUHvk2+SOp z)Z*l#%mQ$5fy_-z$}cUkRZ;?31P4&hB^JOf$}5Hj9xxd7D-sLz4fPE4;U)t$+5iQu zz!8yO6q28xV}~WqY(P3u6d`Oy=udS?EJ?KkhKGf&fswAEd5D3Lm9d$XiD?v)euyG8 z?Y{XbnQ4_s+KqLMOhODTtqcsTOpKt~krY9-+vtM=0x4j?p$_sBnz#ai082@RhgU&q zQ4Tm-Qj+ykb5e6t^Gb?=VP=RLW+};5Y57IDi6wTKxryni`UQFEHu?xbyzYaz8kj7A z$x`D0-@5LI7SBsl$YuZpw;nD$jBzc1r(0 z`=*gw|NGtVr+0q0Ra}}PbNmFGr^#$z#ic6uLRMdO*`;s3g2?h_U_Abl4y+!Bsu{taER+U8> zO{-R=zdrp`$Wh?H_gamvrl6H9mraZ(|5j&YIQ($J(;~^+Z^ib#Km6I|Ns*-p7i-3> zHm{{cl^z@utt{ew_upThC}Ao^tJ>Q)f4%3+>q?3(0-4rcTp3%V zk~T&t@Hnqn)m3B1?|ZqxLWY5%-p`Z4Vfp2qxA_b*fAM>Q8^GU7_%CS>ASThKk-vC*Cpk u^WNE^Y1e%8c}mC3KmP^S-9BlzWWTkgZ*Gc0WgW2mXYh3Ob6Mw<&;$U8UH+v2 literal 0 HcmV?d00001 diff --git a/Core/src/org/sleuthkit/autopsy/images/delete-tag.png b/Core/src/org/sleuthkit/autopsy/images/delete-tag.png new file mode 100755 index 0000000000000000000000000000000000000000..25edd1ab6bb33c22b5275bc245cb90e81e2712f9 GIT binary patch literal 1698 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`Jj+tIX_n~5oC^DMQ#CujeSKy zVsdtBi9%9pdS;%jl7fPQl0s&Rtx~wDuYqrYb81GWM^#a3aFt(3a#eP+Wr~u$9hXgo z6;N|-YDuC(MQ%=Bu~mhw64*>DAR8pCucQE0Qj%?}1aWkPZ-9bxeo?A|iJqZuvVpOQ zf{B@)k-3qjxtWeaaAJvqS7M%mk-37AfdP;(vNANZGBE@?1`L$!xPY`xQA(Oskc%7C zP9V=#DWjyMz)D}gyu4hm+*mKaC|%#s($Z4jz)0W7NEfI=x41H|B(Xv_uUHvk2+SOp z)Z*l#%mQ$5fy_-z$}cUkRZ;?31P4&hB^JOf$}5Hj9xxd7D-sLz4fPE4;U)t$+5iQu zz!8yO6q28xV}~WqY(P3u6d`Oy=udS?EJ?KkhKGf&fswAEd5D3Lm9d$XiD?v)euyG8 z?Y{XbnQ4_s+KqLMOhODTtqcsTOpKt~krY9-+vtM=0x4j?p$_sBnz#ai082@RhgU&q zQ4Tm-Qj+ykb5e6t^Gb?=VP=RLW+};5Y57IDi6wTKxryni`UQFEHu?xbyzYaz8kj7A z$xkBVZ1|p4AzCwQby<%WR99S_^P#VD3Y^zVQ{R?Zo6Y9ke6y!)_u0RHZSUrZH@qzQ_3o>|lXvg@7#I@_Bm}yT zT3A~%Cv1(Hc>Z~zjJv$z?`KIHGcru1fW~E+&E|Uj>Xlc2e}C5Y+pDg>X8-uTc!SEu zn>iL%R$Pn9tz^Sii|%`$94WRfH+c0`r^(fm8F%d47iKj#%|hnUZ@YQV1v_0jjz4x; z9H?_T$!`AT*I!qJXdTR#Nai^6^y$)1KW%Qm6+8cV#@V!rdBc0kz_BhF(DM=ETd{rF+=;lNRA28X?I({pdTC<$`4 zGU-2i>*Zthft{ftYVEQREmyPIs&f68&D*cndDz(4)Li=)e>E%A+}vEM*KN|0{Q^3k zRaI4!_IYgxUw%1IZ~Ee&o=x-P&noD67CD{WuVVKrU-f0oq`9(86N-u literal 0 HcmV?d00001 diff --git a/Core/src/org/sleuthkit/autopsy/images/edit-tag.png b/Core/src/org/sleuthkit/autopsy/images/edit-tag.png new file mode 100755 index 0000000000000000000000000000000000000000..4bc2a7ec131d3bd0bcc982feb699d9c8b8e194d6 GIT binary patch literal 1755 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`JjxV%QuQiw3m9zdD+&^mvr|hHl2X$%^K6wA z6cm&cGE;1o!cBb*d<&dYGcrA@ic*8C{6dnevXd=Slr%ES=p7%)(>;{wt)MJZ`kK`w4kJAph~rHqo20xNy} z^73-Ma$~*xqI7*jOG`_A10#JSBVC{h-Qvo;lEez#ykcdDAuw}XQj3#|G7CyF^Yauy z<|ZcPmzLNnDS<441E}W`3*Z*z6+;6L7>xQAi3R$GdItJ%lYts-fPz-eMX8A;`9&f5 z`8jqF@4ICdrIzOxWfvXKNJY6lDt3ta;vT|@H_10ySAGbO1mn?toDDS~RZ(FX+tQow*i9poo8aY6x>k_->8 zg3_WKaI~Z(>!;?V=BDPA6a&M|5H-wFlC9G6i*gf7>@sr`(^K^e^3rYe5rTN#2XQqp zSpbuzK0IB*oDPplnlKRIP7~uHhSJg!jsqEwfF*_~sBi!$T2OWf$;?etkVo^j2MnSp^x+|$J|#G<8brF1H2?wEP-?o#iAOP#;}>-pEPEmJerI7L9D(=cGogaRE6lL;>pTs^$K&-xxZ ztGaV%KKounx25_r=Z-(zbN*+=`EN<-v9PySpXf2+Y#O5k58IL;&28JZnecL+o#}HdDL>zTZ=C<{-@j*FdG~IepTGar z43jMzHx{n`Yrq~YwC}xeuiNpp^78V=5UvxEm2(^oeNo8 zffCnCJ6)8{oIfwze|%%^?7Z!#Z{C#5&d%P>$gniXb7e@^#f+BMyDa*eU++>8;!N5o z!SJ$V*8TVKkLyesY<`9unmvMvMsi#KT+S*|p8{RWB Date: Fri, 16 Sep 2016 16:00:45 +0200 Subject: [PATCH 13/54] change to a more generic account type --- .../sleuthkit/autopsy/datamodel/Accounts.java | 26 +++++++++---------- .../autopsy/datamodel/ExtractedContent.java | 4 +-- .../sleuthkit/autopsy/report/ReportHTML.java | 2 +- .../autopsy/report/TableReportGenerator.java | 2 +- .../keywordsearch/ExtractedContentViewer.java | 12 ++++----- .../keywordsearch/KeywordSearchList.java | 2 +- .../keywordsearch/TermComponentQuery.java | 16 +++++++----- 7 files changed, 34 insertions(+), 30 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java index ab4571395d..666b4f91cc 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java @@ -64,7 +64,6 @@ import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; @@ -77,7 +76,7 @@ import org.sleuthkit.datamodel.TskCoreException; public class Accounts extends Observable implements AutopsyVisitableItem { private static final Logger LOGGER = Logger.getLogger(Accounts.class.getName()); - private static final BlackboardArtifact.Type CREDIT_CARD_ACCOUNT_TYPE = new BlackboardArtifact.Type(TSK_CREDIT_CARD_ACCOUNT); + private static final BlackboardArtifact.Type ACCOUNT_TYPE = new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT); @NbBundle.Messages("AccountsRootNode.name=Accounts") final public static String NAME = Bundle.AccountsRootNode_name(); @@ -183,7 +182,6 @@ public class Accounts extends Observable implements AutopsyVisitableItem { notifyObservers(); } - /** * Get an IINInfo object with details about the given IIN * @@ -487,7 +485,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { * for the event to have a null oldValue. */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); - if (null != eventData && CREDIT_CARD_ACCOUNT_TYPE.equals(eventData.getBlackboardArtifactType())) { + if (null != eventData && ACCOUNT_TYPE.equals(eventData.getBlackboardArtifactType())) { Accounts.this.update(); } } catch (IllegalStateException notUsed) { @@ -764,14 +762,17 @@ public class Accounts extends Observable implements AutopsyVisitableItem { protected boolean createKeys(List list) { String query = "SELECT blackboard_artifacts.obj_id," //NON-NLS - + " blackboard_attributes.value_text AS solr_document_id, " //NON-NLS + + " solr_attribute.value_text AS solr_document_id, " //NON-NLS + " GROUP_CONCAT(blackboard_artifacts.artifact_id) AS artifact_IDs, " //NON-NLS + " COUNT( blackboard_artifacts.artifact_id) AS hits, " //NON-NLS + " GROUP_CONCAT(blackboard_artifacts.review_status_id) AS review_status_ids " + " FROM blackboard_artifacts " //NON-NLS - + " LEFT JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS - + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SOLR_DOCUMENT_ID.getTypeID() //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID() //NON-NLS + + " LEFT JOIN blackboard_attributes as solr_attribute ON blackboard_artifacts.artifact_id = solr_attribute.artifact_id " //NON-NLS + + " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SOLR_DOCUMENT_ID.getTypeID() //NON-NLS + + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS + + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + + " AND account_type.value_text = 'credit_card'" //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + getRejectedArtifactFilterClause() + " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS + " ORDER BY hits DESC "; //NON-NLS @@ -1030,8 +1031,8 @@ public class Accounts extends Observable implements AutopsyVisitableItem { + " COUNT(blackboard_artifacts.artifact_id) AS count " //NON-NLS + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID() //NON-NLS - + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER.getTypeID() //NON-NLS + getRejectedArtifactFilterClause() + " GROUP BY BIN " //NON-NLS + " ORDER BY BIN "; //NON-NLS @@ -1107,7 +1108,6 @@ public class Accounts extends Observable implements AutopsyVisitableItem { return iinEnd; } - public long getCount() { return count; } @@ -1180,8 +1180,8 @@ public class Accounts extends Observable implements AutopsyVisitableItem { = "SELECT blackboard_artifacts.artifact_id " //NON-NLS + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID() //NON-NLS - + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER.getTypeID() //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER.getTypeID() //NON-NLS + " AND blackboard_attributes.value_text >= \"" + bin.getIINStart() + "\" AND blackboard_attributes.value_text < \"" + (bin.getIINEnd() + 1) + "\"" //NON-NLS + getRejectedArtifactFilterClause() + " ORDER BY blackboard_attributes.value_text"; //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index e638794da1..4a420f926d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT; @@ -201,7 +201,7 @@ public class ExtractedContent implements AutopsyVisitableItem { doNotShow.add(new BlackboardArtifact.Type(TSK_KEYWORD_HIT)); doNotShow.add(new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT)); doNotShow.add(new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT)); - doNotShow.add(new BlackboardArtifact.Type(TSK_CREDIT_CARD_ACCOUNT)); + doNotShow.add(new BlackboardArtifact.Type(TSK_ACCOUNT)); } private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index ea32f57537..7b924ad972 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -254,7 +254,7 @@ class ReportHTML implements TableReportModule { case TSK_REMOTE_DRIVE: in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/drive_network.png"); //NON-NLS break; - case TSK_CREDIT_CARD_ACCOUNT: + case TSK_ACCOUNT: in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/credit-card.png"); //NON-NLS break; default: diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java index a7ad4b1415..d2cd7e1d00 100755 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -1449,7 +1449,7 @@ class TableReportGenerator { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.remotePath"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REMOTE_PATH))); - } else if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID()) { + } else if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { columns.add(new StatusColumn()); } else { // This is the case that it is a custom type. The reason an else is diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java index 2dfaa0b4ec..56ef0725d1 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java @@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; -import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; @@ -127,7 +127,7 @@ public class ExtractedContentViewer implements DataContentViewer { //if the node had artifacts in the lookup use them, other wise look up all credit card artifacts for the content. Collection artifacts = nodeLookup.lookupAll(BlackboardArtifact.class); artifacts = (artifacts == null || artifacts.isEmpty()) - ? content.getArtifacts(TSK_CREDIT_CARD_ACCOUNT) + ? content.getArtifacts(TSK_ACCOUNT) : artifacts; /* @@ -148,7 +148,7 @@ public class ExtractedContentViewer implements DataContentViewer { } } - BlackboardAttribute keyWordAttr = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER)); + BlackboardAttribute keyWordAttr = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER)); if (keyWordAttr != null) { String valueString = keyWordAttr.getValueString(); if (StringUtils.isNotBlank(valueString)) { @@ -188,7 +188,7 @@ public class ExtractedContentViewer implements DataContentViewer { * For keyword hit artifacts, add the text of the artifact that hit, * not the hit artifact; otherwise add the text for the artifact. */ - if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) { + if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID() || artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID()) { try { BlackboardAttribute attribute = artifact.getAttribute(TSK_ASSOCIATED_ARTIFACT_TYPE); if (attribute != null) { @@ -296,7 +296,7 @@ public class ExtractedContentViewer implements DataContentViewer { Collection artifacts = node.getLookup().lookupAll(BlackboardArtifact.class); if (artifacts != null) { for (BlackboardArtifact art : artifacts) { - if (art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID()) { + if (art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { return true; } } @@ -321,7 +321,7 @@ public class ExtractedContentViewer implements DataContentViewer { if (art == null) { return 4; } else if (art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() - || art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID()) { + || art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { return 6; } else { return 4; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchList.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchList.java index ab06fc0cbc..3e437caaa8 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchList.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchList.java @@ -122,7 +122,7 @@ abstract class KeywordSearchList { //CCN List ccns = new ArrayList<>(); - ccns.add(new Keyword(CCN_REGEX, false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER)); + ccns.add(new Keyword(CCN_REGEX, false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER)); lockedLists.add("Credit Card Numbers"); addList("Credit Card Numbers", ccns, true, false, true); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java index eea866a2e3..103a8bf573 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java @@ -53,7 +53,9 @@ final class TermComponentQuery implements KeywordSearchQuery { private static final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName(); private static final BlackboardAttribute.Type SOLR_DOCUMENT_ID_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SOLR_DOCUMENT_ID); - private static final BlackboardAttribute.Type ACCOUNT_NUMBER_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER); + private static final BlackboardAttribute.Type ACCOUNT_NUMBER_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER); + private static final BlackboardAttribute.Type ACOUNT_TYPE_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE); + //TODO: move these regex and the luhn check to a new class, something like: CreditCardNumberValidator /* @@ -186,8 +188,10 @@ final class TermComponentQuery implements KeywordSearchQuery { Collection attributes = new ArrayList<>(); try { //if the keyword hit matched the credit card number keyword/regex... - if (keyword.getType() == ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER) { - newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT); + if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER) { + newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT); + newArtifact.addAttribute(new BlackboardAttribute(ACOUNT_TYPE_TYPE, MODULE_NAME, "credit_card")); + // make account artifact //try to match it against the track 1 regex Matcher matcher = TRACK1_PATTERN.matcher(hit.getSnippet()); @@ -323,7 +327,7 @@ final class TermComponentQuery implements KeywordSearchQuery { for (Term term : terms) { final String termStr = KeywordSearchUtil.escapeLuceneQuery(term.getTerm()); - if (keyword.getType() == ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER) { + if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER) { //If the keyword is a credit card number, pass it through luhn validator Matcher matcher = CCN_PATTERN.matcher(term.getTerm()); matcher.find(); @@ -383,7 +387,7 @@ final class TermComponentQuery implements KeywordSearchQuery { BlackboardAttribute.Type type = new BlackboardAttribute.Type(attrType); if (artifact.getAttribute(type) == null) { String value = matcher.group(groupName); - if (attrType.equals(ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER)) { + if (attrType.equals(ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER)) { value = CharMatcher.anyOf(" -").removeFrom(value); } if (StringUtils.isNotBlank(value)) { @@ -404,7 +408,7 @@ final class TermComponentQuery implements KeywordSearchQuery { */ static private void parseTrack2Data(BlackboardArtifact artifact, Matcher matcher) throws IllegalArgumentException, TskCoreException { //try to add all the attrributes common to track 1 and 2 - addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER, "accountNumber", matcher); + addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER, "accountNumber", matcher); addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_EXPIRATION, "expiration", matcher); addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_SERVICE_CODE, "serviceCode", matcher); addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_DISCRETIONARY, "discretionary", matcher); From f3cb08ed8ea5dfa5785206531044262c274adf80 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 19 Sep 2016 13:25:05 +0200 Subject: [PATCH 14/54] fixing reporting for new TSK_ACCOUNT artifact --- .../sleuthkit/autopsy/report/ReportHTML.java | 8 +- .../autopsy/report/TableReportGenerator.java | 114 ++++++++++-------- .../autopsy/report/images/account_menu.png | Bin 0 -> 1484 bytes .../keywordsearch/TermComponentQuery.java | 4 +- 4 files changed, 75 insertions(+), 51 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/report/images/account_menu.png diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 7b924ad972..6065d72237 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -255,7 +255,7 @@ class ReportHTML implements TableReportModule { in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/drive_network.png"); //NON-NLS break; case TSK_ACCOUNT: - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/credit-card.png"); //NON-NLS + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/account_menu.png"); //NON-NLS break; default: logger.log(Level.WARNING, "useDataTypeIcon: unhandled artifact type = " + dataType); //NON-NLS @@ -264,7 +264,11 @@ class ReportHTML implements TableReportModule { iconFilePath = path + File.separator + iconFileName; break; } - } else { // no defined artifact found for this dataType + } else if (dataType.startsWith(ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName())) { + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/account_menu.png"); //NON-NLS + iconFileName = "account_menu.png"; //NON-NLS + iconFilePath = path + File.separator + iconFileName; + } else { // no defined artifact found for this dataType in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/star.png"); //NON-NLS iconFileName = "star.png"; //NON-NLS iconFilePath = path + File.separator + iconFileName; diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java index d2cd7e1d00..f4262f9d57 100755 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -33,6 +33,7 @@ import java.util.Objects; import java.util.Set; import java.util.TreeSet; import java.util.logging.Level; +import java.util.stream.Collectors; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.EscapeUtil; @@ -43,6 +44,7 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.BlackboardAttribute.Type; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; @@ -152,54 +154,70 @@ class TableReportGenerator { continue; } - /* - Gets all of the attribute types of this artifact type by adding - all of the types to a set - */ - Set attrTypeSet = new TreeSet<>((BlackboardAttribute.Type o1, BlackboardAttribute.Type o2) -> o1.getDisplayName().compareTo(o2.getDisplayName())); - for (ArtifactData data : artifactList) { - List attributes = data.getAttributes(); - for (BlackboardAttribute attribute : attributes) { - attrTypeSet.add(attribute.getAttributeType()); + if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + Map> collect = artifactList.stream().collect(Collectors.groupingBy((ArtifactData t) -> { + try { + return t.getArtifact().getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE)).getValueString(); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Unable to get value of TSK_ACCOUNT_TYPE attribute.", ex); + return ""; + } + })); + for (Map.Entry> x : collect.entrySet()) { + writeDataType(x.getValue(), type, BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + x.getKey(), comment); } + } else { + writeDataType(artifactList, type, type.getDisplayName(), comment); } - // Get the columns appropriate for the artifact type. This is - // used to get the data that will be in the cells below based on - // type, and display the column headers. - List columns = getArtifactTableColumns(type.getTypeID(), attrTypeSet); - if (columns.isEmpty()) { - continue; - } - columnHeaderMap.put(type.getTypeID(), columns); - - // The artifact list is sorted now, as getting the row data is - // dependent on having the columns, which is necessary for - // sorting. - Collections.sort(artifactList); - List columnHeaderNames = new ArrayList<>(); - for (Column currColumn : columns) { - columnHeaderNames.add(currColumn.getColumnHeader()); - } - - tableReport.startDataType(type.getDisplayName(), comment.toString()); - tableReport.startTable(columnHeaderNames); - for (ArtifactData artifactData : artifactList) { - // Get the row data for this artifact, and has the - // module add it. - List rowData = artifactData.getRow(); - if (rowData.isEmpty()) { - continue; - } - - tableReport.addRow(rowData); - } - // Finish up this data type - progressPanel.increment(); - tableReport.endTable(); - tableReport.endDataType(); } } + private void writeDataType(List artifactList, BlackboardArtifact.Type type, String dataType, StringBuilder comment) { + /* + * Gets all of the attribute types of this artifact type by adding all + * of the types to a set + */ + Set attrTypeSet = new TreeSet<>((BlackboardAttribute.Type o1, BlackboardAttribute.Type o2) -> o1.getDisplayName().compareTo(o2.getDisplayName())); + for (ArtifactData data : artifactList) { + List attributes = data.getAttributes(); + for (BlackboardAttribute attribute : attributes) { + attrTypeSet.add(attribute.getAttributeType()); + } + } + // Get the columns appropriate for the artifact type. This is + // used to get the data that will be in the cells below based on + // type, and display the column headers. + List columns = getArtifactTableColumns(type.getTypeID(), attrTypeSet); + if (columns.isEmpty()) { + return; + } + columnHeaderMap.put(type.getTypeID(), columns); + // The artifact list is sorted now, as getting the row data is + // dependent on having the columns, which is necessary for + // sorting. + Collections.sort(artifactList); + List columnHeaderNames = new ArrayList<>(); + for (Column currColumn : columns) { + columnHeaderNames.add(currColumn.getColumnHeader()); + } + tableReport.startDataType(dataType, comment.toString()); + tableReport.startTable(columnHeaderNames); + for (ArtifactData artifactData : artifactList) { + // Get the row data for this artifact, and has the + // module add it. + List rowData = artifactData.getRow(); + if (rowData.isEmpty()) { + return; + } + + tableReport.addRow(rowData); + } + // Finish up this data type + progressPanel.increment(); + tableReport.endTable(); + tableReport.endDataType(); + } + /** * Make table for tagged files */ @@ -1451,6 +1469,7 @@ class TableReportGenerator { new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REMOTE_PATH))); } else if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { columns.add(new StatusColumn()); + attributeTypeSet.remove(new Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE)); } else { // This is the case that it is a custom type. The reason an else is // necessary is to make sure that the source file column is added @@ -1584,6 +1603,7 @@ class TableReportGenerator { } } + private class AttributeColumn implements Column { private final String columnHeader; @@ -1643,10 +1663,10 @@ class TableReportGenerator { @Override public String getCellData(ArtifactData artData) { return getFileUniquePath(artData.getContent()); - /*else if (this.columnHeader.equals(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags"))) { - return makeCommaSeparatedList(artData.getTags()); - } - return "";*/ + /* else if + * (this.columnHeader.equals(NbBundle.getMessage(this.getClass(), + * "ReportGenerator.artTableColHdr.tags"))) { return + * makeCommaSeparatedList(artData.getTags()); } return ""; */ } @Override diff --git a/Core/src/org/sleuthkit/autopsy/report/images/account_menu.png b/Core/src/org/sleuthkit/autopsy/report/images/account_menu.png new file mode 100644 index 0000000000000000000000000000000000000000..3a53d894dcd70631d2cf8d7e54eab9e90a9eed58 GIT binary patch literal 1484 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%uvD1M9IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr4|esh*)icxGNo zet9uiy|1s8XI^nhVqS8pr;Du;&;-5A%oHm}XGe1$o&6x?nx!>Lyv=oo!a#3DsBObD2IKumbD1#;jCKQ#}S+KYh6dg+Gzr@%z57j7*|rVD%>T?=)0e3BP&EqUs9Cvr=p^?I!`*}7Qn{`a}Xc@k!k;&L@> zKE`d&T6^|}w1e|lH>VB4WtOy2T|y!YO%e(>)kXV0|V1?zYYOxw10Q+GPU+YDYNb6r1wxAMG# z57$J}{NmeE&+LBE+kQNK%f{qc@4{Wh(@L#2wCVGx@|$~0#NXiSdDEUI^Yf0?N|Pxy z4?g&bbBPIda_}wI*^bvi`4T^s{6F7{*uo1*%~iH zbUanM88=55rEq82ge&rGUb1vr-M900xB8nGeUmZmNO`l}+In{PC$O-7NeWqa zcgaBs^#&1xaIvWq%r9sQKC;*nv3|`Y-#~%y3cR|uv%IUm{L${ZYj$OQ*xl&|T94kD zE9((8X_8aDz0K`s(pFU~Ib9=zkCz4NN=?h!Tb`9+v38H@<)90Zce-NEo#bMeV_>f6bFRzA^mUFY|hOuS`9Q1jAmv2OK{$Yu|#(S5H?zmvv4FO#rRJ BDT)99 literal 0 HcmV?d00001 diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java index 103a8bf573..a52bc7ce7f 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java @@ -55,7 +55,7 @@ final class TermComponentQuery implements KeywordSearchQuery { private static final BlackboardAttribute.Type SOLR_DOCUMENT_ID_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SOLR_DOCUMENT_ID); private static final BlackboardAttribute.Type ACCOUNT_NUMBER_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER); private static final BlackboardAttribute.Type ACOUNT_TYPE_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE); - + private static final String CREDIT_CARD_NUMBER = "Credit Card Number"; //TODO: move these regex and the luhn check to a new class, something like: CreditCardNumberValidator /* @@ -190,7 +190,7 @@ final class TermComponentQuery implements KeywordSearchQuery { //if the keyword hit matched the credit card number keyword/regex... if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER) { newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT); - newArtifact.addAttribute(new BlackboardAttribute(ACOUNT_TYPE_TYPE, MODULE_NAME, "credit_card")); + newArtifact.addAttribute(new BlackboardAttribute(ACOUNT_TYPE_TYPE, MODULE_NAME, CREDIT_CARD_NUMBER)); // make account artifact //try to match it against the track 1 regex From 42d99e31d6304ac4a51f8a72e70f3ec48bb48ef6 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 19 Sep 2016 14:54:45 +0200 Subject: [PATCH 15/54] cleanup and commenting --- .../sleuthkit/autopsy/datamodel/Accounts.java | 7 +- .../sleuthkit/autopsy/report/ReportHTML.java | 6 ++ .../autopsy/report/TableReportGenerator.java | 73 +++++++++++-------- .../keywordsearch/TermComponentQuery.java | 8 +- 4 files changed, 60 insertions(+), 34 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java index 666b4f91cc..046534f773 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java @@ -80,6 +80,11 @@ public class Accounts extends Observable implements AutopsyVisitableItem { @NbBundle.Messages("AccountsRootNode.name=Accounts") final public static String NAME = Bundle.AccountsRootNode_name(); + /** + * This is a secret handshake with + * org.sleuthkit.autopsy.keywordsearch.TermComponentQuery + */ + private static final String CREDIT_CARD_NUMBER_ACCOUNT_TYPE = "Credit Card Number"; /** * Range Map from a (ranges of) B/IINs to data model object with details of * the B/IIN, ie, bank name, phone, url, visa/amex/mastercard/..., @@ -771,7 +776,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { + " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SOLR_DOCUMENT_ID.getTypeID() //NON-NLS + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS - + " AND account_type.value_text = 'credit_card'" //NON-NLS + + " AND account_type.value_text = '" + CREDIT_CARD_NUMBER_ACCOUNT_TYPE + "'" //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + getRejectedArtifactFilterClause() + " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 6065d72237..d04f96ff0b 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -265,6 +265,12 @@ class ReportHTML implements TableReportModule { break; } } else if (dataType.startsWith(ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName())) { + /* TSK_ACCOUNT artifacts get separated by their TSK_ACCOUNT_TYPE + * attribute, with a compund dataType name, so they are not caught + * by the switch statement above. For now we just give them all the + * general account icon, but we could do soemthing else in the + * future. + */ in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/account_menu.png"); //NON-NLS iconFileName = "account_menu.png"; //NON-NLS iconFilePath = path + File.separator + iconFileName; diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java index f4262f9d57..7d0a41fd43 100755 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -18,12 +18,14 @@ */ package org.sleuthkit.autopsy.report; +import com.google.common.collect.Lists; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -121,10 +123,10 @@ class TableReportGenerator { */ private void makeBlackboardArtifactTables() { // Make a comment string describing the tag names filter in effect. - StringBuilder comment = new StringBuilder(); + String comment = ""; if (!tagNamesFilter.isEmpty()) { - comment.append(NbBundle.getMessage(this.getClass(), "ReportGenerator.artifactTable.taggedResults.text")); - comment.append(makeCommaSeparatedList(tagNamesFilter)); + comment += NbBundle.getMessage(this.getClass(), "ReportGenerator.artifactTable.taggedResults.text"); + comment += makeCommaSeparatedList(tagNamesFilter); } // Add a table to the report for every enabled blackboard artifact type. @@ -141,10 +143,10 @@ class TableReportGenerator { // Keyword hits and hashset hit artifacts get special handling. if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - writeKeywordHits(tableReport, comment.toString(), tagNamesFilter); + writeKeywordHits(tableReport, comment, tagNamesFilter); continue; } else if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { - writeHashsetHits(tableReport, comment.toString(), tagNamesFilter); + writeHashsetHits(tableReport, comment, tagNamesFilter); continue; } @@ -154,54 +156,67 @@ class TableReportGenerator { continue; } + /* TSK_ACCOUNT artifacts get grouped by their TSK_ACCOUNT_TYPE + * attribute, and then handed off the default method for writing + * tables. */ if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { - Map> collect = artifactList.stream().collect(Collectors.groupingBy((ArtifactData t) -> { + Map> collect = artifactList.stream().collect(Collectors.groupingBy((ArtifactData artifactData) -> { try { - return t.getArtifact().getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE)).getValueString(); + return artifactData.getArtifact().getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE)).getValueString(); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Unable to get value of TSK_ACCOUNT_TYPE attribute.", ex); - return ""; + logger.log(Level.SEVERE, "Unable to get value of TSK_ACCOUNT_TYPE attribute. Defaulting to \"unknown\"", ex); + return "unknown"; } })); for (Map.Entry> x : collect.entrySet()) { - writeDataType(x.getValue(), type, BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + x.getKey(), comment); + writeTableForDataType(x.getValue(), type, BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + x.getKey(), comment); } } else { - writeDataType(artifactList, type, type.getDisplayName(), comment); + writeTableForDataType(artifactList, type, type.getDisplayName(), comment); } } } - private void writeDataType(List artifactList, BlackboardArtifact.Type type, String dataType, StringBuilder comment) { + /** + * + * Write the given list of artifacts to the table for the given type. + * + * @param artifactList The List of artifacts to include in the table. + * @param type The Type of artifacts included in the table. All the + * artifacts in artifactList should be of this type. + * @param tableName The name of the table. + * @param comment A comment to put in the header. + */ + private void writeTableForDataType(List artifactList, BlackboardArtifact.Type type, String tableName, String comment) { /* - * Gets all of the attribute types of this artifact type by adding all - * of the types to a set + * Make a sorted set of all of the attribute types that are on any of + * the given artifacts. */ - Set attrTypeSet = new TreeSet<>((BlackboardAttribute.Type o1, BlackboardAttribute.Type o2) -> o1.getDisplayName().compareTo(o2.getDisplayName())); + Set attrTypeSet = new TreeSet<>(Comparator.comparing(BlackboardAttribute.Type::getDisplayName)); for (ArtifactData data : artifactList) { List attributes = data.getAttributes(); for (BlackboardAttribute attribute : attributes) { attrTypeSet.add(attribute.getAttributeType()); } } - // Get the columns appropriate for the artifact type. This is - // used to get the data that will be in the cells below based on - // type, and display the column headers. + /* Get the columns appropriate for the artifact type. This is used to + * get the data that will be in the cells below based on type, and + * display the column headers. + */ List columns = getArtifactTableColumns(type.getTypeID(), attrTypeSet); if (columns.isEmpty()) { return; } columnHeaderMap.put(type.getTypeID(), columns); - // The artifact list is sorted now, as getting the row data is - // dependent on having the columns, which is necessary for - // sorting. + + /* The artifact list is sorted now, as getting the row data is dependent + * on having the columns, which is necessary for sorting. + */ Collections.sort(artifactList); - List columnHeaderNames = new ArrayList<>(); - for (Column currColumn : columns) { - columnHeaderNames.add(currColumn.getColumnHeader()); - } - tableReport.startDataType(dataType, comment.toString()); - tableReport.startTable(columnHeaderNames); + + tableReport.startDataType(tableName, comment); + tableReport.startTable(Lists.transform(columns, Column::getColumnHeader)); + for (ArtifactData artifactData : artifactList) { // Get the row data for this artifact, and has the // module add it. @@ -1663,10 +1678,6 @@ class TableReportGenerator { @Override public String getCellData(ArtifactData artData) { return getFileUniquePath(artData.getContent()); - /* else if - * (this.columnHeader.equals(NbBundle.getMessage(this.getClass(), - * "ReportGenerator.artTableColHdr.tags"))) { return - * makeCommaSeparatedList(artData.getTags()); } return ""; */ } @Override diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java index a52bc7ce7f..7e855b57a1 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java @@ -55,7 +55,11 @@ final class TermComponentQuery implements KeywordSearchQuery { private static final BlackboardAttribute.Type SOLR_DOCUMENT_ID_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SOLR_DOCUMENT_ID); private static final BlackboardAttribute.Type ACCOUNT_NUMBER_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER); private static final BlackboardAttribute.Type ACOUNT_TYPE_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE); - private static final String CREDIT_CARD_NUMBER = "Credit Card Number"; + + /** + * This is a secret handshake with org.sleuthkit.autopsy.datamodel.Accounts + */ + private static final String CREDIT_CARD_NUMBER_ACCOUNT_TYPE = "Credit Card Number"; //TODO: move these regex and the luhn check to a new class, something like: CreditCardNumberValidator /* @@ -190,7 +194,7 @@ final class TermComponentQuery implements KeywordSearchQuery { //if the keyword hit matched the credit card number keyword/regex... if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER) { newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT); - newArtifact.addAttribute(new BlackboardAttribute(ACOUNT_TYPE_TYPE, MODULE_NAME, CREDIT_CARD_NUMBER)); + newArtifact.addAttribute(new BlackboardAttribute(ACOUNT_TYPE_TYPE, MODULE_NAME, CREDIT_CARD_NUMBER_ACCOUNT_TYPE)); // make account artifact //try to match it against the track 1 regex From e9cd0e49d1141640dc139ec17ef81c16191b7677 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 19 Sep 2016 16:48:46 +0200 Subject: [PATCH 16/54] query for account types --- .../sleuthkit/autopsy/datamodel/Accounts.java | 37 ++++++++++++++----- .../datamodel/DisplayableItemNodeVisitor.java | 4 +- .../directorytree/DataResultFilterNode.java | 2 +- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java index 046534f773..408383bd65 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java @@ -52,10 +52,12 @@ import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVParser; import org.apache.commons.csv.CSVRecord; import org.apache.commons.lang3.StringUtils; +import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; @@ -521,15 +523,32 @@ public class Accounts extends Observable implements AutopsyVisitableItem { }; @Override - @NbBundle.Messages({"Accounts.AccountTypeFactory.accountType.creditCards=Credit Card Numbers"}) + protected boolean createKeys(List list) { - list.add(Bundle.Accounts_AccountTypeFactory_accountType_creditCards()); + + try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery( + "SELECT DISTINCT blackboard_attributes.value_text as account_type " + + " FROM blackboard_attributes " + + " WHERE blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()); + ResultSet resultSet = executeQuery.getResultSet()) { + while (resultSet.next()) { + list.add(resultSet.getString("account_type")); + } + } catch (TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + return false; + } return true; } @Override protected Node createNodeForKey(String key) { - return new AccountTypeNode(key); + if (key.equals(CREDIT_CARD_NUMBER_ACCOUNT_TYPE)) { + return new CreditCardNumberAccountTypeNode(key); + } else { + //Flesh out what happens with other account types here. + return new AbstractNode(Children.LEAF); + } } @Override @@ -555,9 +574,9 @@ public class Accounts extends Observable implements AutopsyVisitableItem { * * NOTE: currently hard coded to work for Credit Card only */ - public class AccountTypeNode extends DisplayableItemNode { + public class CreditCardNumberAccountTypeNode extends DisplayableItemNode { - private AccountTypeNode(String accountTypeName) { + private CreditCardNumberAccountTypeNode(String accountTypeName) { super(Children.create(new ViewModeFactory(), true)); super.setName(accountTypeName); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS @@ -916,13 +935,13 @@ public class Accounts extends Observable implements AutopsyVisitableItem { public class BINNode extends DisplayableItemNode implements Observer { private final BinResult bin; - private final AccountFactory accountFactory; + private final CreditCardNumberFactory accountFactory; private BINNode(BinResult bin) { super(Children.LEAF); this.bin = bin; - accountFactory = new AccountFactory(bin); + accountFactory = new CreditCardNumberFactory(bin); setChildren(Children.create(accountFactory, true)); setName(bin.toString()); updateDisplayName(); @@ -1170,11 +1189,11 @@ public class Accounts extends Observable implements AutopsyVisitableItem { /** * Creates the nodes for the accounts of a given type */ - private class AccountFactory extends ObservingChildFactory { + private class CreditCardNumberFactory extends ObservingChildFactory { private final BinResult bin; - private AccountFactory(BinResult bin) { + private CreditCardNumberFactory(BinResult bin) { this.bin = bin; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index fe3445728b..14171a6201 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -127,7 +127,7 @@ public interface DisplayableItemNodeVisitor { */ T visit(Accounts.AccountsRootNode accountRootNode); - T visit(Accounts.AccountTypeNode accountTypeNode); + T visit(Accounts.CreditCardNumberAccountTypeNode accountTypeNode); T visit(Accounts.ByBINNode byArtifactNode); @@ -350,7 +350,7 @@ public interface DisplayableItemNodeVisitor { } @Override - public T visit(Accounts.AccountTypeNode node) { + public T visit(Accounts.CreditCardNumberAccountTypeNode node) { return defaultVisit(node); } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index d8985ac8a7..33d15b14f9 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -497,7 +497,7 @@ public class DataResultFilterNode extends FilterNode { } @Override - public AbstractAction visit(Accounts.AccountTypeNode node) { + public AbstractAction visit(Accounts.CreditCardNumberAccountTypeNode node) { return openChild(node); } From fa2b068b224511b2f93124e9cb9d7b1fde886e4d Mon Sep 17 00:00:00 2001 From: millmanorama Date: Wed, 14 Sep 2016 17:17:37 +0200 Subject: [PATCH 17/54] maintain selection in data result viewer --- .../sleuthkit/autopsy/datamodel/Accounts.java | 54 ++++++++++++++++--- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java index ab4571395d..0b7062c672 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java @@ -34,6 +34,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Observable; import java.util.Observer; import java.util.Optional; @@ -48,6 +49,7 @@ import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.Immutable; import javax.swing.AbstractAction; import javax.swing.Action; +import javax.swing.SwingUtilities; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVParser; import org.apache.commons.csv.CSVRecord; @@ -55,11 +57,15 @@ import org.apache.commons.lang3.StringUtils; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; +import org.openide.nodes.NodeOp; import org.openide.nodes.Sheet; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; @@ -78,6 +84,8 @@ public class Accounts extends Observable implements AutopsyVisitableItem { private static final Logger LOGGER = Logger.getLogger(Accounts.class.getName()); private static final BlackboardArtifact.Type CREDIT_CARD_ACCOUNT_TYPE = new BlackboardArtifact.Type(TSK_CREDIT_CARD_ACCOUNT); + private static final BlackboardAttribute.Type ACCOUNT_NUMBER_TYPE = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER); + @NbBundle.Messages("AccountsRootNode.name=Accounts") final public static String NAME = Bundle.AccountsRootNode_name(); @@ -183,7 +191,6 @@ public class Accounts extends Observable implements AutopsyVisitableItem { notifyObservers(); } - /** * Get an IINInfo object with details about the given IIN * @@ -842,7 +849,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { this.fileName = (key.getSolrDocmentID() == null) ? content.getName() : Bundle.Accounts_FileWithCCNNode_unallocatedSpaceFile_displayName(content.getName(), StringUtils.substringAfter(key.getSolrDocmentID(), "_")); //NON-NLS - setName(fileName); + setName(fileName + key.getObjID()); setDisplayName(fileName); } @@ -902,7 +909,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { LOGGER.log(Level.SEVERE, "Error gettung content by id", ex); } arrayList.add(new ApproveAccounts(getLookup().lookupAll(BlackboardArtifact.class))); - arrayList.add(new RejectAccounts(getLookup().lookupAll(BlackboardArtifact.class))); + arrayList.add(new RejectAccounts(getLookup().lookupAll(BlackboardArtifact.class), this)); return arrayList.toArray(new Action[arrayList.size()]); } } @@ -918,7 +925,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { accountFactory = new AccountFactory(bin); setChildren(Children.create(accountFactory, true)); - setName(bin.toString()); + setName(getBinRangeString()); updateDisplayName(); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/bank.png"); //NON-NLS Accounts.this.addObserver(this); @@ -1076,6 +1083,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { @Immutable static private class BinResult implements IINInfo { + /** * The number of accounts with this BIN */ @@ -1107,7 +1115,6 @@ public class Accounts extends Observable implements AutopsyVisitableItem { return iinEnd; } - public long getCount() { return count; } @@ -1220,6 +1227,11 @@ public class Accounts extends Observable implements AutopsyVisitableItem { private AccountArtifactNode(BlackboardArtifact artifact) { super(artifact, "org/sleuthkit/autopsy/images/credit-card.png"); //NON-NLS this.artifact = artifact; + try { + setName(this.artifact.getAttribute(ACCOUNT_NUMBER_TYPE).getValueString() + "_" + this.artifact.getArtifactID()); + } catch (TskCoreException ex) { + Exceptions.printStackTrace(ex); + } } @Override @@ -1227,7 +1239,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { List actionsList = new ArrayList<>(); actionsList.addAll(Arrays.asList(super.getActions(context))); actionsList.add(new ApproveAccounts(Collections.singleton(artifact))); - actionsList.add(new RejectAccounts(Collections.singleton(artifact))); + actionsList.add(new RejectAccounts(Collections.singleton(artifact), this)); return actionsList.toArray(new Action[actionsList.size()]); } @@ -1287,10 +1299,12 @@ public class Accounts extends Observable implements AutopsyVisitableItem { private class RejectAccounts extends AbstractAction { private final Collection artifacts; + private final Node target; - RejectAccounts(Collection artifacts) { + RejectAccounts(Collection artifacts, Node target) { super(Bundle.RejectAccountsAction_name()); this.artifacts = artifacts; + this.target = target; } @Override @@ -1299,7 +1313,31 @@ public class Accounts extends Observable implements AutopsyVisitableItem { for (BlackboardArtifact artifact : artifacts) { skCase.setReviewStatus(artifact, BlackboardArtifact.ReviewStatus.REJECTED); } - Accounts.this.update(); + + //find the node to select after the target is removed from the UI + List siblings = Arrays.asList(target.getParentNode().getChildren().getNodes()); + if (siblings.size() <= 1) { + Accounts.this.update(); + } else { + final int indexOf = siblings.indexOf(target); + + final Node sibling = indexOf < siblings.size() - 1 // if it is not the last in the list + ? siblings.get(indexOf + 1) //select the next element + : siblings.get(indexOf - 1);//else select the previous element + String nodeToSelectName = sibling.getName(); + + Accounts.this.update(); + + if (showRejected == false && siblings.size() > 1) { + SwingUtilities.invokeLater(() -> { + final DirectoryTreeTopComponent directoryTree = DirectoryTreeTopComponent.findInstance(); + final DataResultTopComponent directoryListing = directoryTree.getDirectoryListing(); + + Node findChild = NodeOp.findChild(directoryListing.getRootNode(), nodeToSelectName); + directoryListing.getExplorerManager().setExploredContext(findChild, new Node[]{findChild}); + }); + } + } } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error approving artifacts.", ex); //NON-NLS From ad994761677e937823d28a1b967fc5f0538b7a6c Mon Sep 17 00:00:00 2001 From: millmanorama Date: Thu, 15 Sep 2016 11:25:21 +0200 Subject: [PATCH 18/54] improve selection management --- Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java index 0b7062c672..249836d683 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java @@ -34,7 +34,6 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.Objects; import java.util.Observable; import java.util.Observer; import java.util.Optional; @@ -1334,7 +1333,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { final DataResultTopComponent directoryListing = directoryTree.getDirectoryListing(); Node findChild = NodeOp.findChild(directoryListing.getRootNode(), nodeToSelectName); - directoryListing.getExplorerManager().setExploredContext(findChild, new Node[]{findChild}); + directoryListing.getExplorerManager().setExploredContext(findChild.getParentNode(), new Node[]{findChild}); }); } } From 7534bb9f18986cea9c1170de763efd34f870e65b Mon Sep 17 00:00:00 2001 From: millmanorama Date: Fri, 16 Sep 2016 13:32:29 +0200 Subject: [PATCH 19/54] WIP --- .../sleuthkit/autopsy/datamodel/Accounts.java | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java index 249836d683..1b3eb6914f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java @@ -58,7 +58,6 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.NodeOp; import org.openide.nodes.Sheet; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; @@ -916,14 +915,10 @@ public class Accounts extends Observable implements AutopsyVisitableItem { public class BINNode extends DisplayableItemNode implements Observer { private final BinResult bin; - private final AccountFactory accountFactory; private BINNode(BinResult bin) { - super(Children.LEAF); + super(Children.create(new AccountFactory(bin), true)); this.bin = bin; - - accountFactory = new AccountFactory(bin); - setChildren(Children.create(accountFactory, true)); setName(getBinRangeString()); updateDisplayName(); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/bank.png"); //NON-NLS @@ -1082,7 +1077,6 @@ public class Accounts extends Observable implements AutopsyVisitableItem { @Immutable static private class BinResult implements IINInfo { - /** * The number of accounts with this BIN */ @@ -1226,11 +1220,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { private AccountArtifactNode(BlackboardArtifact artifact) { super(artifact, "org/sleuthkit/autopsy/images/credit-card.png"); //NON-NLS this.artifact = artifact; - try { - setName(this.artifact.getAttribute(ACCOUNT_NUMBER_TYPE).getValueString() + "_" + this.artifact.getArtifactID()); - } catch (TskCoreException ex) { - Exceptions.printStackTrace(ex); - } + setName("" + this.artifact.getArtifactID()); } @Override @@ -1324,16 +1314,21 @@ public class Accounts extends Observable implements AutopsyVisitableItem { ? siblings.get(indexOf + 1) //select the next element : siblings.get(indexOf - 1);//else select the previous element String nodeToSelectName = sibling.getName(); - Accounts.this.update(); if (showRejected == false && siblings.size() > 1) { SwingUtilities.invokeLater(() -> { final DirectoryTreeTopComponent directoryTree = DirectoryTreeTopComponent.findInstance(); final DataResultTopComponent directoryListing = directoryTree.getDirectoryListing(); + final Node rootNode = directoryListing.getRootNode(); - Node findChild = NodeOp.findChild(directoryListing.getRootNode(), nodeToSelectName); - directoryListing.getExplorerManager().setExploredContext(findChild.getParentNode(), new Node[]{findChild}); + Node child = NodeOp.findChild(rootNode, nodeToSelectName); + + if (child.getParentNode() == rootNode) { + directoryListing.setSelectedNodes(new Node[]{child}); + } else { + directoryListing.getExplorerManager().setExploredContext(child.getParentNode(), new Node[]{child}); + } }); } } From 7ea16893637bbeb74f1bf3ed93d8859381de6862 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Wed, 21 Sep 2016 12:17:13 +0200 Subject: [PATCH 20/54] WIP --- .../src/org/sleuthkit/autopsy/datamodel/Accounts.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java index 1b3eb6914f..c2266685e0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java @@ -24,6 +24,7 @@ import com.google.common.collect.TreeRangeMap; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; import java.io.IOException; import java.io.InputStreamReader; import java.sql.ResultSet; @@ -58,6 +59,7 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.NodeOp; import org.openide.nodes.Sheet; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; @@ -1324,10 +1326,11 @@ public class Accounts extends Observable implements AutopsyVisitableItem { Node child = NodeOp.findChild(rootNode, nodeToSelectName); - if (child.getParentNode() == rootNode) { - directoryListing.setSelectedNodes(new Node[]{child}); - } else { - directoryListing.getExplorerManager().setExploredContext(child.getParentNode(), new Node[]{child}); + try { + directoryTree.getExplorerManager().setSelectedNodes(new Node[]{child.getParentNode()}); + directoryListing.setSelectedNodes(new Node[]{child.getParentNode()}); + } catch (PropertyVetoException ex) { + Exceptions.printStackTrace(ex); } }); } From 0bb4fff4b2aaca46977efd9f412d9b5a46950807 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Thu, 22 Sep 2016 10:08:50 +0200 Subject: [PATCH 21/54] WIP using actionsGlobalContext --- Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java index 3e7a540714..65a9080c79 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java @@ -30,6 +30,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -1307,6 +1308,8 @@ public class Accounts extends Observable implements AutopsyVisitableItem { @Override public void actionPerformed(ActionEvent e) { super.actionPerformed(e); + Collection lookupAll = Utilities.actionsGlobalContext().lookupAll(Node.class); + System.out.println(lookupAll); // //find the node to select after the target is removed from the UI // List siblings = Arrays.asList(target.getParentNode().getChildren().getNodes()); // if (siblings.size() <= 1) { From 27995fd6ab5ab606e635b9a0cf9deeee89d16cfd Mon Sep 17 00:00:00 2001 From: millmanorama Date: Fri, 23 Sep 2016 13:45:56 +0200 Subject: [PATCH 22/54] rename image file --- .../org/sleuthkit/autopsy/datamodel/Accounts.java | 2 +- .../images/{account_menu.png => accounts.png} | Bin .../org/sleuthkit/autopsy/report/ReportHTML.java | 6 +++--- 3 files changed, 4 insertions(+), 4 deletions(-) rename Core/src/org/sleuthkit/autopsy/images/{account_menu.png => accounts.png} (100%) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java index 408383bd65..4f7ed78859 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java @@ -447,7 +447,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { super(Children.create(new AccountTypeFactory(), true), Lookups.singleton(Accounts.this)); super.setName(Accounts.NAME); super.setDisplayName(Bundle.Accounts_RootNode_displayName()); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account_menu.png"); //NON-NLS + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/accounts.png"); //NON-NLS } @Override diff --git a/Core/src/org/sleuthkit/autopsy/images/account_menu.png b/Core/src/org/sleuthkit/autopsy/images/accounts.png similarity index 100% rename from Core/src/org/sleuthkit/autopsy/images/account_menu.png rename to Core/src/org/sleuthkit/autopsy/images/accounts.png diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index d04f96ff0b..fd4c5713a3 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -255,7 +255,7 @@ class ReportHTML implements TableReportModule { in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/drive_network.png"); //NON-NLS break; case TSK_ACCOUNT: - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/account_menu.png"); //NON-NLS + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/accounts.png"); //NON-NLS break; default: logger.log(Level.WARNING, "useDataTypeIcon: unhandled artifact type = " + dataType); //NON-NLS @@ -271,8 +271,8 @@ class ReportHTML implements TableReportModule { * general account icon, but we could do soemthing else in the * future. */ - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/account_menu.png"); //NON-NLS - iconFileName = "account_menu.png"; //NON-NLS + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/accounts.png"); //NON-NLS + iconFileName = "accounts.png"; //NON-NLS iconFilePath = path + File.separator + iconFileName; } else { // no defined artifact found for this dataType in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/star.png"); //NON-NLS From 01bc9a41d75bc6f61ec2a3226f66128f345acd54 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Fri, 23 Sep 2016 13:50:14 +0200 Subject: [PATCH 23/54] fix typos in comment --- Core/src/org/sleuthkit/autopsy/report/ReportHTML.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index fd4c5713a3..dfd4975aa7 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -266,9 +266,9 @@ class ReportHTML implements TableReportModule { } } else if (dataType.startsWith(ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName())) { /* TSK_ACCOUNT artifacts get separated by their TSK_ACCOUNT_TYPE - * attribute, with a compund dataType name, so they are not caught + * attribute, with a compound dataType name, so they are not caught * by the switch statement above. For now we just give them all the - * general account icon, but we could do soemthing else in the + * general account icon, but we could do something else in the * future. */ in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/accounts.png"); //NON-NLS From 665aacf9dc9eaf6f5411dafe96fb7016bf04daae Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Fri, 23 Sep 2016 15:47:47 -0400 Subject: [PATCH 24/54] Changed user interface, kept bookmark tag always, renamed files --- .../casemodule/services/Bundle.properties | 23 +- .../services/NewUserTagNameDialog.form | 98 ++++ .../services/NewUserTagNameDialog.java | 197 ++++++++ ...va => TagNamesOptionsPanelController.java} | 18 +- ...sPanel.form => TagNamesSettingsPanel.form} | 59 +-- .../services/TagNamesSettingsPanel.java | 293 ++++++++++++ .../casemodule/services/TagsManager.java | 107 ++--- .../services/TagsManagerOptionsPanel.java | 427 ------------------ .../casemodule/services/UserTagName.java | 72 +++ 9 files changed, 745 insertions(+), 549 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.form create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java rename Core/src/org/sleuthkit/autopsy/casemodule/services/{TagsManagerOptionsPanelController.java => TagNamesOptionsPanelController.java} (85%) rename Core/src/org/sleuthkit/autopsy/casemodule/services/{TagsManagerOptionsPanel.form => TagNamesSettingsPanel.form} (75%) create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java delete mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/UserTagName.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index a7425bfa0d..226b661523 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -1,5 +1,5 @@ -OptionsCategory_Name_TagsManager=My Tags -OptionsCategory_Keywords_TagsManager=TagsManager +OptionsCategory_Name_TagNamesOptions=My Tag Names +OptionsCategory_TagNames=TagNames TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0} out of content size range (0 - {1}) TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} out of content size range (0 - {1}) TagsManager.addContentTag.exception.endLTbegin.msg=endByteOffset < beginByteOffset @@ -12,9 +12,16 @@ Blackboard.unableToIndexArtifact.error.msg=Unable to index blackboard artifact { TagsManagerOptionsPanel.addTagNameButton.empty=Tag name text is empty. TagsManagerOptionsPanel.addTagNameButton.containInvalidCharacter=Tag name may not contain any of the following symbols\: \\ \: * ? " < > | , ; TagsManagerOptionsPanel.addTagNameButton.alreadyExists=Tag name already exists. -TagsManagerOptionsPanel.jLabel1.text=Autopsy keeps a list of the tag names you have created in the past. Add more or delete them here. -TagsManagerOptionsPanel.tagNamesListLabel.text=Your tag names: -TagsManagerOptionsPanel.userTagNameTextField.text= -TagsManagerOptionsPanel.addTagNameButton.text=Add Tag Name -TagsManagerOptionsPanel.deleteTagNameButton.text=Delete Tag Name -TagsManagerOptionsPanel.tagNameErrLabel.text= \ No newline at end of file +TagNamesSettingsPanel.deleteTagNameButton.text=Delete Tag Name +TagNamesSettingsPanel.addTagNameButton.text=Add Tag Name +TagNamesSettingsPanel.tagNamesListLabel.text=Your tag names: +NewUserTagNameDialog.tagNameTextField.text= +NewUserTagNameDialog.newTagNameLabel.text=New Tag Name: +NewUserTagNameDialog.okButton.text=OK +NewUserTagNameDialog.cancelButton.text=Cancel +NewUserTagNameDialog.title.text=New Tag Name +NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.message=Tag name may not contain any of the following symbols\: \\ \: * ? " < > | , ; +NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.title=Invalid character in tag name +TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.message=The tag name already exists in your settings +TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.title=Tag name already exists +TagNamesSettingsPanel.panelDescriptionLabel.text=Autopsy keeps a list of the tag names you have created in the past. Add more or delete them here. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.form new file mode 100755 index 0000000000..26ab153c27 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.form @@ -0,0 +1,98 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java new file mode 100755 index 0000000000..c39be3dd07 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java @@ -0,0 +1,197 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.casemodule.services; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.beans.PropertyChangeEvent; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import org.openide.util.NbBundle; + +public class NewUserTagNameDialog extends javax.swing.JDialog { + + private String userTagDisplayName; + private BUTTON_PRESSED result; + + enum BUTTON_PRESSED { + OK, CANCEL; + } + + NewUserTagNameDialog() { + super(new JFrame(NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.title.text")), + NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.title.text"), true); + initComponents(); + String test = ""; + this.display(); + } + + private void display() { + setLayout(new BorderLayout()); + + // Center the dialog + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); + int width = this.getSize().width; + int height = this.getSize().height; + setLocation((screenDimension.width - width) / 2, (screenDimension.height - height) / 2); + + // Add a handler for when the dialog window is closed directly + this.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + doButtonAction(false); + } + }); + + // Add a listener to enable the save button + tagNameTextField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void changedUpdate(DocumentEvent e) { + fire(); + } + @Override + public void removeUpdate(DocumentEvent e) { + fire(); + } + @Override + public void insertUpdate(DocumentEvent e) { + fire(); + } + private void fire() { + enableOkButton(); + } + }); + + enableOkButton(); + + // Show the dialog + setResizable(false); + setVisible(true); + + } + + private void doButtonAction(boolean okPressed) { + if (okPressed) { + String newTagDisplayName = tagNameTextField.getText(); + if (TagsManager.containsIllegalCharacters(newTagDisplayName)) { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.message"), + NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.title"), + JOptionPane.ERROR_MESSAGE); + } else { + userTagDisplayName = newTagDisplayName; + result = BUTTON_PRESSED.OK; + setVisible(false); + } + } else { + result = BUTTON_PRESSED.CANCEL; + setVisible(false); + } + } + + String getTagName() { + return userTagDisplayName; + } + + BUTTON_PRESSED getResult() { + return result; + } + + private void enableOkButton() { + okButton.setEnabled(!tagNameTextField.getText().isEmpty()); + getRootPane().setDefaultButton(okButton); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + newTagNameLabel = new javax.swing.JLabel(); + tagNameTextField = new javax.swing.JTextField(); + cancelButton = new javax.swing.JButton(); + okButton = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + + org.openide.awt.Mnemonics.setLocalizedText(newTagNameLabel, org.openide.util.NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.newTagNameLabel.text")); // NOI18N + + tagNameTextField.setText(org.openide.util.NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.tagNameTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.cancelButton.text")); // NOI18N + cancelButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cancelButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.okButton.text")); // NOI18N + okButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okButtonActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(tagNameTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 220, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(okButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelButton)) + .addComponent(newTagNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(newTagNameLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(tagNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(50, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cancelButton) + .addComponent(okButton)) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed + doButtonAction(true); + }//GEN-LAST:event_okButtonActionPerformed + + private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed + doButtonAction(false); + }//GEN-LAST:event_cancelButtonActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton cancelButton; + private javax.swing.JLabel newTagNameLabel; + private javax.swing.JButton okButton; + private javax.swing.JTextField tagNameTextField; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesOptionsPanelController.java similarity index 85% rename from Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java rename to Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesOptionsPanelController.java index 18c15f9c46..6f6cb53412 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesOptionsPanelController.java @@ -14,15 +14,15 @@ import org.openide.util.HelpCtx; import org.openide.util.Lookup; @OptionsPanelController.TopLevelRegistration( - categoryName = "#OptionsCategory_Name_TagsManager", + categoryName = "#OptionsCategory_Name_TagNamesOptions", iconBase = "org/sleuthkit/autopsy/casemodule/services/tags-manager.png", - keywords = "#OptionsCategory_Keywords_TagsManager", - keywordsCategory = "TagsManager", + keywords = "#OptionsCategory_TagNames", + keywordsCategory = "CustomTagNames", position = 8 ) -public final class TagsManagerOptionsPanelController extends OptionsPanelController { +public final class TagNamesOptionsPanelController extends OptionsPanelController { - private TagsManagerOptionsPanel panel; + private TagNamesSettingsPanel panel; private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private boolean changed; @@ -55,10 +55,6 @@ public final class TagsManagerOptionsPanelController extends OptionsPanelControl */ @Override public void cancel() { - if (changed) { - getPanel().cancelChanges(); - changed = false; - } } @Override @@ -97,9 +93,9 @@ public final class TagsManagerOptionsPanelController extends OptionsPanelControl pcs.removePropertyChangeListener(l); } - private TagsManagerOptionsPanel getPanel() { + private TagNamesSettingsPanel getPanel() { if (panel == null) { - panel = new TagsManagerOptionsPanel(); + panel = new TagNamesSettingsPanel(); panel.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form similarity index 75% rename from Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.form rename to Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form index fc35b992fe..59cac6e9bc 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form @@ -43,7 +43,7 @@ - +
@@ -53,7 +53,7 @@ - + @@ -62,22 +62,22 @@ - + - + - + - + @@ -90,16 +90,14 @@ - - - - - + + + @@ -111,15 +109,13 @@ - + - - @@ -128,7 +124,7 @@ - + @@ -145,29 +141,22 @@ + + + - + - - - - - - - - - - - + @@ -180,26 +169,16 @@ - + - - - - - - - - - - - + @@ -209,7 +188,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java new file mode 100755 index 0000000000..08fb8ea4e3 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java @@ -0,0 +1,293 @@ +/* +* To change this license header, choose License Headers in Project Properties. +* To change this template file, choose Tools | Templates +* and open the template in the editor. + */ +package org.sleuthkit.autopsy.casemodule.services; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import javax.swing.DefaultListModel; +import javax.swing.JOptionPane; +import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.corecomponents.OptionsPanel; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; + +/** + * A panel to allow the user to create new tag names or to delete tag names that + * user has created in the past. List of user tag names is maintained in a + * properties file, able to be used across cases. Potentially room to add other + * tag name options in the future. + */ +public class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsPanel { + + private static final Logger logger = Logger.getLogger(TagNamesSettingsPanel.class.getName()); + + private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS + private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS + + private static final String TAG_BOOKMARK = "Bookmark"; + + private static final String DEFAULT_DESCRIPTION = ""; + private static final String DEFAULT_COLOR_STRING = "NONE"; + + private DefaultListModel tagNamesListModel; + private List tagNames; + + /** + * Creates new form TagsManagerOptionsPanel + */ + public TagNamesSettingsPanel() { + initComponents(); + customizeComponents(); + } + + private void customizeComponents() { + tagNamesListModel = new DefaultListModel<>(); + tagNamesList.setModel(tagNamesListModel); + tagNames = new ArrayList<>(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jPanel1 = new javax.swing.JPanel(); + panelDescriptionLabel = new javax.swing.JLabel(); + jSplitPane1 = new javax.swing.JSplitPane(); + modifyTagNameListPanel = new javax.swing.JPanel(); + tagNamesListLabel = new javax.swing.JLabel(); + jScrollPane1 = new javax.swing.JScrollPane(); + tagNamesList = new javax.swing.JList<>(); + addTagNameButton = new javax.swing.JButton(); + deleteTagNameButton = new javax.swing.JButton(); + tagNameAdditionalPanel = new javax.swing.JPanel(); + + jPanel1.setPreferredSize(new java.awt.Dimension(750, 500)); + + org.openide.awt.Mnemonics.setLocalizedText(panelDescriptionLabel, org.openide.util.NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.panelDescriptionLabel.text")); // NOI18N + + jSplitPane1.setDividerLocation(400); + jSplitPane1.setDividerSize(1); + + org.openide.awt.Mnemonics.setLocalizedText(tagNamesListLabel, org.openide.util.NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.tagNamesListLabel.text")); // NOI18N + + tagNamesList.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + tagNamesListMouseClicked(evt); + } + }); + jScrollPane1.setViewportView(tagNamesList); + + addTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add-tag.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(addTagNameButton, org.openide.util.NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.addTagNameButton.text")); // NOI18N + addTagNameButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + addTagNameButtonActionPerformed(evt); + } + }); + + deleteTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete-tag.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteTagNameButton, org.openide.util.NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.deleteTagNameButton.text")); // NOI18N + deleteTagNameButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + deleteTagNameButtonActionPerformed(evt); + } + }); + + javax.swing.GroupLayout modifyTagNameListPanelLayout = new javax.swing.GroupLayout(modifyTagNameListPanel); + modifyTagNameListPanel.setLayout(modifyTagNameListPanelLayout); + modifyTagNameListPanelLayout.setHorizontalGroup( + modifyTagNameListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(modifyTagNameListPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(modifyTagNameListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(tagNamesListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(modifyTagNameListPanelLayout.createSequentialGroup() + .addComponent(addTagNameButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deleteTagNameButton) + .addGap(0, 115, Short.MAX_VALUE)) + .addComponent(jScrollPane1)) + .addContainerGap()) + ); + modifyTagNameListPanelLayout.setVerticalGroup( + modifyTagNameListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(modifyTagNameListPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(tagNamesListLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 383, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(modifyTagNameListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(addTagNameButton) + .addComponent(deleteTagNameButton)) + .addContainerGap()) + ); + + jSplitPane1.setLeftComponent(modifyTagNameListPanel); + + javax.swing.GroupLayout tagNameAdditionalPanelLayout = new javax.swing.GroupLayout(tagNameAdditionalPanel); + tagNameAdditionalPanel.setLayout(tagNameAdditionalPanelLayout); + tagNameAdditionalPanelLayout.setHorizontalGroup( + tagNameAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 356, Short.MAX_VALUE) + ); + tagNameAdditionalPanelLayout.setVerticalGroup( + tagNameAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 456, Short.MAX_VALUE) + ); + + jSplitPane1.setRightComponent(tagNameAdditionalPanel); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jSplitPane1) + .addComponent(panelDescriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(panelDescriptionLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jSplitPane1) + .addContainerGap()) + ); + + 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.DEFAULT_SIZE, 778, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void addTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addTagNameButtonActionPerformed + NewUserTagNameDialog dialog = new NewUserTagNameDialog(); + NewUserTagNameDialog.BUTTON_PRESSED result = dialog.getResult(); + if (result == NewUserTagNameDialog.BUTTON_PRESSED.OK) { + String newTagDisplayName = dialog.getTagName(); + UserTagName newTagName = new UserTagName(newTagDisplayName, DEFAULT_DESCRIPTION, DEFAULT_COLOR_STRING); + if (tagNames.contains(newTagName)) { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.message"), + NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.title"), + JOptionPane.ERROR_MESSAGE); + } else { + tagNames.add(newTagName); + updateTagNamesListModel(); + tagNamesList.setSelectedIndex(tagNames.size() - 1); + enableButtons(); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + } + } + }//GEN-LAST:event_addTagNameButtonActionPerformed + + private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagNameButtonActionPerformed + UserTagName tagName = tagNamesList.getSelectedValue(); + tagNames.remove(tagName); + updateTagNamesListModel(); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + }//GEN-LAST:event_deleteTagNameButtonActionPerformed + + private void tagNamesListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tagNamesListMouseClicked + enableButtons(); + }//GEN-LAST:event_tagNamesListMouseClicked + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton addTagNameButton; + private javax.swing.JButton deleteTagNameButton; + private javax.swing.JPanel jPanel1; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JSplitPane jSplitPane1; + private javax.swing.JPanel modifyTagNameListPanel; + private javax.swing.JLabel panelDescriptionLabel; + private javax.swing.JPanel tagNameAdditionalPanel; + private javax.swing.JList tagNamesList; + private javax.swing.JLabel tagNamesListLabel; + // End of variables declaration//GEN-END:variables + + /** + * Updates the tag names model for the tag names list component. + */ + private void updateTagNamesListModel() { + tagNamesListModel.clear(); + Collections.sort(tagNames); + for (UserTagName tagName : tagNames) { + tagNamesListModel.addElement(tagName); + } + } + + /** + * Stores tag name changes in the properties file, called when OK or Apply + * is selected in the OptionsPanel. + * + * Adds all new tag names to the case database for use. + */ + @Override + public void store() { + //Case.getCurrentCase().getServices().getTagsManager().saveUserTagNames(tagNames); + StringBuilder setting = new StringBuilder(); + for (UserTagName tagName : tagNames) { + if (setting.length() != 0) { + setting.append(";"); + } + setting.append(tagName.toSettingsFormat()); + } + ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); + if (Case.isCaseOpen()) { + Case.getCurrentCase().getServices().getTagsManager().storeNewUserTagNames(tagNames); + } + } + + /** + * Updates the tag names list component with tag names from the properties + * file. + */ + @Override + public void load() { + //tagNames = Case.getCurrentCase().getServices().getTagsManager().getUserTagNames(); + String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); + tagNames.clear(); + if (null != setting && !setting.isEmpty()) { + List tagNameTuples = Arrays.asList(setting.split(";")); + for (String tagNameTuple : tagNameTuples) { + String[] tagNameAttributes = tagNameTuple.split(","); + tagNames.add(new UserTagName(tagNameAttributes[0], tagNameAttributes[1], tagNameAttributes[2])); + } + } + updateTagNamesListModel(); + enableButtons(); + } + + private void enableButtons() { + boolean ruleIsSelected = tagNamesList.getSelectedIndex() != -1; + deleteTagNameButton.setEnabled(ruleIsSelected); + } + + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index fcd7b051bd..ed4b58eb98 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -95,8 +95,18 @@ public class TagsManager implements Closeable { } lazyLoadExistingTagNames(); Set tagNameSet = new HashSet<>(); + // Add bookmark tag and other tag names that are in use + tagNameSet.add(uniqueTagNames.get(NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"))); tagNameSet.addAll(getTagNamesInUse()); - tagNameSet.addAll(getTagNamesForPropertyFile()); + // Add any tag names defined by the user + String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); + if (null != setting && !setting.isEmpty()) { + List tagNameTuples = Arrays.asList(setting.split(";")); + for (String tagNameTuple : tagNameTuples) { + String[] tagNameAttributes = tagNameTuple.split(","); + tagNameSet.add(uniqueTagNames.get(tagNameAttributes[0])); + } + } return new ArrayList<>(tagNameSet); } @@ -117,27 +127,6 @@ public class TagsManager implements Closeable { return caseDb.getTagNamesInUse(); } - /** - * Gets a list of all tag names associated with the ones found in the - * properties file. - * - * @return A list, possibly empty, of TagName data transfer objects (DTOs). - */ - private synchronized List getTagNamesForPropertyFile() { - lazyLoadExistingTagNames(); - List propertyFileTagNames = new ArrayList<>(); - - String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); - if (null != setting && !setting.isEmpty()) { - List tagNameTuples = Arrays.asList(setting.split(";")); - for (String tagNameTuple : tagNameTuples) { - String[] tagNameAttributes = tagNameTuple.split(","); - propertyFileTagNames.add(uniqueTagNames.get(tagNameAttributes[0])); - } - } - return propertyFileTagNames; - } - /** * Checks whether a tag name with a given display name exists. * @@ -213,30 +202,32 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); - //The tag name already exists in the database, user either - //1) adding it again by error -> throws TagNameAlreadyExistsException - //2) adding it after it was deleted at some point in the past + /** + * It is possible user is trying to add back a tag after having deleted + * it. + */ if (uniqueTagNames.containsKey(displayName)) { TagName existingTagName = uniqueTagNames.get(displayName); - long tagNameCount = getContentTagsCountByTagName(existingTagName) + getBlackboardArtifactTagsCountByTagName(existingTagName); - if (tagNameCount > 0) { - throw new TagNameAlreadyExistsException(); - } else { + long count = getContentTagsCountByTagName(existingTagName) + getBlackboardArtifactTagsCountByTagName(existingTagName); + if (count == 0) { addNewTagNameToTagsSettings(existingTagName); + return existingTagName; + } else { + throw new TagNameAlreadyExistsException(); } - return existingTagName; } + /* - * Add the tag name to the case. - */ + * Add the tag name to the case. + */ TagName newTagName = caseDb.addTagName(displayName, description, color); + uniqueTagNames.put(newTagName.getDisplayName(), newTagName); /* - * Add the tag name to the tags settings. - */ - uniqueTagNames.put(newTagName.getDisplayName(), newTagName); + * Add the tag name to the tags settings. + */ addNewTagNameToTagsSettings(newTagName); - + return newTagName; } @@ -634,15 +625,12 @@ public class TagsManager implements Closeable { /** * Populates the tag names collection and the tag names table in the case * database with the existing tag names from all sources. - * - * Tag names from current case are not saved into the settings file. */ private void lazyLoadExistingTagNames() { if (!tagNamesLoaded) { - addTagNamesFromTagsSettings(); - addPredefinedTagNames(); - saveTagNamesToTagsSettings(); addTagNamesFromCurrentCase(); + addPredefinedTagNames(); + addTagNamesFromTagsSettings(); tagNamesLoaded = true; } } @@ -683,7 +671,7 @@ public class TagsManager implements Closeable { uniqueTagNames.put(tagName.getDisplayName(), tagName); } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add saved tag name " + tagNameAttributes[0], ex); //NON-NLS - } + } } } } @@ -703,23 +691,24 @@ public class TagsManager implements Closeable { } } } - + /** - * Saves the tag names to a properties file. The properties file is used to - * make it possible to use tag names across cases. + * Adds any user defined tag name to the case db and also to uniqueTagNames, + * to allow user tag names to be displayed while tagging. + * + * @param userTagNames a List of UserTagName objects to be added */ - private void saveTagNamesToTagsSettings() { - if (!uniqueTagNames.isEmpty()) { - StringBuilder setting = new StringBuilder(); - for (TagName tagName : uniqueTagNames.values()) { - if (setting.length() != 0) { - setting.append(";"); + void storeNewUserTagNames(List userTagNames) { + lazyLoadExistingTagNames(); + for (UserTagName utn : userTagNames) { + if (!uniqueTagNames.containsKey(utn.getDisplayName())) { + try { + TagName tagName = caseDb.addTagName(utn.getDisplayName(), utn.getDescription(), TagName.HTML_COLOR.getColorByName(utn.getColorName())); + uniqueTagNames.put(tagName.getDisplayName(), tagName); + } catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add saved tag name " + utn.getDisplayName(), ex); //NON-NLS } - setting.append(tagName.getDisplayName()).append(","); - setting.append(tagName.getDescription()).append(","); - setting.append(tagName.getColor().name()); } - ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); } } @@ -767,12 +756,4 @@ public class TagsManager implements Closeable { private static final long serialVersionUID = 1L; } - /** - * Exception thrown if there is an attempt to delete a nonexistent tag name. - * Unused for current implementation of tag name deletion. - */ - public static class TagNameDoesNotExistException extends Exception { - - } - } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java deleted file mode 100755 index 17343d9690..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManagerOptionsPanel.java +++ /dev/null @@ -1,427 +0,0 @@ -/* -* To change this license header, choose License Headers in Project Properties. -* To change this template file, choose Tools | Templates -* and open the template in the editor. -*/ -package org.sleuthkit.autopsy.casemodule.services; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.TreeSet; -import java.util.logging.Level; -import javax.swing.DefaultListModel; -import org.netbeans.spi.options.OptionsPanelController; -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.corecomponents.OptionsPanel; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.ModuleSettings; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * A panel to allow the user to create new tag names or to delete tag names that - * user has created in the past. List of user tag names is maintained in a - * properties file, able to be used across cases. - * Potentially room to add other tag name options in the future. - */ -public class TagsManagerOptionsPanel extends javax.swing.JPanel implements OptionsPanel { - - private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS - private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS - - private static final String TAG_BOOKMARK = "Bookmark"; - - private static final String DEFAULT_DESCRIPTION = ""; - private static final String DEFAULT_COLOR_STRING = "NONE"; - - private final DefaultListModel tagNamesListModel; - private Set tagNames; - private List newDisplayNames; - - - /** - * Creates new form TagsManagerOptionsPanel - */ - public TagsManagerOptionsPanel() { - initComponents(); - - tagNamesListModel = new DefaultListModel<>(); - tagNamesList.setModel(tagNamesListModel); - tagNames = getTagNamesFromTagsSettings(); - newDisplayNames = new ArrayList<>(); - - userTagNameTextField.setText(""); - tagNameErrLabel.setText(""); - } - - /** - * Gets tag names from properties file. - * - * @return A set, possibly empty, of CustomTagName objects - */ - private Set getTagNamesFromTagsSettings() { - Set tagNamesFromSettings = new TreeSet<>(); - String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); - if ((setting != null) && !setting.isEmpty()) { - List tagNameTuples = Arrays.asList(setting.split(";")); - for (String tagNameTuple : tagNameTuples) { - String[] tagNameAttributes = tagNameTuple.split(","); - CustomTagName tagName = new CustomTagName(tagNameAttributes[0], tagNameAttributes[1], tagNameAttributes[2]); - tagNamesFromSettings.add(tagName); - } - } else { - tagNamesFromSettings.add(new CustomTagName(TAG_BOOKMARK, DEFAULT_DESCRIPTION, DEFAULT_COLOR_STRING)); - } - - return tagNamesFromSettings; - } - - /** - * Updates the tag names model for the tag names list component. - */ - private void updateTagNamesListModel() { - tagNamesListModel.clear(); - tagNames.stream().forEach((tagName) -> { - tagNamesListModel.addElement(tagName); - }); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - jPanel1 = new javax.swing.JPanel(); - jLabel1 = new javax.swing.JLabel(); - jSplitPane1 = new javax.swing.JSplitPane(); - jPanel2 = new javax.swing.JPanel(); - tagNamesListLabel = new javax.swing.JLabel(); - jScrollPane1 = new javax.swing.JScrollPane(); - tagNamesList = new javax.swing.JList<>(); - userTagNameTextField = new javax.swing.JTextField(); - addTagNameButton = new javax.swing.JButton(); - deleteTagNameButton = new javax.swing.JButton(); - tagNameErrLabel = new javax.swing.JLabel(); - jPanel3 = new javax.swing.JPanel(); - - jPanel1.setPreferredSize(new java.awt.Dimension(750, 500)); - - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.jLabel1.text")); // NOI18N - - jSplitPane1.setDividerLocation(-100); - jSplitPane1.setDividerSize(1); - - org.openide.awt.Mnemonics.setLocalizedText(tagNamesListLabel, org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.tagNamesListLabel.text")); // NOI18N - - jScrollPane1.setViewportView(tagNamesList); - - userTagNameTextField.setText(org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.userTagNameTextField.text")); // NOI18N - userTagNameTextField.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - userTagNameTextFieldActionPerformed(evt); - } - }); - - addTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add-tag.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(addTagNameButton, org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.text")); // NOI18N - addTagNameButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - addTagNameButtonActionPerformed(evt); - } - }); - - deleteTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete-tag.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(deleteTagNameButton, org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.deleteTagNameButton.text")); // NOI18N - deleteTagNameButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - deleteTagNameButtonActionPerformed(evt); - } - }); - - tagNameErrLabel.setForeground(new java.awt.Color(255, 0, 0)); - org.openide.awt.Mnemonics.setLocalizedText(tagNameErrLabel, org.openide.util.NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.tagNameErrLabel.text")); // NOI18N - - 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(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(tagNameErrLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jScrollPane1) - .addComponent(tagNamesListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup() - .addComponent(userTagNameTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 135, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(addTagNameButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deleteTagNameButton))) - .addContainerGap()) - ); - jPanel2Layout.setVerticalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel2Layout.createSequentialGroup() - .addContainerGap() - .addComponent(tagNamesListLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 374, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(userTagNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(addTagNameButton) - .addComponent(deleteTagNameButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(tagNameErrLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) - ); - - jSplitPane1.setLeftComponent(jPanel2); - - javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); - jPanel3.setLayout(jPanel3Layout); - jPanel3Layout.setHorizontalGroup( - jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 330, Short.MAX_VALUE) - ); - jPanel3Layout.setVerticalGroup( - jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 456, Short.MAX_VALUE) - ); - - jSplitPane1.setRightComponent(jPanel3); - - javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); - jPanel1.setLayout(jPanel1Layout); - jPanel1Layout.setHorizontalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(jSplitPane1) - .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) - ); - jPanel1Layout.setVerticalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jLabel1) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jSplitPane1) - .addContainerGap()) - ); - - 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.DEFAULT_SIZE, 778, Short.MAX_VALUE) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)) - ); - }// //GEN-END:initComponents - - /** - * Adds a new tag name to the tag names list component without necessarily - * saving the changes. - * - * @param evt ActionEvent generated by clicking the Add Tag Name button - */ - private void addTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addTagNameButtonActionPerformed - String newDisplayName = userTagNameTextField.getText(); - - if (newDisplayName.isEmpty()) { - tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.empty")); - return; - } - if (TagsManager.containsIllegalCharacters(newDisplayName)) { - tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.containInvalidCharacter")); - return; - } - - CustomTagName tagName = new CustomTagName(newDisplayName, DEFAULT_DESCRIPTION, DEFAULT_COLOR_STRING); - - boolean addedToTagNames = tagNames.add(tagName); - - if (!addedToTagNames) { - tagNameErrLabel.setText(NbBundle.getMessage(TagsManagerOptionsPanel.class, "TagsManagerOptionsPanel.addTagNameButton.alreadyExists")); - return; - } - - updateTagNamesListModel(); - - newDisplayNames.add(newDisplayName); - userTagNameTextField.setText(""); - tagNameErrLabel.setText(""); - - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - }//GEN-LAST:event_addTagNameButtonActionPerformed - - /** - * Deletes a tag name from the tag names list component without saving the - * changes. - * - * @param evt ActionEvent generated by clicking the Delete Tag Name button - */ - private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagNameButtonActionPerformed - CustomTagName tagName = tagNamesList.getSelectedValue(); - if (tagName == null) { - tagNameErrLabel.setText("No tag name selected."); - } else { - tagNames.remove(tagName); - updateTagNamesListModel(); - - if (!tagNamesListModel.isEmpty()) { - tagNamesList.setSelectedIndex(0); - } - - newDisplayNames.remove(tagName.getDisplayName()); - - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - } - }//GEN-LAST:event_deleteTagNameButtonActionPerformed - - /** - * Activates addTagNameButtonActionPerformed instead of the OptionsPanel OK - * button when the userTagNameTextField experiences an action. - * @param evt ActionEvent - */ - private void userTagNameTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_userTagNameTextFieldActionPerformed - addTagNameButtonActionPerformed(evt); - }//GEN-LAST:event_userTagNameTextFieldActionPerformed - - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton addTagNameButton; - private javax.swing.JButton deleteTagNameButton; - private javax.swing.JLabel jLabel1; - private javax.swing.JPanel jPanel1; - private javax.swing.JPanel jPanel2; - private javax.swing.JPanel jPanel3; - private javax.swing.JScrollPane jScrollPane1; - private javax.swing.JSplitPane jSplitPane1; - private javax.swing.JLabel tagNameErrLabel; - private javax.swing.JList tagNamesList; - private javax.swing.JLabel tagNamesListLabel; - private javax.swing.JTextField userTagNameTextField; - // End of variables declaration//GEN-END:variables - - /** - * Stores tag name changes in the properties file, called when OK or Apply - * is selected in the OptionsPanel. - * - * Adds all new tag names to the case database for use. - */ - @Override - public void store() { - for (String displayName : newDisplayNames) { - try { - Case.getCurrentCase().getServices().getTagsManager().addTagName(displayName); - } catch (TagsManager.TagNameAlreadyExistsException ex) { - //Do nothing, this is just to update the database - } catch (TskCoreException ex) { - Logger.getLogger(TagsManagerOptionsPanel.class.getName()).log(Level.SEVERE, "Error adding " + displayName + " tag name", ex); - } - } - newDisplayNames = new ArrayList<>(); - - StringBuilder builder = new StringBuilder(); - for (CustomTagName tagName : tagNames) { - if (builder.length() != 0) { - builder.append(";"); - } - builder.append(tagName.toSettingsFormat()); - } - ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, builder.toString()); - } - - /** - * Updates the tag names list component with tag names from the properties - * file. - */ - @Override - public void load() { - tagNames = getTagNamesFromTagsSettings(); - updateTagNamesListModel(); - if (!tagNamesListModel.isEmpty()) { - tagNamesList.setSelectedIndex(0); - } - tagNameErrLabel.setText(""); - } - - /** - * Discards changes made to the tag names list component if Cancel button is - * selected in the OptionsPanel. - */ - public void cancelChanges() { - tagNames = getTagNamesFromTagsSettings(); - newDisplayNames = new ArrayList<>(); - } - - /** - * Because the DTO TagName constructor should not be called outside of its - * class package, CustomTagName is used in this tags managers panel for the - * purpose of tracking the description and color of each tag name. - */ - private class CustomTagName implements Comparable { - private final String displayName; - private final String description; - private final String colorName; - - private CustomTagName(String displayName, String description, String colorName) { - this.displayName = displayName; - this.description = description; - this.colorName = colorName; - } - - private String getDisplayName() { - return displayName; - } - - @Override - public int compareTo(CustomTagName other) { - return this.getDisplayName().toLowerCase().compareTo(other.getDisplayName().toLowerCase()); - } - - @Override - public int hashCode() { - int hash = 7; - hash = 83 * hash + Objects.hashCode(this.displayName); - hash = 83 * hash + Objects.hashCode(this.description); - hash = 83 * hash + Objects.hashCode(this.colorName); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof CustomTagName)) return false; - CustomTagName thatTagName = (CustomTagName) obj; - return this.getDisplayName().equals(thatTagName.getDisplayName()); - } - - @Override - public String toString() { - return displayName; - } - - /** - * @return A string representation of the tag name in the format that is - * used by the properties file. - */ - public String toSettingsFormat() { - return displayName + "," + description + "," + colorName; - } - - } -} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/UserTagName.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/UserTagName.java new file mode 100755 index 0000000000..d70f9d38af --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/UserTagName.java @@ -0,0 +1,72 @@ +/* +* To change this license header, choose License Headers in Project Properties. +* To change this template file, choose Tools | Templates +* and open the template in the editor. +*/ +package org.sleuthkit.autopsy.casemodule.services; + +import java.util.Objects; + +/** + * Because the DTO TagName constructor should not be called outside of its + * class package, CustomTagName is used in this tags managers panel for the + * purpose of tracking the description and color of each tag name. + */ +class UserTagName implements Comparable { + + private final String displayName; + private final String description; + private final String colorName; + + UserTagName(String displayName, String description, String colorName) { + this.displayName = displayName; + this.description = description; + this.colorName = colorName; + } + + String getDisplayName() { + return displayName; + } + + String getDescription() { + return description; + } + + String getColorName() { + return colorName; + } + + @Override + public int compareTo(UserTagName other) { + return this.getDisplayName().toLowerCase().compareTo(other.getDisplayName().toLowerCase()); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 83 * hash + Objects.hashCode(this.displayName); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof UserTagName)) { + return false; + } + UserTagName thatTagName = (UserTagName) obj; + return this.getDisplayName().equals(thatTagName.getDisplayName()); + } + + @Override + public String toString() { + return displayName; + } + + /** + * @return A string representation of the tag name in the format that is + * used by the properties file. + */ + public String toSettingsFormat() { + return displayName + "," + description + "," + colorName; + } +} From 807d3c0017642d4c9fed49cb50b9a96b2cb26403 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Fri, 23 Sep 2016 16:07:23 -0400 Subject: [PATCH 25/54] Cleaned up formatting, comments, and imports --- .../services/NewUserTagNameDialog.java | 90 ++++++++++++++----- .../TagNamesOptionsPanelController.java | 21 ++++- .../services/TagNamesSettingsPanel.java | 56 +++++++----- .../casemodule/services/TagsManager.java | 80 ++++++++--------- .../casemodule/services/UserTagName.java | 48 ++++++---- 5 files changed, 191 insertions(+), 104 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java index c39be3dd07..778ae3886d 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. +* Autopsy Forensic Browser +* +* Copyright 2011-2016 Basis Technology Corp. +* Contact: carrier sleuthkit org +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. */ package org.sleuthkit.autopsy.casemodule.services; @@ -10,7 +23,6 @@ import java.awt.Dimension; import java.awt.Toolkit; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -import java.beans.PropertyChangeEvent; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.event.DocumentEvent; @@ -18,14 +30,17 @@ import javax.swing.event.DocumentListener; import org.openide.util.NbBundle; public class NewUserTagNameDialog extends javax.swing.JDialog { - + private String userTagDisplayName; private BUTTON_PRESSED result; - + enum BUTTON_PRESSED { OK, CANCEL; } - + + /** + * Creates a new NewUserTagNameDialog dialog. + */ NewUserTagNameDialog() { super(new JFrame(NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.title.text")), NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.title.text"), true); @@ -33,25 +48,34 @@ public class NewUserTagNameDialog extends javax.swing.JDialog { String test = ""; this.display(); } - + + /** + * Sets display settings for the dialog and adds appropriate listeners. + */ private void display() { setLayout(new BorderLayout()); - - // Center the dialog + + /* + * Center the dialog + */ Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); int width = this.getSize().width; int height = this.getSize().height; setLocation((screenDimension.width - width) / 2, (screenDimension.height - height) / 2); - - // Add a handler for when the dialog window is closed directly + + /* + * Add a handler for when the dialog window is closed directly. + */ this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { doButtonAction(false); } }); - - // Add a listener to enable the save button + + /* + * Add a listener to enable the save button when the text field changes. + */ tagNameTextField.getDocument().addDocumentListener(new DocumentListener() { @Override public void changedUpdate(DocumentEvent e) { @@ -69,15 +93,20 @@ public class NewUserTagNameDialog extends javax.swing.JDialog { enableOkButton(); } }); - + enableOkButton(); - - // Show the dialog + + /* + * Used to show the dialog. + */ setResizable(false); setVisible(true); - } - + + /** + * Called when a button is pressed or when the dialog is closed. + * @param okPressed whether the OK button was pressed. + */ private void doButtonAction(boolean okPressed) { if (okPressed) { String newTagDisplayName = tagNameTextField.getText(); @@ -96,20 +125,35 @@ public class NewUserTagNameDialog extends javax.swing.JDialog { setVisible(false); } } - + + /** + * Returns the tag name entered by the user. + * + * @return a new user tag name + */ String getTagName() { return userTagDisplayName; } - + + /** + * Returns information about which button was pressed. + * + * @return BUTTON_PRESSED (OK, CANCEL) + */ BUTTON_PRESSED getResult() { return result; } - + + /** + * Enable the OK button if the tag name text field is not empty. + * Sets the enter button as default, so user can press enter to activate + * an okButton press and add the tag name. + */ private void enableOkButton() { okButton.setEnabled(!tagNameTextField.getText().isEmpty()); getRootPane().setDefaultButton(okButton); } - + /** * 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 diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesOptionsPanelController.java index 6f6cb53412..20c478d966 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesOptionsPanelController.java @@ -1,8 +1,21 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ +* Autopsy Forensic Browser +* +* Copyright 2011-2016 Basis Technology Corp. +* Contact: carrier sleuthkit org +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.sleuthkit.autopsy.casemodule.services; import java.beans.PropertyChangeEvent; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java index 08fb8ea4e3..e0da98adb6 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java @@ -1,15 +1,27 @@ /* -* To change this license header, choose License Headers in Project Properties. -* To change this template file, choose Tools | Templates -* and open the template in the editor. - */ +* Autopsy Forensic Browser +* +* Copyright 2011-2016 Basis Technology Corp. +* Contact: carrier sleuthkit org +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.sleuthkit.autopsy.casemodule.services; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Objects; import javax.swing.DefaultListModel; import javax.swing.JOptionPane; import org.netbeans.spi.options.OptionsPanelController; @@ -32,8 +44,6 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS - private static final String TAG_BOOKMARK = "Bookmark"; - private static final String DEFAULT_DESCRIPTION = ""; private static final String DEFAULT_COLOR_STRING = "NONE"; @@ -185,13 +195,16 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options .addGap(0, 0, Short.MAX_VALUE)) ); }// //GEN-END:initComponents - + private void addTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addTagNameButtonActionPerformed NewUserTagNameDialog dialog = new NewUserTagNameDialog(); NewUserTagNameDialog.BUTTON_PRESSED result = dialog.getResult(); if (result == NewUserTagNameDialog.BUTTON_PRESSED.OK) { String newTagDisplayName = dialog.getTagName(); UserTagName newTagName = new UserTagName(newTagDisplayName, DEFAULT_DESCRIPTION, DEFAULT_COLOR_STRING); + /* + * If tag name already exists, don't add the tag name. + */ if (tagNames.contains(newTagName)) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.message"), @@ -200,13 +213,16 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options } else { tagNames.add(newTagName); updateTagNamesListModel(); + /* + * Set the selection to the tag name that was just added. + */ tagNamesList.setSelectedIndex(tagNames.size() - 1); enableButtons(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } } }//GEN-LAST:event_addTagNameButtonActionPerformed - + private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagNameButtonActionPerformed UserTagName tagName = tagNamesList.getSelectedValue(); tagNames.remove(tagName); @@ -236,7 +252,6 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options */ private void updateTagNamesListModel() { tagNamesListModel.clear(); - Collections.sort(tagNames); for (UserTagName tagName : tagNames) { tagNamesListModel.addElement(tagName); } @@ -244,13 +259,13 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options /** * Stores tag name changes in the properties file, called when OK or Apply - * is selected in the OptionsPanel. + * is selected in the options panel. * - * Adds all new tag names to the case database for use. + * Adds all new tag names to the case database for displaying usable tag + * names when tagging. */ @Override public void store() { - //Case.getCurrentCase().getServices().getTagsManager().saveUserTagNames(tagNames); StringBuilder setting = new StringBuilder(); for (UserTagName tagName : tagNames) { if (setting.length() != 0) { @@ -263,31 +278,32 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options Case.getCurrentCase().getServices().getTagsManager().storeNewUserTagNames(tagNames); } } - + /** * Updates the tag names list component with tag names from the properties * file. */ @Override public void load() { - //tagNames = Case.getCurrentCase().getServices().getTagsManager().getUserTagNames(); String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); tagNames.clear(); if (null != setting && !setting.isEmpty()) { List tagNameTuples = Arrays.asList(setting.split(";")); for (String tagNameTuple : tagNameTuples) { String[] tagNameAttributes = tagNameTuple.split(","); - tagNames.add(new UserTagName(tagNameAttributes[0], tagNameAttributes[1], tagNameAttributes[2])); - } + tagNames.add(new UserTagName(tagNameAttributes[0], tagNameAttributes[1], tagNameAttributes[2])); } + } + Collections.sort(tagNames); updateTagNamesListModel(); enableButtons(); } - + + /** + * Only enable delete button when there is a tag name selected in the list. + */ private void enableButtons() { boolean ruleIsSelected = tagNamesList.getSelectedIndex() != -1; deleteTagNameButton.setEnabled(ruleIsSelected); } - - } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index ed4b58eb98..5727fde423 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -44,14 +44,14 @@ import org.sleuthkit.datamodel.TskCoreException; * of tags applied to content and blackboard artifacts by users. */ public class TagsManager implements Closeable { - + private static final Logger logger = Logger.getLogger(TagsManager.class.getName()); private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS private SleuthkitCase caseDb; private final HashMap uniqueTagNames = new HashMap<>(); private boolean tagNamesLoaded = false; - + /** * Constructs a per case Autopsy service that manages the creation, * updating, and deletion of tags applied to content and blackboard @@ -79,7 +79,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getAllTagNames(); } - + /** * Gets a list of all tag names currently being used or tag names loaded * from the properties file. @@ -109,7 +109,7 @@ public class TagsManager implements Closeable { } return new ArrayList<>(tagNameSet); } - + /** * Gets a list of all tag names currently in use for tagging content or * artifacts. @@ -126,7 +126,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getTagNamesInUse(); } - + /** * Checks whether a tag name with a given display name exists. * @@ -138,7 +138,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return uniqueTagNames.containsKey(tagDisplayName); } - + /** * Adds a new tag name to the current case and to the tags settings. * @@ -158,7 +158,7 @@ public class TagsManager implements Closeable { } return addTagName(displayName, "", TagName.HTML_COLOR.NONE); } - + /** * Adds a new tag name to the current case and to the tags settings. * @@ -179,7 +179,7 @@ public class TagsManager implements Closeable { } return addTagName(displayName, description, TagName.HTML_COLOR.NONE); } - + /** * Adds a new tag name to the current case and to the tags settings. * @@ -199,10 +199,10 @@ public class TagsManager implements Closeable { if (null == caseDb) { throw new TskCoreException("Tags manager has been closed"); } - + lazyLoadExistingTagNames(); - - /** + + /* * It is possible user is trying to add back a tag after having deleted * it. */ @@ -222,7 +222,7 @@ public class TagsManager implements Closeable { */ TagName newTagName = caseDb.addTagName(displayName, description, color); uniqueTagNames.put(newTagName.getDisplayName(), newTagName); - + /* * Add the tag name to the tags settings. */ @@ -230,7 +230,7 @@ public class TagsManager implements Closeable { return newTagName; } - + /** * Tags a content object. * @@ -248,7 +248,7 @@ public class TagsManager implements Closeable { } return addContentTag(content, tagName, "", -1, -1); } - + /** * Tags a content object. * @@ -267,7 +267,7 @@ public class TagsManager implements Closeable { } return addContentTag(content, tagName, comment, -1, -1); } - + /** * Tags a content object or a section of a content object. * @@ -325,7 +325,7 @@ public class TagsManager implements Closeable { } return tag; } - + /** * Deletes a content tag. * @@ -349,7 +349,7 @@ public class TagsManager implements Closeable { logger.log(Level.SEVERE, NbBundle.getMessage(TagsManager.class, "TagsManager.deleteContentTag.noCaseWarning"), ex); } } - + /** * Gets all content tags for the current case. * @@ -365,7 +365,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getAllContentTags(); } - + /** * Gets content tags count by tag name. * @@ -383,7 +383,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getContentTagsCountByTagName(tagName); } - + /** * Gets a content tag by tag id. * @@ -401,7 +401,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getContentTagByID(tagID); } - + /** * Gets content tags by tag name. * @@ -420,7 +420,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getContentTagsByTagName(tagName); } - + /** * Gets content tags count by content. * @@ -439,7 +439,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getContentTagsByContent(content); } - + /** * Tags a blackboard artifact object. * @@ -458,7 +458,7 @@ public class TagsManager implements Closeable { } return addBlackboardArtifactTag(artifact, tagName, ""); } - + /** * Tags a blackboard artifact object. * @@ -484,7 +484,7 @@ public class TagsManager implements Closeable { } tag = caseDb.addBlackboardArtifactTag(artifact, tagName, comment); } - + try { Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(tag); } catch (IllegalStateException ex) { @@ -492,7 +492,7 @@ public class TagsManager implements Closeable { } return tag; } - + /** * Deletes a blackboard artifact tag. * @@ -516,7 +516,7 @@ public class TagsManager implements Closeable { logger.log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.deleteBlackboardArtifactTag.noCaseWarning"), ex); } } - + /** * Gets all blackboard artifact tags for the current case. * @@ -532,7 +532,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getAllBlackboardArtifactTags(); } - + /** * Gets blackboard artifact tags count by tag name. * @@ -551,7 +551,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getBlackboardArtifactTagsCountByTagName(tagName); } - + /** * Gets a blackboard artifact tag by tag id. * @@ -569,7 +569,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getBlackboardArtifactTagByID(tagID); } - + /** * Gets blackboard artifact tags by tag name. * @@ -588,7 +588,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getBlackboardArtifactTagsByTagName(tagName); } - + /** * Gets blackboard artifact tags for a particular blackboard artifact. * @@ -607,7 +607,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); return caseDb.getBlackboardArtifactTagsByArtifact(artifact); } - + /** * Closes the tags manager, saving the available tag names to secondary * storage. @@ -621,7 +621,7 @@ public class TagsManager implements Closeable { //saveTagNamesToTagsSettings(); caseDb = null; } - + /** * Populates the tag names collection and the tag names table in the case * database with the existing tag names from all sources. @@ -634,7 +634,7 @@ public class TagsManager implements Closeable { tagNamesLoaded = true; } } - + /** * Adds any tag names that are in the case database to the tag names * collection. @@ -649,7 +649,7 @@ public class TagsManager implements Closeable { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); //NON-NLS } } - + /** * Adds any tag names that are in the properties file to the tag names * collection and to the case database. The properties file is used to make @@ -676,7 +676,7 @@ public class TagsManager implements Closeable { } } } - + /** * Adds the standard tag names to the tag names collection. */ @@ -696,7 +696,7 @@ public class TagsManager implements Closeable { * Adds any user defined tag name to the case db and also to uniqueTagNames, * to allow user tag names to be displayed while tagging. * - * @param userTagNames a List of UserTagName objects to be added + * @param userTagNames a List of UserTagName objects to be potentially added */ void storeNewUserTagNames(List userTagNames) { lazyLoadExistingTagNames(); @@ -711,7 +711,7 @@ public class TagsManager implements Closeable { } } } - + /** * Adds a new tag name to the settings file, used when user creates a new * tag name. @@ -727,7 +727,7 @@ public class TagsManager implements Closeable { setting += tagName.getDisplayName() + "," + tagName.getDescription() + "," + tagName.getColor().toString(); ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting); } - + /** * Returns true if the tag display name contains an illegal character. Used * after a tag display name is retrieved from user input. @@ -747,7 +747,7 @@ public class TagsManager implements Closeable { || content.contains(",") || content.contains(";")); } - + /** * Exception thrown if there is an attempt to add a duplicate tag name. */ @@ -755,5 +755,5 @@ public class TagsManager implements Closeable { private static final long serialVersionUID = 1L; } - + } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/UserTagName.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/UserTagName.java index d70f9d38af..c761665c08 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/UserTagName.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/UserTagName.java @@ -1,53 +1,67 @@ /* -* To change this license header, choose License Headers in Project Properties. -* To change this template file, choose Tools | Templates -* and open the template in the editor. +* Autopsy Forensic Browser +* +* Copyright 2011-2016 Basis Technology Corp. +* Contact: carrier sleuthkit org +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. */ package org.sleuthkit.autopsy.casemodule.services; import java.util.Objects; /** - * Because the DTO TagName constructor should not be called outside of its - * class package, CustomTagName is used in this tags managers panel for the - * purpose of tracking the description and color of each tag name. + * Because the DTO TagName constructor can not be called outside of its class + * package, UserTagName is used to keep track of user tag names while + * preserving properties that will potentially be implemented in the future + * (tag name description and tag name color). */ class UserTagName implements Comparable { - + private final String displayName; private final String description; private final String colorName; - + UserTagName(String displayName, String description, String colorName) { this.displayName = displayName; this.description = description; this.colorName = colorName; } - + String getDisplayName() { return displayName; } - + String getDescription() { return description; } - + String getColorName() { return colorName; } - + @Override public int compareTo(UserTagName other) { return this.getDisplayName().toLowerCase().compareTo(other.getDisplayName().toLowerCase()); } - + @Override public int hashCode() { int hash = 7; hash = 83 * hash + Objects.hashCode(this.displayName); return hash; } - + @Override public boolean equals(Object obj) { if (!(obj instanceof UserTagName)) { @@ -56,15 +70,15 @@ class UserTagName implements Comparable { UserTagName thatTagName = (UserTagName) obj; return this.getDisplayName().equals(thatTagName.getDisplayName()); } - + @Override public String toString() { return displayName; } - + /** * @return A string representation of the tag name in the format that is - * used by the properties file. + * used by the properties file. */ public String toSettingsFormat() { return displayName + "," + description + "," + colorName; From 58a90500b9d62792c0ac2bc450167f5706361822 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Sat, 24 Sep 2016 16:00:24 +0200 Subject: [PATCH 26/54] Extract BinMap from Accounts.java --- .../autopsy/datamodel/AccountType.java | 15 +++ .../sleuthkit/autopsy/datamodel/Accounts.java | 106 ++---------------- .../sleuthkit/autopsy/datamodel/BINMap.java | 98 ++++++++++++++++ .../keywordsearch/TermComponentQuery.java | 10 +- 4 files changed, 128 insertions(+), 101 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/AccountType.java create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/BINMap.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AccountType.java b/Core/src/org/sleuthkit/autopsy/datamodel/AccountType.java new file mode 100644 index 0000000000..f5afc9a32e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AccountType.java @@ -0,0 +1,15 @@ +package org.sleuthkit.autopsy.datamodel; + +public enum AccountType { + CREDIT_CARD("Credit Card"), OTHER("Other"); + + public String getDisplayName() { + return displayName; + } + + private final String displayName; + + private AccountType(String displayName) { + this.displayName = displayName; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java index 4f7ed78859..f825703277 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java @@ -24,8 +24,6 @@ import com.google.common.collect.TreeRangeMap; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.io.IOException; -import java.io.InputStreamReader; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; @@ -44,13 +42,9 @@ import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nonnull; -import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.Immutable; import javax.swing.AbstractAction; import javax.swing.Action; -import org.apache.commons.csv.CSVFormat; -import org.apache.commons.csv.CSVParser; -import org.apache.commons.csv.CSVRecord; import org.apache.commons.lang3.StringUtils; import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; @@ -61,7 +55,6 @@ import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; @@ -86,19 +79,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { * This is a secret handshake with * org.sleuthkit.autopsy.keywordsearch.TermComponentQuery */ - private static final String CREDIT_CARD_NUMBER_ACCOUNT_TYPE = "Credit Card Number"; - /** - * Range Map from a (ranges of) B/IINs to data model object with details of - * the B/IIN, ie, bank name, phone, url, visa/amex/mastercard/..., - */ - @GuardedBy("Accounts.class") - private final static RangeMap iinRanges = TreeRangeMap.create(); - - /** - * Flag for if we have loaded the IINs from the file already. - */ - @GuardedBy("Accounts.class") - private static boolean iinsLoaded = false; + private static final String CREDIT_CARD_ACCOUNT_TYPE = "Credit Card"; private SleuthkitCase skCase; @@ -107,59 +88,6 @@ public class Accounts extends Observable implements AutopsyVisitableItem { */ private boolean showRejected = false; - /** - * Load the IIN range information from disk. If the map has already been - * initialized, don't load again. - */ - synchronized private static void loadIINRanges() { - if (iinsLoaded == false) { - try { - InputStreamReader in = new InputStreamReader(Accounts.class.getResourceAsStream("ranges.csv")); //NON-NLS - CSVParser rangesParser = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(in); - - //parse each row and add to range map - for (CSVRecord record : rangesParser) { - - /** - * Because ranges.csv allows both 6 and (the newer) 8 digit - * IINs, but we need a consistent length for the range map, - * we pad all the numbers out to 8 digits - */ - String start = StringUtils.rightPad(record.get("iin_start"), 8, "0"); //pad start with 0's //NON-NLS - - //if there is no end listed, use start, since ranges will be closed. - String end = StringUtils.defaultIfBlank(record.get("iin_end"), start); //NON-NLS - end = StringUtils.rightPad(end, 8, "99"); //pad end with 9's //NON-NLS - - final String numberLength = record.get("number_length"); //NON-NLS - - try { - IINRange iinRange = new IINRange(Integer.parseInt(start), - Integer.parseInt(end), - StringUtils.isBlank(numberLength) ? null : Integer.valueOf(numberLength), - record.get("scheme"), //NON-NLS - record.get("brand"), //NON-NLS - record.get("type"), //NON-NLS - record.get("country"), //NON-NLS - record.get("bank_name"), //NON-NLS - record.get("bank_url"), //NON-NLS - record.get("bank_phone"), //NON-NLS - record.get("bank_city")); //NON-NLS - - iinRanges.put(Range.closed(iinRange.getIINstart(), iinRange.getIINend()), iinRange); - - } catch (NumberFormatException numberFormatException) { - LOGGER.log(Level.WARNING, "Failed to parse IIN range: " + record.toString(), numberFormatException); //NON-NLS - } - iinsLoaded = true; - } - } catch (IOException ex) { - LOGGER.log(Level.WARNING, "Failed to load IIN ranges form ranges.csv", ex); //NON-NLS - MessageNotifyUtil.Notify.warn("Credit Card Number Discovery", "There was an error loading Bank Identification Number information. Accounts will not have their BINs identified."); - } - } - } - /** * Constructor * @@ -169,6 +97,11 @@ public class Accounts extends Observable implements AutopsyVisitableItem { this.skCase = skCase; } + @Override + public T accept(AutopsyItemVisitor v) { + return v.visit(this); + } + /** * Get the clause that should be used in order to (not) filter out rejected * results from db queries. @@ -189,23 +122,6 @@ public class Accounts extends Observable implements AutopsyVisitableItem { notifyObservers(); } - /** - * Get an IINInfo object with details about the given IIN - * - * @param iin the IIN to get details of. - * - * @return - */ - synchronized static public IINInfo getIINInfo(int iin) { - loadIINRanges(); - return iinRanges.get(iin); - } - - @Override - public T accept(AutopsyItemVisitor v) { - return v.visit(this); - } - /** * Gets a new Action that when invoked toggles showing rejected artifacts on * or off. @@ -294,7 +210,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { * by a bank. */ @Immutable - static private class IINRange implements IINInfo { + static class IINRange implements IINInfo { private final int IINStart; //start of IIN range, 8 digits private final int IINEnd; // end (incluse ) of IIN rnage, 8 digits @@ -333,7 +249,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { * @param bank_phone the phone number of the issuer * @param bank_city the city of the issuer */ - private IINRange(int IIN_start, int IIN_end, Integer number_length, String scheme, String brand, String type, String country, String bank_name, String bank_url, String bank_phone, String bank_city) { + IINRange(int IIN_start, int IIN_end, Integer number_length, String scheme, String brand, String type, String country, String bank_name, String bank_url, String bank_phone, String bank_city) { this.IINStart = IIN_start; this.IINEnd = IIN_end; @@ -543,7 +459,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { @Override protected Node createNodeForKey(String key) { - if (key.equals(CREDIT_CARD_NUMBER_ACCOUNT_TYPE)) { + if (key.equals(CREDIT_CARD_ACCOUNT_TYPE)) { return new CreditCardNumberAccountTypeNode(key); } else { //Flesh out what happens with other account types here. @@ -795,7 +711,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { + " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SOLR_DOCUMENT_ID.getTypeID() //NON-NLS + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS - + " AND account_type.value_text = '" + CREDIT_CARD_NUMBER_ACCOUNT_TYPE + "'" //NON-NLS + + " AND account_type.value_text = '" + CREDIT_CARD_ACCOUNT_TYPE + "'" //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + getRejectedArtifactFilterClause() + " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS @@ -1066,7 +982,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { final Integer bin = Integer.valueOf(resultSet.getString("BIN")); long count = resultSet.getLong("count"); - IINRange iinRange = (IINRange) getIINInfo(bin); + IINRange iinRange = (IINRange) BINMap.getIINInfo(bin); BinResult previousResult = ranges.get(bin); if (previousResult != null) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BINMap.java b/Core/src/org/sleuthkit/autopsy/datamodel/BINMap.java new file mode 100644 index 0000000000..5a4f99154e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BINMap.java @@ -0,0 +1,98 @@ +package org.sleuthkit.autopsy.datamodel; + +import com.google.common.collect.Range; +import com.google.common.collect.RangeMap; +import com.google.common.collect.TreeRangeMap; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.concurrent.GuardedBy; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVRecord; +import org.apache.commons.lang3.StringUtils; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; + +public class BINMap { + + private static final Logger LOGGER = Logger.getLogger(BINMap.class.getName()); + /** + * Range Map from a (ranges of) B/IINs to data model object with details of + * the B/IIN, ie, bank name, phone, url, visa/amex/mastercard/..., + */ + @GuardedBy("Accounts.class") + private final static RangeMap iinRanges = TreeRangeMap.create(); + + /** + * Flag for if we have loaded the IINs from the file already. + */ + @GuardedBy("Accounts.class") + private static boolean iinsLoaded = false; + + /** + * Load the IIN range information from disk. If the map has already been + * initialized, don't load again. + */ + synchronized private static void loadIINRanges() { + if (iinsLoaded == false) { + try { + InputStreamReader in = new InputStreamReader(Accounts.class.getResourceAsStream("ranges.csv")); //NON-NLS + CSVParser rangesParser = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(in); + + //parse each row and add to range map + for (CSVRecord record : rangesParser) { + + /** + * Because ranges.csv allows both 6 and (the newer) 8 digit + * IINs, but we need a consistent length for the range map, + * we pad all the numbers out to 8 digits + */ + String start = StringUtils.rightPad(record.get("iin_start"), 8, "0"); //pad start with 0's //NON-NLS + + //if there is no end listed, use start, since ranges will be closed. + String end = StringUtils.defaultIfBlank(record.get("iin_end"), start); //NON-NLS + end = StringUtils.rightPad(end, 8, "99"); //pad end with 9's //NON-NLS + + final String numberLength = record.get("number_length"); //NON-NLS + + try { + Accounts.IINRange iinRange = new Accounts.IINRange(Integer.parseInt(start), + Integer.parseInt(end), + StringUtils.isBlank(numberLength) ? null : Integer.valueOf(numberLength), + record.get("scheme"), //NON-NLS + record.get("brand"), //NON-NLS + record.get("type"), //NON-NLS + record.get("country"), //NON-NLS + record.get("bank_name"), //NON-NLS + record.get("bank_url"), //NON-NLS + record.get("bank_phone"), //NON-NLS + record.get("bank_city")); //NON-NLS + + iinRanges.put(Range.closed(iinRange.getIINstart(), iinRange.getIINend()), iinRange); + + } catch (NumberFormatException numberFormatException) { + LOGGER.log(Level.WARNING, "Failed to parse IIN range: " + record.toString(), numberFormatException); //NON-NLS + } + iinsLoaded = true; + } + } catch (IOException ex) { + LOGGER.log(Level.WARNING, "Failed to load IIN ranges form ranges.csv", ex); //NON-NLS + MessageNotifyUtil.Notify.warn("Credit Card Number Discovery", "There was an error loading Bank Identification Number information. Accounts will not have their BINs identified."); + } + } + } + + /** + * Get an IINInfo object with details about the given IIN + * + * @param iin the IIN to get details of. + * + * @return + */ + synchronized static public Accounts.IINInfo getIINInfo(int iin) { + loadIINRanges(); + return iinRanges.get(iin); + } + +} diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java index 7e855b57a1..40dd483165 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java @@ -34,7 +34,9 @@ import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.response.TermsResponse.Term; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Version; +import org.sleuthkit.autopsy.datamodel.AccountType; import org.sleuthkit.autopsy.datamodel.Accounts; +import org.sleuthkit.autopsy.datamodel.BINMap; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; @@ -56,10 +58,6 @@ final class TermComponentQuery implements KeywordSearchQuery { private static final BlackboardAttribute.Type ACCOUNT_NUMBER_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER); private static final BlackboardAttribute.Type ACOUNT_TYPE_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE); - /** - * This is a secret handshake with org.sleuthkit.autopsy.datamodel.Accounts - */ - private static final String CREDIT_CARD_NUMBER_ACCOUNT_TYPE = "Credit Card Number"; //TODO: move these regex and the luhn check to a new class, something like: CreditCardNumberValidator /* @@ -194,7 +192,7 @@ final class TermComponentQuery implements KeywordSearchQuery { //if the keyword hit matched the credit card number keyword/regex... if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER) { newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT); - newArtifact.addAttribute(new BlackboardAttribute(ACOUNT_TYPE_TYPE, MODULE_NAME, CREDIT_CARD_NUMBER_ACCOUNT_TYPE)); + newArtifact.addAttribute(new BlackboardAttribute(ACOUNT_TYPE_TYPE, MODULE_NAME, AccountType.CREDIT_CARD.name())); // make account artifact //try to match it against the track 1 regex @@ -219,7 +217,7 @@ final class TermComponentQuery implements KeywordSearchQuery { String ccn = newArtifact.getAttribute(ACCOUNT_NUMBER_TYPE).getValueString(); final int iin = Integer.parseInt(ccn.substring(0, 8)); - Accounts.IINInfo iinInfo = Accounts.getIINInfo(iin); + Accounts.IINInfo iinInfo = BINMap.getIINInfo(iin); if (iinInfo != null) { iinInfo.getScheme().ifPresent(scheme From bcdb16638b801356a1c3091e3ef4adc02ba64bf9 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Sat, 24 Sep 2016 16:44:28 +0200 Subject: [PATCH 27/54] use new sleuthkit Account.Type enum --- .../autopsy/datamodel/AccountType.java | 15 --------------- .../sleuthkit/autopsy/datamodel/Accounts.java | 17 ++++++++--------- .../keywordsearch/TermComponentQuery.java | 15 +++++++-------- 3 files changed, 15 insertions(+), 32 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/AccountType.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AccountType.java b/Core/src/org/sleuthkit/autopsy/datamodel/AccountType.java deleted file mode 100644 index f5afc9a32e..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AccountType.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.sleuthkit.autopsy.datamodel; - -public enum AccountType { - CREDIT_CARD("Credit Card"), OTHER("Other"); - - public String getDisplayName() { - return displayName; - } - - private final String displayName; - - private AccountType(String displayName) { - this.displayName = displayName; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java index f825703277..d203e07925 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java @@ -58,6 +58,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; @@ -75,12 +76,6 @@ public class Accounts extends Observable implements AutopsyVisitableItem { @NbBundle.Messages("AccountsRootNode.name=Accounts") final public static String NAME = Bundle.AccountsRootNode_name(); - /** - * This is a secret handshake with - * org.sleuthkit.autopsy.keywordsearch.TermComponentQuery - */ - private static final String CREDIT_CARD_ACCOUNT_TYPE = "Credit Card"; - private SleuthkitCase skCase; /** @@ -459,7 +454,11 @@ public class Accounts extends Observable implements AutopsyVisitableItem { @Override protected Node createNodeForKey(String key) { - if (key.equals(CREDIT_CARD_ACCOUNT_TYPE)) { + if (key.equals( /** + * This is a secret handshake with + * org.sleuthkit.autopsy.keywordsearch.TermComponentQuery + */ + Account.Type.CREDIT_CARD.name())) { return new CreditCardNumberAccountTypeNode(key); } else { //Flesh out what happens with other account types here. @@ -708,10 +707,10 @@ public class Accounts extends Observable implements AutopsyVisitableItem { + " GROUP_CONCAT(blackboard_artifacts.review_status_id) AS review_status_ids " + " FROM blackboard_artifacts " //NON-NLS + " LEFT JOIN blackboard_attributes as solr_attribute ON blackboard_artifacts.artifact_id = solr_attribute.artifact_id " //NON-NLS - + " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SOLR_DOCUMENT_ID.getTypeID() //NON-NLS + + " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS - + " AND account_type.value_text = '" + CREDIT_CARD_ACCOUNT_TYPE + "'" //NON-NLS + + " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.name() + "'" //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + getRejectedArtifactFilterClause() + " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java index 40dd483165..0f7858448f 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java @@ -34,10 +34,10 @@ import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.response.TermsResponse.Term; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Version; -import org.sleuthkit.autopsy.datamodel.AccountType; import org.sleuthkit.autopsy.datamodel.Accounts; import org.sleuthkit.autopsy.datamodel.BINMap; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -54,10 +54,9 @@ final class TermComponentQuery implements KeywordSearchQuery { private static final boolean DEBUG = Version.Type.DEVELOPMENT.equals(Version.getBuildType()); private static final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName(); - private static final BlackboardAttribute.Type SOLR_DOCUMENT_ID_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SOLR_DOCUMENT_ID); - private static final BlackboardAttribute.Type ACCOUNT_NUMBER_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER); - private static final BlackboardAttribute.Type ACOUNT_TYPE_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE); - + private static final BlackboardAttribute.Type KEYWORD_SEARCH_DOCUMENT_ID = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID); + private static final BlackboardAttribute.Type CREDIT_CARD_NUMBER = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER); + private static final BlackboardAttribute.Type ACOUNT_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE); //TODO: move these regex and the luhn check to a new class, something like: CreditCardNumberValidator /* @@ -192,7 +191,7 @@ final class TermComponentQuery implements KeywordSearchQuery { //if the keyword hit matched the credit card number keyword/regex... if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER) { newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT); - newArtifact.addAttribute(new BlackboardAttribute(ACOUNT_TYPE_TYPE, MODULE_NAME, AccountType.CREDIT_CARD.name())); + newArtifact.addAttribute(new BlackboardAttribute(ACOUNT_TYPE, MODULE_NAME, Account.Type.CREDIT_CARD.name())); // make account artifact //try to match it against the track 1 regex @@ -210,11 +209,11 @@ final class TermComponentQuery implements KeywordSearchQuery { AbstractFile file = (AbstractFile) hit.getContent(); if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS || file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) { - newArtifact.addAttribute(new BlackboardAttribute(SOLR_DOCUMENT_ID_TYPE, MODULE_NAME, hit.getSolrDocumentId())); + newArtifact.addAttribute(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId())); } } - String ccn = newArtifact.getAttribute(ACCOUNT_NUMBER_TYPE).getValueString(); + String ccn = newArtifact.getAttribute(CREDIT_CARD_NUMBER).getValueString(); final int iin = Integer.parseInt(ccn.substring(0, 8)); Accounts.IINInfo iinInfo = BINMap.getIINInfo(iin); From a39419393da3bf4f331b64b5d11e9aa52fd06adc Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 26 Sep 2016 14:04:41 +0200 Subject: [PATCH 28/54] introduce datamodel._private package and move some interfaces and classes there; create basic generic support for other account types; some renaming for clarity --- .../datamodel/AbstractContentChildren.java | 5 + .../sleuthkit/autopsy/datamodel/BINMap.java | 98 ------ .../datamodel/BlackboardArtifactNode.java | 42 +-- .../autopsy/datamodel/Bundle.properties | 11 - .../autopsy/datamodel/CreditCards.java | 171 +++++++++++ .../autopsy/datamodel/DataSources.java | 3 + .../autopsy/datamodel/DeletedContent.java | 2 + .../datamodel/DisplayableItemNodeVisitor.java | 7 + .../autopsy/datamodel/EmailExtracted.java | 2 + .../autopsy/datamodel/ExtractedContent.java | 2 + .../sleuthkit/autopsy/datamodel/FileSize.java | 2 + .../autopsy/datamodel/FileTypeNode.java | 1 + .../autopsy/datamodel/FileTypesNode.java | 1 + .../autopsy/datamodel/HashsetHits.java | 2 + .../autopsy/datamodel/InterestingHits.java | 2 + .../autopsy/datamodel/KeywordHits.java | 2 + .../datamodel/RecentFilesChildren.java | 1 + .../datamodel/RecentFilesFilterChildren.java | 2 +- .../datamodel/RecentFilesFilterNode.java | 2 +- .../sleuthkit/autopsy/datamodel/Reports.java | 2 + .../sleuthkit/autopsy/datamodel/Results.java | 2 + .../autopsy/datamodel/ResultsNode.java | 1 + .../org/sleuthkit/autopsy/datamodel/Tags.java | 2 + .../sleuthkit/autopsy/datamodel/Views.java | 2 + .../autopsy/datamodel/ViewsNode.java | 1 + .../datamodel/{ => _private}/Accounts.java | 289 +++++++++--------- .../{ => _private}/AutopsyItemVisitor.java | 17 +- .../{ => _private}/AutopsyVisitableItem.java | 5 +- .../datamodel/_private/Bundle.properties | 12 + .../FileTypeExtensionFilters.java | 34 +-- .../datamodel/{ => _private}/RecentFiles.java | 4 +- .../directorytree/DataResultFilterNode.java | 2 +- .../DirectoryTreeTopComponent.java | 2 +- .../keywordsearch/ExtractedContentViewer.java | 2 +- .../keywordsearch/TermComponentQuery.java | 25 +- 35 files changed, 444 insertions(+), 316 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/BINMap.java create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/CreditCards.java rename Core/src/org/sleuthkit/autopsy/datamodel/{ => _private}/Accounts.java (85%) rename Core/src/org/sleuthkit/autopsy/datamodel/{ => _private}/AutopsyItemVisitor.java (85%) rename Core/src/org/sleuthkit/autopsy/datamodel/{ => _private}/AutopsyVisitableItem.java (91%) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/_private/Bundle.properties rename Core/src/org/sleuthkit/autopsy/datamodel/{ => _private}/FileTypeExtensionFilters.java (90%) rename Core/src/org/sleuthkit/autopsy/datamodel/{ => _private}/RecentFiles.java (96%) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index 701367e9ba..86f247395e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -18,6 +18,11 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.Accounts; +import org.sleuthkit.autopsy.datamodel._private.FileTypeExtensionFilters; +import org.sleuthkit.autopsy.datamodel._private.RecentFiles; +import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; +import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children.Keys; import org.openide.nodes.Node; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BINMap.java b/Core/src/org/sleuthkit/autopsy/datamodel/BINMap.java deleted file mode 100644 index 5a4f99154e..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BINMap.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.sleuthkit.autopsy.datamodel; - -import com.google.common.collect.Range; -import com.google.common.collect.RangeMap; -import com.google.common.collect.TreeRangeMap; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.annotation.concurrent.GuardedBy; -import org.apache.commons.csv.CSVFormat; -import org.apache.commons.csv.CSVParser; -import org.apache.commons.csv.CSVRecord; -import org.apache.commons.lang3.StringUtils; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; - -public class BINMap { - - private static final Logger LOGGER = Logger.getLogger(BINMap.class.getName()); - /** - * Range Map from a (ranges of) B/IINs to data model object with details of - * the B/IIN, ie, bank name, phone, url, visa/amex/mastercard/..., - */ - @GuardedBy("Accounts.class") - private final static RangeMap iinRanges = TreeRangeMap.create(); - - /** - * Flag for if we have loaded the IINs from the file already. - */ - @GuardedBy("Accounts.class") - private static boolean iinsLoaded = false; - - /** - * Load the IIN range information from disk. If the map has already been - * initialized, don't load again. - */ - synchronized private static void loadIINRanges() { - if (iinsLoaded == false) { - try { - InputStreamReader in = new InputStreamReader(Accounts.class.getResourceAsStream("ranges.csv")); //NON-NLS - CSVParser rangesParser = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(in); - - //parse each row and add to range map - for (CSVRecord record : rangesParser) { - - /** - * Because ranges.csv allows both 6 and (the newer) 8 digit - * IINs, but we need a consistent length for the range map, - * we pad all the numbers out to 8 digits - */ - String start = StringUtils.rightPad(record.get("iin_start"), 8, "0"); //pad start with 0's //NON-NLS - - //if there is no end listed, use start, since ranges will be closed. - String end = StringUtils.defaultIfBlank(record.get("iin_end"), start); //NON-NLS - end = StringUtils.rightPad(end, 8, "99"); //pad end with 9's //NON-NLS - - final String numberLength = record.get("number_length"); //NON-NLS - - try { - Accounts.IINRange iinRange = new Accounts.IINRange(Integer.parseInt(start), - Integer.parseInt(end), - StringUtils.isBlank(numberLength) ? null : Integer.valueOf(numberLength), - record.get("scheme"), //NON-NLS - record.get("brand"), //NON-NLS - record.get("type"), //NON-NLS - record.get("country"), //NON-NLS - record.get("bank_name"), //NON-NLS - record.get("bank_url"), //NON-NLS - record.get("bank_phone"), //NON-NLS - record.get("bank_city")); //NON-NLS - - iinRanges.put(Range.closed(iinRange.getIINstart(), iinRange.getIINend()), iinRange); - - } catch (NumberFormatException numberFormatException) { - LOGGER.log(Level.WARNING, "Failed to parse IIN range: " + record.toString(), numberFormatException); //NON-NLS - } - iinsLoaded = true; - } - } catch (IOException ex) { - LOGGER.log(Level.WARNING, "Failed to load IIN ranges form ranges.csv", ex); //NON-NLS - MessageNotifyUtil.Notify.warn("Credit Card Number Discovery", "There was an error loading Bank Identification Number information. Accounts will not have their BINs identified."); - } - } - } - - /** - * Get an IINInfo object with details about the given IIN - * - * @param iin the IIN to get details of. - * - * @return - */ - synchronized static public Accounts.IINInfo getIINInfo(int iin) { - loadIINRanges(); - return iinRanges.get(iin); - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index fbc17420b2..788d6969ec 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -185,13 +185,13 @@ public class BlackboardArtifactNode extends DisplayableItemNode { ss = Sheet.createPropertiesSet(); s.put(ss); } - final String NO_DESCR = NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.noDesc.text"); + final String NO_DESCR = NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.noDesc.text"); Map map = new LinkedHashMap<>(); fillPropertyMap(map, artifact); - ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.srcFile.name"), - NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.srcFile.displayName"), + ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.name"), + NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.displayName"), NO_DESCR, this.getDisplayName())); @@ -222,13 +222,13 @@ public class BlackboardArtifactNode extends DisplayableItemNode { actualMimeType = ""; //NON-NLS } } - ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.ext.name"), - NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.ext.displayName"), + ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.name"), + NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.displayName"), NO_DESCR, ext)); ss.put(new NodeProperty<>( - NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.mimeType.name"), - NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.mimeType.displayName"), + NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.mimeType.name"), + NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.mimeType.displayName"), NO_DESCR, actualMimeType)); } @@ -243,32 +243,32 @@ public class BlackboardArtifactNode extends DisplayableItemNode { if (sourcePath.isEmpty() == false) { ss.put(new NodeProperty<>( - NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.filePath.name"), - NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.filePath.displayName"), + NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.filePath.name"), + NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.filePath.displayName"), NO_DESCR, sourcePath)); } if (Arrays.asList(SHOW_FILE_METADATA).contains(artifactTypeId)) { AbstractFile file = associated instanceof AbstractFile ? (AbstractFile) associated : null; - ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.name"), - NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.displayName"), + ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.name"), + NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.displayName"), "", file != null ? ContentUtils.getStringTime(file.getMtime(), file) : "")); - ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.name"), - NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.displayName"), + ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.name"), + NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.displayName"), "", file != null ? ContentUtils.getStringTime(file.getCtime(), file) : "")); - ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.name"), - NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.displayName"), + ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.name"), + NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.displayName"), "", file != null ? ContentUtils.getStringTime(file.getAtime(), file) : "")); - ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.name"), - NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.displayName"), + ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.name"), + NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.displayName"), "", file != null ? ContentUtils.getStringTime(file.getCrtime(), file) : "")); - ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.name"), - NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.displayName"), + ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.name"), + NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.displayName"), "", associated.getSize())); } @@ -287,8 +287,8 @@ public class BlackboardArtifactNode extends DisplayableItemNode { if (dataSourceStr.isEmpty() == false) { ss.put(new NodeProperty<>( - NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.dataSrc.name"), - NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.dataSrc.displayName"), + NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.dataSrc.name"), + NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.dataSrc.displayName"), NO_DESCR, dataSourceStr)); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index 7eb9bc14f4..3c24e02283 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -118,17 +118,6 @@ FileSize.createSheet.filterType.displayName=Filter Type FileSize.createSheet.filterType.desc=no description FileSize.exception.notSupported.msg=Not supported for this type of Displayable Item\: {0} FileTypeChildren.exception.notSupported.msg=Not supported for this type of Displayable Item\: {0} -FileTypeExtensionFilters.tskImgFilter.text=Images -FileTypeExtensionFilters.tskVideoFilter.text=Videos -FileTypeExtensionFilters.tskAudioFilter.text=Audio -FileTypeExtensionFilters.tskArchiveFilter.text=Archives -FileTypeExtensionFilters.tskDocumentFilter.text=Documents -FileTypeExtensionFilters.tskExecFilter.text=Executable -FileTypeExtensionFilters.autDocHtmlFilter.text=HTML -FileTypeExtensionFilters.autDocOfficeFilter.text=Office -FileTypeExtensionFilters.autoDocPdfFilter.text=PDF -FileTypeExtensionFilters.autDocTxtFilter.text=Plain Text -FileTypeExtensionFilters.autDocRtfFilter.text=Rich Text FileTypeNode.createSheet.filterType.name=Filter Type FileTypeNode.createSheet.filterType.displayName=Filter Type FileTypeNode.createSheet.filterType.desc=no description diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/CreditCards.java b/Core/src/org/sleuthkit/autopsy/datamodel/CreditCards.java new file mode 100644 index 0000000000..17593d8547 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/CreditCards.java @@ -0,0 +1,171 @@ +package org.sleuthkit.autopsy.datamodel; + +import com.google.common.collect.Range; +import com.google.common.collect.RangeMap; +import com.google.common.collect.TreeRangeMap; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.concurrent.GuardedBy; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVRecord; +import org.apache.commons.lang3.StringUtils; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.datamodel._private.Accounts; + +public class CreditCards { + + //Interface for objects that provide details about one or more BINs. + static public interface BankIdentificationNumber { + + /** + * Get the city of the issuer. + * + * @return the city of the issuer. + */ + Optional getBankCity(); + + /** + * Get the name of the issuer. + * + * @return the name of the issuer. + */ + Optional getBankName(); + + /** + * Get the phone number of the issuer. + * + * @return the phone number of the issuer. + */ + Optional getBankPhoneNumber(); + + /** + * Get the URL of the issuer. + * + * @return the URL of the issuer. + */ + Optional getBankURL(); + + /** + * Get the brand of this BIN range. + * + * @return the brand of this BIN range. + */ + Optional getBrand(); + + /** + * Get the type of card (credit vs debit) for this BIN range. + * + * @return the type of cards in this BIN range. + */ + Optional getCardType(); + + /** + * Get the country of the issuer. + * + * @return the country of the issuer. + */ + Optional getCountry(); + + /** + * Get the length of account numbers in this BIN range. + * + * NOTE: the length is currently unused, and not in the data file for + * any ranges. It could be quite helpfull for validation... + * + * @return the length of account numbers in this BIN range. Or an empty + * Optional if the length is unknown. + * + */ + Optional getNumberLength(); + + /** + * Get the scheme this BIN range uses to amex,visa,mastercard, etc + * + * @return the scheme this BIN range uses. + */ + Optional getScheme(); + } + + private static final Logger LOGGER = Logger.getLogger(CreditCards.class.getName()); + /** + * Range Map from a (ranges of) BINs to data model object with details of + * the BIN, ie, bank name, phone, url, visa/amex/mastercard/..., + */ + @GuardedBy("CreditCards.class") + private final static RangeMap binRanges = TreeRangeMap.create(); + + /** + * Flag for if we have loaded the BINs from the file already. + */ + @GuardedBy("CreditCards.class") + private static boolean binsLoaded = false; + + /** + * Load the BIN range information from disk. If the map has already been + * initialized, don't load again. + */ + synchronized private static void loadBINRanges() { + if (binsLoaded == false) { + try { + InputStreamReader in = new InputStreamReader(CreditCards.class.getResourceAsStream("ranges.csv")); //NON-NLS + CSVParser rangesParser = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(in); + + //parse each row and add to range map + for (CSVRecord record : rangesParser) { + + /** + * Because ranges.csv allows both 6 and (the newer) 8 digit + * BINs, but we need a consistent length for the range map, + * we pad all the numbers out to 8 digits + */ + String start = StringUtils.rightPad(record.get("iin_start"), 8, "0"); //pad start with 0's //NON-NLS + + //if there is no end listed, use start, since ranges will be closed. + String end = StringUtils.defaultIfBlank(record.get("iin_end"), start); //NON-NLS + end = StringUtils.rightPad(end, 8, "99"); //pad end with 9's //NON-NLS + + final String numberLength = record.get("number_length"); //NON-NLS + + try { + Accounts.BINRange binRange = new Accounts.BINRange(Integer.parseInt(start), + Integer.parseInt(end), + StringUtils.isBlank(numberLength) ? null : Integer.valueOf(numberLength), + record.get("scheme"), //NON-NLS + record.get("brand"), //NON-NLS + record.get("type"), //NON-NLS + record.get("country"), //NON-NLS + record.get("bank_name"), //NON-NLS + record.get("bank_url"), //NON-NLS + record.get("bank_phone"), //NON-NLS + record.get("bank_city")); //NON-NLS + + binRanges.put(Range.closed(binRange.getBINstart(), binRange.getBINend()), binRange); + + } catch (NumberFormatException numberFormatException) { + LOGGER.log(Level.WARNING, "Failed to parse BIN range: " + record.toString(), numberFormatException); //NON-NLS + } + binsLoaded = true; + } + } catch (IOException ex) { + LOGGER.log(Level.WARNING, "Failed to load BIN ranges form ranges.csv", ex); //NON-NLS + MessageNotifyUtil.Notify.warn("Credit Card Number Discovery", "There was an error loading Bank Identification Number information. Accounts will not have their BINs identified."); + } + } + } + + /** + * Get an BINInfo object with details about the given BIN + * + * @param bin the BIN to get details of. + * + * @return + */ + synchronized static public BankIdentificationNumber getBINInfo(int bin) { + loadBINRanges(); + return binRanges.get(bin); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java index e7aa3d8fe4..3ddb6a158d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java @@ -18,6 +18,9 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; +import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; + /** * Root node to store the data sources in a case */ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index 3a1e70b164..92b75059b9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; +import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 14171a6201..45a5abc66e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -22,6 +22,7 @@ import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.De import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode; import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode; import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode; +import org.sleuthkit.autopsy.datamodel._private.Accounts; /** * Visitor pattern that goes over all nodes in the directory tree. This includes @@ -137,6 +138,8 @@ public interface DisplayableItemNodeVisitor { T visit(Accounts.BINNode binNode); + T visit(Accounts.DefaultAccountTypeNode node); + /** * Visitor with an implementable default behavior for all types. Override * specific visit types to not use the default behavior. @@ -378,5 +381,9 @@ public interface DisplayableItemNodeVisitor { public T visit(Accounts.BINNode node) { return defaultVisit(node); } + @Override + public T visit(Accounts.DefaultAccountTypeNode node) { + return defaultVisit(node); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 89e8c5b217..b9626d5646 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; +import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.sql.ResultSet; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 4a420f926d..561e96d510 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; +import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java index c5fee7d696..88ac89bdc9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; +import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java index e1b7553aba..e03b2ac924 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.FileTypeExtensionFilters; import java.util.List; import java.util.Observable; import java.util.Observer; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java index 3bbbf0b63c..86913224e1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.FileTypeExtensionFilters; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Arrays; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index 2264b95ac6..ab2d6c2492 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; +import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.sql.ResultSet; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index b07f5568c0..57239561ba 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; +import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.sql.ResultSet; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 319d9ecf9f..8b155ccf32 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; +import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.sql.ResultSet; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesChildren.java index 391a49f757..d7665b2157 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesChildren.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.RecentFiles; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Arrays; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesFilterChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesFilterChildren.java index c6c9c72471..903028abed 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesFilterChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesFilterChildren.java @@ -28,7 +28,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; import org.openide.nodes.Node; -import org.sleuthkit.autopsy.datamodel.RecentFiles.RecentFilesFilter; +import org.sleuthkit.autopsy.datamodel._private.RecentFiles.RecentFilesFilter; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesFilterNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesFilterNode.java index e9d8fe6b63..e4ab6811cf 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesFilterNode.java @@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; -import org.sleuthkit.autopsy.datamodel.RecentFiles.RecentFilesFilter; +import org.sleuthkit.autopsy.datamodel._private.RecentFiles.RecentFilesFilter; import org.sleuthkit.datamodel.SleuthkitCase; /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java b/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java index 7a4f581966..5bb16c5602 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Reports.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; +import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; import java.awt.Desktop; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Results.java b/Core/src/org/sleuthkit/autopsy/datamodel/Results.java index 61e9ad626e..60f0247f97 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Results.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Results.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; +import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; import org.sleuthkit.datamodel.SleuthkitCase; /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java index aa4688dea0..31bd236ade 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.Accounts; import java.util.Arrays; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index ac85cd8787..1ab1e72ad0 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; +import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Collections; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Views.java b/Core/src/org/sleuthkit/autopsy/datamodel/Views.java index 4a9dee9886..4e5ef0f027 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Views.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Views.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; +import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; import org.sleuthkit.datamodel.SleuthkitCase; /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java index 4919594378..6f7ec0f2c5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.datamodel; +import org.sleuthkit.autopsy.datamodel._private.FileTypeExtensionFilters; import java.util.Arrays; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java similarity index 85% rename from Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java rename to Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java index d203e07925..9b87639c35 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datamodel; +package org.sleuthkit.autopsy.datamodel._private; import com.google.common.collect.Range; import com.google.common.collect.RangeMap; @@ -46,7 +46,6 @@ import javax.annotation.concurrent.Immutable; import javax.swing.AbstractAction; import javax.swing.Action; import org.apache.commons.lang3.StringUtils; -import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; @@ -55,11 +54,18 @@ import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; +import org.sleuthkit.autopsy.datamodel.CreditCards; +import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory; +import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; +import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; +import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; @@ -69,10 +75,9 @@ import org.sleuthkit.datamodel.TskCoreException; * AutopsyVisitableItem for the Accounts section of the tree. All nodes, * factories, and data objects related to accounts are inner classes. */ -public class Accounts extends Observable implements AutopsyVisitableItem { +final public class Accounts extends Observable implements AutopsyVisitableItem { private static final Logger LOGGER = Logger.getLogger(Accounts.class.getName()); - private static final BlackboardArtifact.Type ACCOUNT_TYPE = new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT); @NbBundle.Messages("AccountsRootNode.name=Accounts") final public static String NAME = Bundle.AccountsRootNode_name(); @@ -88,7 +93,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { * * @param skCase The SleuthkitCase object to use for db queries. */ - Accounts(SleuthkitCase skCase) { + public Accounts(SleuthkitCase skCase) { this.skCase = skCase; } @@ -128,89 +133,17 @@ public class Accounts extends Observable implements AutopsyVisitableItem { return new ToggleShowRejected(); } - //Interface for objects that provide details about one or more IINs. - static public interface IINInfo { - - /** - * Get the city of the issuer. - * - * @return the city of the issuer. - */ - Optional getBankCity(); - - /** - * Get the name of the issuer. - * - * @return the name of the issuer. - */ - Optional getBankName(); - - /** - * Get the phone number of the issuer. - * - * @return the phone number of the issuer. - */ - Optional getBankPhoneNumber(); - - /** - * Get the URL of the issuer. - * - * @return the URL of the issuer. - */ - Optional getBankURL(); - - /** - * Get the brand of this IIN range. - * - * @return the brand of this IIN range. - */ - Optional getBrand(); - - /** - * Get the type of card (credit vs debit) for this IIN range. - * - * @return the type of cards in this IIN range. - */ - Optional getCardType(); - - /** - * Get the country of the issuer. - * - * @return the country of the issuer. - */ - Optional getCountry(); - - /** - * Get the length of account numbers in this IIN range. - * - * NOTE: the length is currently unused, and not in the data file for - * any ranges. It could be quite helpfull for validation... - * - * @return the length of account numbers in this IIN range. Or an empty - * Optional if the length is unknown. - * - */ - Optional getNumberLength(); - - /** - * Get the scheme this IIN range uses to, eg amex,visa,mastercard, etc - * - * @return the scheme this IIN range uses. - */ - Optional getScheme(); - } - /** - * Details of a range of Issuer/Bank Identifiaction Number(s) (IIN/BIN) used - * by a bank. + * Details of a range of Bank Identification Number(s) (BIN) used * by a + * bank. */ @Immutable - static class IINRange implements IINInfo { + public static class BINRange implements CreditCards.BankIdentificationNumber { - private final int IINStart; //start of IIN range, 8 digits - private final int IINEnd; // end (incluse ) of IIN rnage, 8 digits + private final int BINStart; //start of BIN range, 8 digits + private final int BINEnd; // end (incluse ) of BIN rnage, 8 digits - private final Integer numberLength; // the length of accounts numbers with this IIN, currently unused + private final Integer numberLength; // the length of accounts numbers with this BIN, currently unused /** * AMEX, VISA, MASTERCARD, DINERS, DISCOVER, UNIONPAY @@ -231,12 +164,12 @@ public class Accounts extends Observable implements AutopsyVisitableItem { /** * Constructor * - * @param IIN_start the first IIN in the range, must be 8 digits - * @param IIN_end the last(inclusive) IIN in the range, must be 8 + * @param BIN_start the first BIN in the range, must be 8 digits + * @param BIN_end the last(inclusive) BIN in the range, must be 8 * digits - * @param number_length the length of account numbers in this IIN range + * @param number_length the length of account numbers in this BIN range * @param scheme amex/visa/mastercard/etc - * @param brand the brand of this IIN range + * @param brand the brand of this BIN range * @param type credit vs debit * @param country the country of the issuer * @param bank_name the name of the issuer @@ -244,9 +177,9 @@ public class Accounts extends Observable implements AutopsyVisitableItem { * @param bank_phone the phone number of the issuer * @param bank_city the city of the issuer */ - IINRange(int IIN_start, int IIN_end, Integer number_length, String scheme, String brand, String type, String country, String bank_name, String bank_url, String bank_phone, String bank_city) { - this.IINStart = IIN_start; - this.IINEnd = IIN_end; + public BINRange(int BIN_start, int BIN_end, Integer number_length, String scheme, String brand, String type, String country, String bank_name, String bank_url, String bank_phone, String bank_city) { + this.BINStart = BIN_start; + this.BINEnd = BIN_end; this.numberLength = number_length; this.scheme = StringUtils.defaultIfBlank(scheme, null); @@ -260,21 +193,21 @@ public class Accounts extends Observable implements AutopsyVisitableItem { } /** - * Get the first IIN in this range + * Get the first BIN in this range * - * @return the first IIN in this range. + * @return the first BIN in this range. */ - int getIINstart() { - return IINStart; + public int getBINstart() { + return BINStart; } /** - * Get the last (inclusive) IIN in this range. + * Get the last (inclusive) BIN in this range. * - * @return the last (inclusive) IIN in this range. + * @return the last (inclusive) BIN in this range. */ - int getIINend() { - return IINEnd; + public int getBINend() { + return BINEnd; } @Override @@ -354,7 +287,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { @NbBundle.Messages({"Accounts.RootNode.displayName=Accounts"}) public class AccountsRootNode extends DisplayableItemNode { - AccountsRootNode() { + public AccountsRootNode() { super(Children.create(new AccountTypeFactory(), true), Lookups.singleton(Accounts.this)); super.setName(Accounts.NAME); super.setDisplayName(Bundle.Accounts_RootNode_displayName()); @@ -403,7 +336,8 @@ public class Accounts extends Observable implements AutopsyVisitableItem { * for the event to have a null oldValue. */ ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); - if (null != eventData && ACCOUNT_TYPE.equals(eventData.getBlackboardArtifactType())) { + if (null != eventData + && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { Accounts.this.update(); } } catch (IllegalStateException notUsed) { @@ -443,7 +377,8 @@ public class Accounts extends Observable implements AutopsyVisitableItem { + " WHERE blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()); ResultSet resultSet = executeQuery.getResultSet()) { while (resultSet.next()) { - list.add(resultSet.getString("account_type")); + String accountType = resultSet.getString("account_type"); + list.add(accountType); } } catch (TskCoreException | SQLException ex) { Exceptions.printStackTrace(ex); @@ -454,15 +389,18 @@ public class Accounts extends Observable implements AutopsyVisitableItem { @Override protected Node createNodeForKey(String key) { - if (key.equals( /** - * This is a secret handshake with - * org.sleuthkit.autopsy.keywordsearch.TermComponentQuery - */ - Account.Type.CREDIT_CARD.name())) { - return new CreditCardNumberAccountTypeNode(key); - } else { + try { + Account.Type accountType = Account.Type.valueOf(key); + switch (accountType) { + case CREDIT_CARD: + return new CreditCardNumberAccountTypeNode(); + default: + return new DefaultAccountTypeNode(key); + } + } catch (IllegalArgumentException ex) { + LOGGER.log(Level.WARNING, "Unknown account type: " + key); //Flesh out what happens with other account types here. - return new AbstractNode(Children.LEAF); + return new DefaultAccountTypeNode(key); } } @@ -484,6 +422,67 @@ public class Accounts extends Observable implements AutopsyVisitableItem { } } + private class DefaultAccountFactory extends ChildFactory.Detachable { + + private final String accountTypeName; + + public DefaultAccountFactory(String accountTypeName) { + this.accountTypeName = accountTypeName; + } + + @Override + protected boolean createKeys(List list) { + + String query + = "SELECT blackboard_artifacts.artifact_id " //NON-NLS + + " FROM blackboard_artifacts " //NON-NLS + + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + + " AND blackboard_attributes.value_text = '" + accountTypeName + "'" //NON-NLS + + getRejectedArtifactFilterClause(); //NON-NLS + try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); + ResultSet rs = results.getResultSet();) { + while (rs.next()) { + list.add(rs.getLong("artifact_id")); //NON-NLS + } + } catch (TskCoreException | SQLException ex) { + LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS + return false; + } + return true; + } + + @Override + protected Node createNodeForKey(Long t) { + try { + return new BlackboardArtifactNode(skCase.getBlackboardArtifact(t)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error get black board artifact with id " + t, ex); + return null; + } + } + } + + public class DefaultAccountTypeNode extends DisplayableItemNode { + + private DefaultAccountTypeNode(String accountTypeName) { + super(Children.create(new DefaultAccountFactory(accountTypeName), true)); + super.setName(accountTypeName); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS + } + + @Override + public boolean isLeafTypeNode() { + return true; + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + } + /** * Node for an account type. * @@ -491,9 +490,9 @@ public class Accounts extends Observable implements AutopsyVisitableItem { */ public class CreditCardNumberAccountTypeNode extends DisplayableItemNode { - private CreditCardNumberAccountTypeNode(String accountTypeName) { + private CreditCardNumberAccountTypeNode() { super(Children.create(new ViewModeFactory(), true)); - super.setName(accountTypeName); + super.setName(Account.Type.CREDIT_CARD.getDisplayName()); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS } @@ -874,10 +873,10 @@ public class Accounts extends Observable implements AutopsyVisitableItem { } private String getBinRangeString() { - if (bin.getIINStart() == bin.getIINEnd()) { - return Integer.toString(bin.getIINStart()); + if (bin.getBINStart() == bin.getBINEnd()) { + return Integer.toString(bin.getBINStart()); } else { - return bin.getIINStart() + "-" + StringUtils.difference(bin.getIINStart() + "", bin.getIINEnd() + ""); + return bin.getBINStart() + "-" + StringUtils.difference(bin.getBINStart() + "", bin.getBINEnd() + ""); } } @@ -981,16 +980,16 @@ public class Accounts extends Observable implements AutopsyVisitableItem { final Integer bin = Integer.valueOf(resultSet.getString("BIN")); long count = resultSet.getLong("count"); - IINRange iinRange = (IINRange) BINMap.getIINInfo(bin); + BINRange binRange = (BINRange) CreditCards.getBINInfo(bin); BinResult previousResult = ranges.get(bin); if (previousResult != null) { - ranges.remove(Range.closed(previousResult.getIINStart(), previousResult.getIINEnd())); + ranges.remove(Range.closed(previousResult.getBINStart(), previousResult.getBINEnd())); count += previousResult.getCount(); } - if (iinRange != null) { - ranges.put(Range.closed(iinRange.getIINstart(), iinRange.getIINend()), new BinResult(count, iinRange)); + if (binRange != null) { + ranges.put(Range.closed(binRange.getBINstart(), binRange.getBINend()), new BinResult(count, binRange)); } else { ranges.put(Range.closed(bin, bin), new BinResult(count, bin, bin)); } @@ -1014,37 +1013,37 @@ public class Accounts extends Observable implements AutopsyVisitableItem { * accounts found with the BIN. */ @Immutable - static private class BinResult implements IINInfo { + static private class BinResult implements CreditCards.BankIdentificationNumber { /** * The number of accounts with this BIN */ private final long count; - private final IINRange iinRange; - private final int iinEnd; - private final int iinStart; + private final BINRange binRange; + private final int binEnd; + private final int binStart; - private BinResult(long count, @Nonnull IINRange iinRange) { + private BinResult(long count, @Nonnull BINRange binRange) { this.count = count; - this.iinRange = iinRange; - iinStart = iinRange.getIINstart(); - iinEnd = iinRange.getIINend(); + this.binRange = binRange; + binStart = binRange.getBINstart(); + binEnd = binRange.getBINend(); } private BinResult(long count, int start, int end) { this.count = count; - this.iinRange = null; - iinStart = start; - iinEnd = end; + this.binRange = null; + binStart = start; + binEnd = end; } - int getIINStart() { - return iinStart; + int getBINStart() { + return binStart; } - int getIINEnd() { - return iinEnd; + int getBINEnd() { + return binEnd; } public long getCount() { @@ -1052,52 +1051,52 @@ public class Accounts extends Observable implements AutopsyVisitableItem { } boolean hasDetails() { - return iinRange != null; + return binRange != null; } @Override public Optional getNumberLength() { - return iinRange.getNumberLength(); + return binRange.getNumberLength(); } @Override public Optional getBankCity() { - return iinRange.getBankCity(); + return binRange.getBankCity(); } @Override public Optional getBankName() { - return iinRange.getBankName(); + return binRange.getBankName(); } @Override public Optional getBankPhoneNumber() { - return iinRange.getBankPhoneNumber(); + return binRange.getBankPhoneNumber(); } @Override public Optional getBankURL() { - return iinRange.getBankURL(); + return binRange.getBankURL(); } @Override public Optional getBrand() { - return iinRange.getBrand(); + return binRange.getBrand(); } @Override public Optional getCardType() { - return iinRange.getCardType(); + return binRange.getCardType(); } @Override public Optional getCountry() { - return iinRange.getCountry(); + return binRange.getCountry(); } @Override public Optional getScheme() { - return iinRange.getScheme(); + return binRange.getScheme(); } } @@ -1121,7 +1120,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER.getTypeID() //NON-NLS - + " AND blackboard_attributes.value_text >= \"" + bin.getIINStart() + "\" AND blackboard_attributes.value_text < \"" + (bin.getIINEnd() + 1) + "\"" //NON-NLS + + " AND blackboard_attributes.value_text >= \"" + bin.getBINStart() + "\" AND blackboard_attributes.value_text < \"" + (bin.getBINEnd() + 1) + "\"" //NON-NLS + getRejectedArtifactFilterClause() + " ORDER BY blackboard_attributes.value_text"; //NON-NLS try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); @@ -1187,7 +1186,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem { } } - final class ToggleShowRejected extends AbstractAction { + private final class ToggleShowRejected extends AbstractAction { @NbBundle.Messages("ToggleShowRejected.name=Show Rejcted Results") ToggleShowRejected() { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/AutopsyItemVisitor.java similarity index 85% rename from Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java rename to Core/src/org/sleuthkit/autopsy/datamodel/_private/AutopsyItemVisitor.java index ceb390e88e..bf6e2246ea 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/AutopsyItemVisitor.java @@ -16,14 +16,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datamodel; +package org.sleuthkit.autopsy.datamodel._private; + +import org.sleuthkit.autopsy.datamodel.DataSources; +import org.sleuthkit.autopsy.datamodel.DeletedContent; +import org.sleuthkit.autopsy.datamodel.EmailExtracted; +import org.sleuthkit.autopsy.datamodel.ExtractedContent; +import org.sleuthkit.autopsy.datamodel.FileSize; +import org.sleuthkit.autopsy.datamodel.HashsetHits; +import org.sleuthkit.autopsy.datamodel.InterestingHits; +import org.sleuthkit.autopsy.datamodel.KeywordHits; +import org.sleuthkit.autopsy.datamodel.Reports; +import org.sleuthkit.autopsy.datamodel.Results; +import org.sleuthkit.autopsy.datamodel.Tags; +import org.sleuthkit.autopsy.datamodel.Views; /** * This visitor goes over the AutopsyVisitableItems, which are currently the * nodes in the tree that are structural and not nodes that are from * Sleuthkit-based data model objects. */ -interface AutopsyItemVisitor { +public interface AutopsyItemVisitor { T visit(DataSources i); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyVisitableItem.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/AutopsyVisitableItem.java similarity index 91% rename from Core/src/org/sleuthkit/autopsy/datamodel/AutopsyVisitableItem.java rename to Core/src/org/sleuthkit/autopsy/datamodel/_private/AutopsyVisitableItem.java index a8efccb494..3eb949ff01 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyVisitableItem.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/AutopsyVisitableItem.java @@ -16,13 +16,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datamodel; +package org.sleuthkit.autopsy.datamodel._private; +; /** * AutopsyVisitableItems are the nodes in the directory tree that are for * structure only. They are not associated with content objects. */ -interface AutopsyVisitableItem { +public interface AutopsyVisitableItem { /** * visitor pattern support diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Bundle.properties new file mode 100644 index 0000000000..dc778857c5 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Bundle.properties @@ -0,0 +1,12 @@ +FileTypeExtensionFilters.tskImgFilter.text=Images +FileTypeExtensionFilters.tskVideoFilter.text=Videos +FileTypeExtensionFilters.tskAudioFilter.text=Audio +FileTypeExtensionFilters.tskArchiveFilter.text=Archives +FileTypeExtensionFilters.tskDocumentFilter.text=Documents +FileTypeExtensionFilters.tskExecFilter.text=Executable +FileTypeExtensionFilters.autDocHtmlFilter.text=HTML +FileTypeExtensionFilters.autDocOfficeFilter.text=Office +FileTypeExtensionFilters.autoDocPdfFilter.text=PDF +FileTypeExtensionFilters.autDocTxtFilter.text=Plain Text +FileTypeExtensionFilters.autDocRtfFilter.text=Rich Text + diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeExtensionFilters.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/FileTypeExtensionFilters.java similarity index 90% rename from Core/src/org/sleuthkit/autopsy/datamodel/FileTypeExtensionFilters.java rename to Core/src/org/sleuthkit/autopsy/datamodel/_private/FileTypeExtensionFilters.java index 1e2dd473dd..09a650161d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeExtensionFilters.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/FileTypeExtensionFilters.java @@ -16,20 +16,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datamodel; +package org.sleuthkit.autopsy.datamodel._private; import java.util.Arrays; import java.util.List; - import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.datamodel.FileTypeExtensions; import org.sleuthkit.datamodel.SleuthkitCase; /** * Filters database results by file extension. */ -class FileTypeExtensionFilters implements AutopsyVisitableItem { +public class FileTypeExtensionFilters implements AutopsyVisitableItem { - private SleuthkitCase skCase; + private final SleuthkitCase skCase; // root node filters public enum RootFilter implements AutopsyVisitableItem, SearchFilterInterface { @@ -53,10 +53,10 @@ class FileTypeExtensionFilters implements AutopsyVisitableItem { NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.tskExecFilter.text"), Arrays.asList(".exe", ".dll", ".bat", ".cmd", ".com")); //NON-NLS - private int id; - private String name; - private String displayName; - private List filter; + private final int id; + private final String name; + private final String displayName; + private final List filter; private RootFilter(int id, String name, String displayName, List filter) { this.id = id; @@ -110,10 +110,10 @@ class FileTypeExtensionFilters implements AutopsyVisitableItem { NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.autDocRtfFilter.text"), Arrays.asList(".rtf")); //NON-NLS - private int id; - private String name; - private String displayName; - private List filter; + private final int id; + private final String name; + private final String displayName; + private final List filter; private DocumentFilter(int id, String name, String displayName, List filter) { this.id = id; @@ -157,10 +157,10 @@ class FileTypeExtensionFilters implements AutopsyVisitableItem { ExecutableFilter_CMD(3, "ExecutableFilter_CMD", ".cmd", Arrays.asList(".cmd")), //NON-NLS ExecutableFilter_COM(4, "ExecutableFilter_COM", ".com", Arrays.asList(".com")); //NON-NLS - private int id; - private String name; - private String displayName; - private List filter; + private final int id; + private final String name; + private final String displayName; + private final List filter; private ExecutableFilter(int id, String name, String displayName, List filter) { this.id = id; @@ -208,7 +208,7 @@ class FileTypeExtensionFilters implements AutopsyVisitableItem { return this.skCase; } - interface SearchFilterInterface { + public interface SearchFilterInterface { public String getName(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFiles.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/RecentFiles.java similarity index 96% rename from Core/src/org/sleuthkit/autopsy/datamodel/RecentFiles.java rename to Core/src/org/sleuthkit/autopsy/datamodel/_private/RecentFiles.java index cc8b8424cb..d3163d579d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFiles.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/RecentFiles.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datamodel; +package org.sleuthkit.autopsy.datamodel._private; import org.openide.util.NbBundle; import org.sleuthkit.datamodel.SleuthkitCase; @@ -25,7 +25,7 @@ import org.sleuthkit.datamodel.SleuthkitCase; * Recent files node support NOTE: As of june '15 we do not display this in the * tree. It can be added back when we have filtering in the results area. */ -class RecentFiles implements AutopsyVisitableItem { +public class RecentFiles implements AutopsyVisitableItem { SleuthkitCase skCase; diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 33d15b14f9..5d7981b677 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; -import org.sleuthkit.autopsy.datamodel.Accounts; +import org.sleuthkit.autopsy.datamodel._private.Accounts; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode; import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode; diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 987c2bc827..6db8d46a6e 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -57,7 +57,7 @@ import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.datamodel.Accounts; +import org.sleuthkit.autopsy.datamodel._private.Accounts; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.DataSources; import org.sleuthkit.autopsy.datamodel.DataSourcesNode; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java index 56ef0725d1..1de41b5eab 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java @@ -140,7 +140,7 @@ public class ExtractedContentViewer implements DataContentViewer { */ for (BlackboardArtifact artifact : artifacts) { try { - BlackboardAttribute solrIDAttr = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SOLR_DOCUMENT_ID)); + BlackboardAttribute solrIDAttr = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID)); if (solrIDAttr != null) { String valueString = solrIDAttr.getValueString(); if (StringUtils.isNotBlank(valueString)) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java index 0f7858448f..7888010d87 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java @@ -34,8 +34,7 @@ import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.response.TermsResponse.Term; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Version; -import org.sleuthkit.autopsy.datamodel.Accounts; -import org.sleuthkit.autopsy.datamodel.BINMap; +import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -214,26 +213,26 @@ final class TermComponentQuery implements KeywordSearchQuery { } String ccn = newArtifact.getAttribute(CREDIT_CARD_NUMBER).getValueString(); - final int iin = Integer.parseInt(ccn.substring(0, 8)); + final int bin = Integer.parseInt(ccn.substring(0, 8)); - Accounts.IINInfo iinInfo = BINMap.getIINInfo(iin); + CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin); - if (iinInfo != null) { - iinInfo.getScheme().ifPresent(scheme + if (binInfo != null) { + binInfo.getScheme().ifPresent(scheme -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_SCHEME, scheme)); - iinInfo.getCardType().ifPresent(cardType + binInfo.getCardType().ifPresent(cardType -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_PAYMENT_CARD_TYPE, cardType)); - iinInfo.getBrand().ifPresent(brand + binInfo.getBrand().ifPresent(brand -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_BRAND, brand)); - iinInfo.getBankName().ifPresent(bankName + binInfo.getBankName().ifPresent(bankName -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_BANK_NAME, bankName)); - iinInfo.getBankPhoneNumber().ifPresent(phoneNumber + binInfo.getBankPhoneNumber().ifPresent(phoneNumber -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, phoneNumber)); - iinInfo.getBankURL().ifPresent(url + binInfo.getBankURL().ifPresent(url -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_URL, url)); - iinInfo.getCountry().ifPresent(country + binInfo.getCountry().ifPresent(country -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_COUNTRY, country)); - iinInfo.getBankCity().ifPresent(city + binInfo.getBankCity().ifPresent(city -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_CITY, city)); } } else { From 06230edeeaf67b169b6b3f1a6d8e4861d1a7ac14 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 26 Sep 2016 14:39:09 +0200 Subject: [PATCH 29/54] extract BINRange from Accounts.java --- .../autopsy/datamodel/CreditCards.java | 6 +- .../autopsy/datamodel/_private/Accounts.java | 124 +---------------- .../autopsy/datamodel/_private/BINRange.java | 128 ++++++++++++++++++ 3 files changed, 133 insertions(+), 125 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/_private/BINRange.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/CreditCards.java b/Core/src/org/sleuthkit/autopsy/datamodel/CreditCards.java index 17593d8547..aa7b13e66b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/CreditCards.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/CreditCards.java @@ -14,7 +14,7 @@ import org.apache.commons.csv.CSVParser; import org.apache.commons.csv.CSVRecord; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.datamodel._private.Accounts; +import org.sleuthkit.autopsy.datamodel._private.BINRange; public class CreditCards { @@ -96,7 +96,7 @@ public class CreditCards { * the BIN, ie, bank name, phone, url, visa/amex/mastercard/..., */ @GuardedBy("CreditCards.class") - private final static RangeMap binRanges = TreeRangeMap.create(); + private final static RangeMap binRanges = TreeRangeMap.create(); /** * Flag for if we have loaded the BINs from the file already. @@ -131,7 +131,7 @@ public class CreditCards { final String numberLength = record.get("number_length"); //NON-NLS try { - Accounts.BINRange binRange = new Accounts.BINRange(Integer.parseInt(start), + BINRange binRange = new BINRange(Integer.parseInt(start), Integer.parseInt(end), StringUtils.isBlank(numberLength) ? null : Integer.valueOf(numberLength), record.get("scheme"), //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java index 9b87639c35..700c9933d8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java @@ -133,128 +133,6 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { return new ToggleShowRejected(); } - /** - * Details of a range of Bank Identification Number(s) (BIN) used * by a - * bank. - */ - @Immutable - public static class BINRange implements CreditCards.BankIdentificationNumber { - - private final int BINStart; //start of BIN range, 8 digits - private final int BINEnd; // end (incluse ) of BIN rnage, 8 digits - - private final Integer numberLength; // the length of accounts numbers with this BIN, currently unused - - /** - * AMEX, VISA, MASTERCARD, DINERS, DISCOVER, UNIONPAY - */ - private final String scheme; - private final String brand; - - /** - * DEBIT, CREDIT - */ - private final String cardType; - private final String country; - private final String bankName; - private final String bankCity; - private final String bankURL; - private final String bankPhoneNumber; - - /** - * Constructor - * - * @param BIN_start the first BIN in the range, must be 8 digits - * @param BIN_end the last(inclusive) BIN in the range, must be 8 - * digits - * @param number_length the length of account numbers in this BIN range - * @param scheme amex/visa/mastercard/etc - * @param brand the brand of this BIN range - * @param type credit vs debit - * @param country the country of the issuer - * @param bank_name the name of the issuer - * @param bank_url the url of the issuer - * @param bank_phone the phone number of the issuer - * @param bank_city the city of the issuer - */ - public BINRange(int BIN_start, int BIN_end, Integer number_length, String scheme, String brand, String type, String country, String bank_name, String bank_url, String bank_phone, String bank_city) { - this.BINStart = BIN_start; - this.BINEnd = BIN_end; - - this.numberLength = number_length; - this.scheme = StringUtils.defaultIfBlank(scheme, null); - this.brand = StringUtils.defaultIfBlank(brand, null); - this.cardType = StringUtils.defaultIfBlank(type, null); - this.country = StringUtils.defaultIfBlank(country, null); - this.bankName = StringUtils.defaultIfBlank(bank_name, null); - this.bankURL = StringUtils.defaultIfBlank(bank_url, null); - this.bankPhoneNumber = StringUtils.defaultIfBlank(bank_phone, null); - this.bankCity = StringUtils.defaultIfBlank(bank_city, null); - } - - /** - * Get the first BIN in this range - * - * @return the first BIN in this range. - */ - public int getBINstart() { - return BINStart; - } - - /** - * Get the last (inclusive) BIN in this range. - * - * @return the last (inclusive) BIN in this range. - */ - public int getBINend() { - return BINEnd; - } - - @Override - public Optional getNumberLength() { - return Optional.ofNullable(numberLength); - } - - @Override - public Optional getScheme() { - return Optional.ofNullable(scheme); - } - - @Override - public Optional getBrand() { - return Optional.ofNullable(brand); - } - - @Override - public Optional getCardType() { - return Optional.ofNullable(cardType); - } - - @Override - public Optional getCountry() { - return Optional.ofNullable(country); - } - - @Override - public Optional getBankName() { - return Optional.ofNullable(bankName); - } - - @Override - public Optional getBankURL() { - return Optional.ofNullable(bankURL); - } - - @Override - public Optional getBankPhoneNumber() { - return Optional.ofNullable(bankPhoneNumber); - } - - @Override - public Optional getBankCity() { - return Optional.ofNullable(bankCity); - } - } /** * Base class for factories that are also observers. @@ -1244,4 +1122,6 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } } + + } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/BINRange.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/BINRange.java new file mode 100644 index 0000000000..4c82cdda95 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/BINRange.java @@ -0,0 +1,128 @@ +package org.sleuthkit.autopsy.datamodel._private; + +import java.util.Optional; +import javax.annotation.concurrent.Immutable; +import org.apache.commons.lang3.StringUtils; +import org.sleuthkit.autopsy.datamodel.CreditCards; + +/** + * Details of a range of Bank Identification Number(s) (BIN) used by a bank. + */ +@Immutable +public class BINRange implements CreditCards.BankIdentificationNumber { + + private final int BINStart; //start of BIN range, 8 digits + private final int BINEnd; // end (incluse ) of BIN rnage, 8 digits + + private final Integer numberLength; // the length of accounts numbers with this BIN, currently unused + + /** + * AMEX, VISA, MASTERCARD, DINERS, DISCOVER, UNIONPAY + */ + private final String scheme; + private final String brand; + + /** + * DEBIT, CREDIT + */ + private final String cardType; + private final String country; + private final String bankName; + private final String bankCity; + private final String bankURL; + private final String bankPhoneNumber; + + /** + * Constructor + * + * @param BIN_start the first BIN in the range, must be 8 digits + * @param BIN_end the last(inclusive) BIN in the range, must be 8 + * digits + * @param number_length the length of account numbers in this BIN range + * @param scheme amex/visa/mastercard/etc + * @param brand the brand of this BIN range + * @param type credit vs debit + * @param country the country of the issuer + * @param bank_name the name of the issuer + * @param bank_url the url of the issuer + * @param bank_phone the phone number of the issuer + * @param bank_city the city of the issuer + */ + public BINRange(int BIN_start, int BIN_end, Integer number_length, String scheme, String brand, String type, String country, String bank_name, String bank_url, String bank_phone, String bank_city) { + this.BINStart = BIN_start; + this.BINEnd = BIN_end; + + this.numberLength = number_length; + this.scheme = StringUtils.defaultIfBlank(scheme, null); + this.brand = StringUtils.defaultIfBlank(brand, null); + this.cardType = StringUtils.defaultIfBlank(type, null); + this.country = StringUtils.defaultIfBlank(country, null); + this.bankName = StringUtils.defaultIfBlank(bank_name, null); + this.bankURL = StringUtils.defaultIfBlank(bank_url, null); + this.bankPhoneNumber = StringUtils.defaultIfBlank(bank_phone, null); + this.bankCity = StringUtils.defaultIfBlank(bank_city, null); + } + + /** + * Get the first BIN in this range + * + * @return the first BIN in this range. + */ + public int getBINstart() { + return BINStart; + } + + /** + * Get the last (inclusive) BIN in this range. + * + * @return the last (inclusive) BIN in this range. + */ + public int getBINend() { + return BINEnd; + } + + @Override + public Optional getNumberLength() { + return Optional.ofNullable(numberLength); + } + + @Override + public Optional getScheme() { + return Optional.ofNullable(scheme); + } + + @Override + public Optional getBrand() { + return Optional.ofNullable(brand); + } + + @Override + public Optional getCardType() { + return Optional.ofNullable(cardType); + } + + @Override + public Optional getCountry() { + return Optional.ofNullable(country); + } + + @Override + public Optional getBankName() { + return Optional.ofNullable(bankName); + } + + @Override + public Optional getBankURL() { + return Optional.ofNullable(bankURL); + } + + @Override + public Optional getBankPhoneNumber() { + return Optional.ofNullable(bankPhoneNumber); + } + + @Override + public Optional getBankCity() { + return Optional.ofNullable(bankCity); + } +} From ce74dc91228d3674631507dbbaf534b4c1b29c97 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 26 Sep 2016 15:18:25 +0200 Subject: [PATCH 30/54] make factories inner classes of the nodes they provide children for --- .../autopsy/datamodel/_private/Accounts.java | 745 +++++++++--------- 1 file changed, 372 insertions(+), 373 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java index 700c9933d8..70adc98f16 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java @@ -133,7 +133,6 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { return new ToggleShowRejected(); } - /** * Base class for factories that are also observers. * @@ -165,10 +164,128 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { @NbBundle.Messages({"Accounts.RootNode.displayName=Accounts"}) public class AccountsRootNode extends DisplayableItemNode { + /** + * Creates child nodes for each account type (currently hard coded to + * make one for Credit Cards) + */ + private class AccountTypeFactory extends ObservingChildFactory { + + /* + * The pcl is in this class because it has the easiest mechanisms to + * add and remove itself during its life cycles. + */ + private final PropertyChangeListener pcl = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + String eventType = evt.getPropertyName(); + if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { + /** + * Checking for a current case is a stop gap measure + * until a different way of handling the closing of + * cases is worked out. Currently, remote events may be + * received for a case that is already closed. + */ + try { + Case.getCurrentCase(); + /** + * Even with the check above, it is still possible + * that the case will be closed in a different + * thread before this code executes. If that + * happens, it is possible for the event to have a + * null oldValue. + */ + ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); + if (null != eventData + && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + Accounts.this.update(); + } + } catch (IllegalStateException notUsed) { + // Case is closed, do nothing. + } + } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) + || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { + /** + * Checking for a current case is a stop gap measure + * until a different way of handling the closing of + * cases is worked out. Currently, remote events may be + * received for a case that is already closed. + */ + try { + Case.getCurrentCase(); + Accounts.this.update(); + } catch (IllegalStateException notUsed) { + // Case is closed, do nothing. + } + } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { + // case was closed. Remove listeners so that we don't get called with a stale case handle + if (evt.getNewValue() == null) { + removeNotify(); + skCase = null; + } + } + } + }; + + @Override + + protected boolean createKeys(List list) { + + try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery( + "SELECT DISTINCT blackboard_attributes.value_text as account_type " + + " FROM blackboard_attributes " + + " WHERE blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()); + ResultSet resultSet = executeQuery.getResultSet()) { + while (resultSet.next()) { + String accountType = resultSet.getString("account_type"); + list.add(accountType); + } + } catch (TskCoreException | SQLException ex) { + Exceptions.printStackTrace(ex); + return false; + } + return true; + } + + @Override + protected Node createNodeForKey(String key) { + try { + Account.Type accountType = Account.Type.valueOf(key); + switch (accountType) { + case CREDIT_CARD: + return new CreditCardNumberAccountTypeNode(); + default: + return new DefaultAccountTypeNode(key); + } + } catch (IllegalArgumentException ex) { + LOGGER.log(Level.WARNING, "Unknown account type: " + key); + //Flesh out what happens with other account types here. + return new DefaultAccountTypeNode(key); + } + } + + @Override + protected void removeNotify() { + IngestManager.getInstance().removeIngestJobEventListener(pcl); + IngestManager.getInstance().removeIngestModuleEventListener(pcl); + Case.removePropertyChangeListener(pcl); + super.removeNotify(); + } + + @Override + protected void addNotify() { + IngestManager.getInstance().addIngestJobEventListener(pcl); + IngestManager.getInstance().addIngestModuleEventListener(pcl); + Case.addPropertyChangeListener(pcl); + super.addNotify(); + Accounts.this.update(); + } + } + public AccountsRootNode() { - super(Children.create(new AccountTypeFactory(), true), Lookups.singleton(Accounts.this)); - super.setName(Accounts.NAME); - super.setDisplayName(Bundle.Accounts_RootNode_displayName()); + super(Children.LEAF, Lookups.singleton(Accounts.this)); + setChildren(Children.create(new AccountTypeFactory(), true)); + setName(Accounts.NAME); + setDisplayName(Bundle.Accounts_RootNode_displayName()); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/accounts.png"); //NON-NLS } @@ -184,169 +301,54 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } - /** - * Creates child nodes for each account type (currently hard coded to make - * one for Credit Cards) - */ - private class AccountTypeFactory extends ObservingChildFactory { - - /* - * The pcl is in this class because it has the easiest mechanisms to add - * and remove itself during its life cycles. - */ - private final PropertyChangeListener pcl = new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - String eventType = evt.getPropertyName(); - if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { - /** - * Checking for a current case is a stop gap measure until a - * different way of handling the closing of cases is worked - * out. Currently, remote events may be received for a case - * that is already closed. - */ - try { - Case.getCurrentCase(); - /** - * Even with the check above, it is still possible that - * the case will be closed in a different thread before - * this code executes. If that happens, it is possible - * for the event to have a null oldValue. - */ - ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); - if (null != eventData - && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { - Accounts.this.update(); - } - } catch (IllegalStateException notUsed) { - // Case is closed, do nothing. - } - } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) - || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { - /** - * Checking for a current case is a stop gap measure until a - * different way of handling the closing of cases is worked - * out. Currently, remote events may be received for a case - * that is already closed. - */ - try { - Case.getCurrentCase(); - Accounts.this.update(); - } catch (IllegalStateException notUsed) { - // Case is closed, do nothing. - } - } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { - // case was closed. Remove listeners so that we don't get called with a stale case handle - if (evt.getNewValue() == null) { - removeNotify(); - skCase = null; - } - } - } - }; - - @Override - - protected boolean createKeys(List list) { - - try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery( - "SELECT DISTINCT blackboard_attributes.value_text as account_type " - + " FROM blackboard_attributes " - + " WHERE blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()); - ResultSet resultSet = executeQuery.getResultSet()) { - while (resultSet.next()) { - String accountType = resultSet.getString("account_type"); - list.add(accountType); - } - } catch (TskCoreException | SQLException ex) { - Exceptions.printStackTrace(ex); - return false; - } - return true; - } - - @Override - protected Node createNodeForKey(String key) { - try { - Account.Type accountType = Account.Type.valueOf(key); - switch (accountType) { - case CREDIT_CARD: - return new CreditCardNumberAccountTypeNode(); - default: - return new DefaultAccountTypeNode(key); - } - } catch (IllegalArgumentException ex) { - LOGGER.log(Level.WARNING, "Unknown account type: " + key); - //Flesh out what happens with other account types here. - return new DefaultAccountTypeNode(key); - } - } - - @Override - protected void removeNotify() { - IngestManager.getInstance().removeIngestJobEventListener(pcl); - IngestManager.getInstance().removeIngestModuleEventListener(pcl); - Case.removePropertyChangeListener(pcl); - super.removeNotify(); - } - - @Override - protected void addNotify() { - IngestManager.getInstance().addIngestJobEventListener(pcl); - IngestManager.getInstance().addIngestModuleEventListener(pcl); - Case.addPropertyChangeListener(pcl); - super.addNotify(); - Accounts.this.update(); - } - } - - private class DefaultAccountFactory extends ChildFactory.Detachable { - - private final String accountTypeName; - - public DefaultAccountFactory(String accountTypeName) { - this.accountTypeName = accountTypeName; - } - - @Override - protected boolean createKeys(List list) { - - String query - = "SELECT blackboard_artifacts.artifact_id " //NON-NLS - + " FROM blackboard_artifacts " //NON-NLS - + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS - + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS - + " AND blackboard_attributes.value_text = '" + accountTypeName + "'" //NON-NLS - + getRejectedArtifactFilterClause(); //NON-NLS - try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); - ResultSet rs = results.getResultSet();) { - while (rs.next()) { - list.add(rs.getLong("artifact_id")); //NON-NLS - } - } catch (TskCoreException | SQLException ex) { - LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS - return false; - } - return true; - } - - @Override - protected Node createNodeForKey(Long t) { - try { - return new BlackboardArtifactNode(skCase.getBlackboardArtifact(t)); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error get black board artifact with id " + t, ex); - return null; - } - } - } - public class DefaultAccountTypeNode extends DisplayableItemNode { + private class DefaultAccountFactory extends ChildFactory.Detachable { + + private final String accountTypeName; + + public DefaultAccountFactory(String accountTypeName) { + this.accountTypeName = accountTypeName; + } + + @Override + protected boolean createKeys(List list) { + + String query + = "SELECT blackboard_artifacts.artifact_id " //NON-NLS + + " FROM blackboard_artifacts " //NON-NLS + + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + + " AND blackboard_attributes.value_text = '" + accountTypeName + "'" //NON-NLS + + getRejectedArtifactFilterClause(); //NON-NLS + try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); + ResultSet rs = results.getResultSet();) { + while (rs.next()) { + list.add(rs.getLong("artifact_id")); //NON-NLS + } + } catch (TskCoreException | SQLException ex) { + LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS + return false; + } + return true; + } + + @Override + protected Node createNodeForKey(Long t) { + try { + return new BlackboardArtifactNode(skCase.getBlackboardArtifact(t)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error get black board artifact with id " + t, ex); + return null; + } + } + } + private DefaultAccountTypeNode(String accountTypeName) { - super(Children.create(new DefaultAccountFactory(accountTypeName), true)); - super.setName(accountTypeName); + super(Children.LEAF); + setChildren(Children.create(new DefaultAccountFactory(accountTypeName), true)); + setName(accountTypeName); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS } @@ -361,30 +363,6 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } - /** - * Node for an account type. - * - * NOTE: currently hard coded to work for Credit Card only - */ - public class CreditCardNumberAccountTypeNode extends DisplayableItemNode { - - private CreditCardNumberAccountTypeNode() { - super(Children.create(new ViewModeFactory(), true)); - super.setName(Account.Type.CREDIT_CARD.getDisplayName()); - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS - } - - @Override - public boolean isLeafTypeNode() { - return false; - } - - @Override - public T accept(DisplayableItemNodeVisitor v) { - return v.visit(this); - } - } - /** * Enum for the children under the credit card AccountTypeNode. */ @@ -394,27 +372,52 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } /** - * ChildFactory that makes nodes for the different account organizations (by - * file, by BIN) + * Node for an account type. + * + * NOTE: currently hard coded to work for Credit Card only */ - private class ViewModeFactory extends ObservingChildFactory { + public class CreditCardNumberAccountTypeNode extends DisplayableItemNode { - @Override - protected boolean createKeys(List list) { - list.addAll(Arrays.asList(CreditCardViewMode.values())); - return true; + /** + * ChildFactory that makes nodes for the different account organizations + * (by file, by BIN) + */ + private class ViewModeFactory extends ObservingChildFactory { + + @Override + protected boolean createKeys(List list) { + list.addAll(Arrays.asList(CreditCardViewMode.values())); + return true; + } + + @Override + protected Node createNodeForKey(CreditCardViewMode key) { + switch (key) { + case BY_BIN: + return new ByBINNode(); + case BY_FILE: + return new ByFileNode(); + default: + return null; + } + } + } + + private CreditCardNumberAccountTypeNode() { + super(Children.LEAF); + setChildren(Children.create(new ViewModeFactory(), true)); + setName(Account.Type.CREDIT_CARD.getDisplayName()); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS } @Override - protected Node createNodeForKey(CreditCardViewMode key) { - switch (key) { - case BY_BIN: - return new ByBINNode(); - case BY_FILE: - return new ByFileNode(); - default: - return null; - } + public boolean isLeafTypeNode() { + return false; + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); } } @@ -424,6 +427,68 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { */ public class ByFileNode extends DisplayableItemNode implements Observer { + /** + * Factory for the children of the ByFiles Node. + */ + private class FileWithCCNFactory extends ObservingChildFactory { + + @Override + protected boolean createKeys(List list) { + String query + = "SELECT blackboard_artifacts.obj_id," //NON-NLS + + " solr_attribute.value_text AS solr_document_id, " //NON-NLS + + " GROUP_CONCAT(blackboard_artifacts.artifact_id) AS artifact_IDs, " //NON-NLS + + " COUNT( blackboard_artifacts.artifact_id) AS hits, " //NON-NLS + + " GROUP_CONCAT(blackboard_artifacts.review_status_id) AS review_status_ids " + + " FROM blackboard_artifacts " //NON-NLS + + " LEFT JOIN blackboard_attributes as solr_attribute ON blackboard_artifacts.artifact_id = solr_attribute.artifact_id " //NON-NLS + + " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS + + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS + + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + + " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.name() + "'" //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + getRejectedArtifactFilterClause() + + " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS + + " ORDER BY hits DESC "; //NON-NLS + try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); + ResultSet rs = results.getResultSet();) { + while (rs.next()) { + list.add(new FileWithCCN( + rs.getLong("obj_id"), //NON-NLS + rs.getString("solr_document_id"), //NON-NLS + unGroupConcat(rs.getString("artifact_IDs"), Long::valueOf), //NON-NLS + rs.getLong("hits"), //NON-NLS + new HashSet<>(unGroupConcat(rs.getString("review_status_ids"), id -> BlackboardArtifact.ReviewStatus.withID(Integer.valueOf(id)))))); //NON-NLS + } + } catch (TskCoreException | SQLException ex) { + LOGGER.log(Level.SEVERE, "Error querying for files with ccn hits.", ex); //NON-NLS + return false; + } + return true; + } + + @Override + protected Node createNodeForKey(FileWithCCN key) { + //add all account artifacts for the file and the file itself to the lookup + try { + List lookupContents = new ArrayList<>(); + for (long artId : key.artifactIDS) { + lookupContents.add(skCase.getBlackboardArtifact(artId)); + } + AbstractFile abstractFileById = skCase.getAbstractFileById(key.getObjID()); + lookupContents.add(abstractFileById); + return new FileWithCCNNode(key, abstractFileById, lookupContents.toArray()); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error getting content for file with ccn hits.", ex); //NON-NLS + return null; + } + } + + @Override + public void update(Observable o, Object arg) { + refresh(true); + } + } private final FileWithCCNFactory fileFactory; private ByFileNode() { @@ -467,6 +532,59 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { */ public class ByBINNode extends DisplayableItemNode implements Observer { + /** + * Factory that generates the children of the ByBin node. + */ + private class BINFactory extends ObservingChildFactory { + + @Override + protected boolean createKeys(List list) { + RangeMap ranges = TreeRangeMap.create(); + + String query + = "SELECT SUBSTR(blackboard_attributes.value_text,1,8) AS BIN, " //NON-NLS + + " COUNT(blackboard_artifacts.artifact_id) AS count " //NON-NLS + + " FROM blackboard_artifacts " //NON-NLS + + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER.getTypeID() //NON-NLS + + getRejectedArtifactFilterClause() + + " GROUP BY BIN " //NON-NLS + + " ORDER BY BIN "; //NON-NLS + try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query)) { + ResultSet resultSet = results.getResultSet(); + while (resultSet.next()) { + final Integer bin = Integer.valueOf(resultSet.getString("BIN")); + long count = resultSet.getLong("count"); + + BINRange binRange = (BINRange) CreditCards.getBINInfo(bin); + BinResult previousResult = ranges.get(bin); + + if (previousResult != null) { + ranges.remove(Range.closed(previousResult.getBINStart(), previousResult.getBINEnd())); + count += previousResult.getCount(); + } + + if (binRange != null) { + ranges.put(Range.closed(binRange.getBINstart(), binRange.getBINend()), new BinResult(count, binRange)); + } else { + ranges.put(Range.closed(bin, bin), new BinResult(count, bin, bin)); + } + } + ranges.asMapOfRanges().values().forEach(list::add); + } catch (TskCoreException | SQLException ex) { + LOGGER.log(Level.SEVERE, "Error querying for BINs.", ex); //NON-NLS + return false; + } + return true; + } + + @Override + protected Node createNodeForKey(BinResult key) { + return new BINNode(key); + } + } + private final BINFactory binFactory; private ByBINNode() { @@ -569,69 +687,6 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { .collect(Collectors.toList()); } - /** - * Factory for the children of the ByFiles Node. - */ - private class FileWithCCNFactory extends ObservingChildFactory { - - @Override - protected boolean createKeys(List list) { - String query - = "SELECT blackboard_artifacts.obj_id," //NON-NLS - + " solr_attribute.value_text AS solr_document_id, " //NON-NLS - + " GROUP_CONCAT(blackboard_artifacts.artifact_id) AS artifact_IDs, " //NON-NLS - + " COUNT( blackboard_artifacts.artifact_id) AS hits, " //NON-NLS - + " GROUP_CONCAT(blackboard_artifacts.review_status_id) AS review_status_ids " - + " FROM blackboard_artifacts " //NON-NLS - + " LEFT JOIN blackboard_attributes as solr_attribute ON blackboard_artifacts.artifact_id = solr_attribute.artifact_id " //NON-NLS - + " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS - + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS - + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS - + " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.name() + "'" //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS - + getRejectedArtifactFilterClause() - + " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS - + " ORDER BY hits DESC "; //NON-NLS - try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); - ResultSet rs = results.getResultSet();) { - while (rs.next()) { - list.add(new FileWithCCN( - rs.getLong("obj_id"), //NON-NLS - rs.getString("solr_document_id"), //NON-NLS - unGroupConcat(rs.getString("artifact_IDs"), Long::valueOf), //NON-NLS - rs.getLong("hits"), //NON-NLS - new HashSet<>(unGroupConcat(rs.getString("review_status_ids"), id -> BlackboardArtifact.ReviewStatus.withID(Integer.valueOf(id)))))); //NON-NLS - } - } catch (TskCoreException | SQLException ex) { - LOGGER.log(Level.SEVERE, "Error querying for files with ccn hits.", ex); //NON-NLS - return false; - } - return true; - } - - @Override - protected Node createNodeForKey(FileWithCCN key) { - //add all account artifacts for the file and the file itself to the lookup - try { - List lookupContents = new ArrayList<>(); - for (long artId : key.artifactIDS) { - lookupContents.add(skCase.getBlackboardArtifact(artId)); - } - AbstractFile abstractFileById = skCase.getAbstractFileById(key.getObjID()); - lookupContents.add(abstractFileById); - return new FileWithCCNNode(key, abstractFileById, lookupContents.toArray()); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error getting content for file with ccn hits.", ex); //NON-NLS - return null; - } - } - - @Override - public void update(Observable o, Object arg) { - refresh(true); - } - } - /** * Node that represents a file or chunk of an unallocated space file. */ @@ -726,6 +781,56 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { public class BINNode extends DisplayableItemNode implements Observer { + /** + * Creates the nodes for the accounts of a given type + */ + private class CreditCardNumberFactory extends ObservingChildFactory { + + private final BinResult bin; + + private CreditCardNumberFactory(BinResult bin) { + this.bin = bin; + } + + @Override + protected boolean createKeys(List list) { + + String query + = "SELECT blackboard_artifacts.artifact_id " //NON-NLS + + " FROM blackboard_artifacts " //NON-NLS + + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER.getTypeID() //NON-NLS + + " AND blackboard_attributes.value_text >= \"" + bin.getBINStart() + "\" AND blackboard_attributes.value_text < \"" + (bin.getBINEnd() + 1) + "\"" //NON-NLS + + getRejectedArtifactFilterClause() + + " ORDER BY blackboard_attributes.value_text"; //NON-NLS + try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); + ResultSet rs = results.getResultSet();) { + while (rs.next()) { + list.add(rs.getLong("artifact_id")); //NON-NLS + } + } catch (TskCoreException | SQLException ex) { + LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS + return false; + } + return true; + } + + @Override + protected Node createNodeForKey(Long artifactID) { + if (skCase == null) { + return null; + } + + try { + BlackboardArtifact art = skCase.getBlackboardArtifact(artifactID); + return new AccountArtifactNode(art); + } catch (TskCoreException ex) { + LOGGER.log(Level.WARNING, "Error creating BlackboardArtifactNode for artifact with ID " + artifactID, ex); //NON-NLS + return null; + } + } + } private final BinResult bin; private final CreditCardNumberFactory accountFactory; @@ -833,59 +938,6 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } - /** - * Factory that generates the children of the ByBin node. - */ - private class BINFactory extends ObservingChildFactory { - - @Override - protected boolean createKeys(List list) { - RangeMap ranges = TreeRangeMap.create(); - - String query - = "SELECT SUBSTR(blackboard_attributes.value_text,1,8) AS BIN, " //NON-NLS - + " COUNT(blackboard_artifacts.artifact_id) AS count " //NON-NLS - + " FROM blackboard_artifacts " //NON-NLS - + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS - + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER.getTypeID() //NON-NLS - + getRejectedArtifactFilterClause() - + " GROUP BY BIN " //NON-NLS - + " ORDER BY BIN "; //NON-NLS - try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query)) { - ResultSet resultSet = results.getResultSet(); - while (resultSet.next()) { - final Integer bin = Integer.valueOf(resultSet.getString("BIN")); - long count = resultSet.getLong("count"); - - BINRange binRange = (BINRange) CreditCards.getBINInfo(bin); - BinResult previousResult = ranges.get(bin); - - if (previousResult != null) { - ranges.remove(Range.closed(previousResult.getBINStart(), previousResult.getBINEnd())); - count += previousResult.getCount(); - } - - if (binRange != null) { - ranges.put(Range.closed(binRange.getBINstart(), binRange.getBINend()), new BinResult(count, binRange)); - } else { - ranges.put(Range.closed(bin, bin), new BinResult(count, bin, bin)); - } - } - ranges.asMapOfRanges().values().forEach(list::add); - } catch (TskCoreException | SQLException ex) { - LOGGER.log(Level.SEVERE, "Error querying for BINs.", ex); //NON-NLS - return false; - } - return true; - } - - @Override - protected Node createNodeForKey(BinResult key) { - return new BINNode(key); - } - } - /** * Data model item to back the BINNodes in the tree. Has the number of * accounts found with the BIN. @@ -978,57 +1030,6 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } - /** - * Creates the nodes for the accounts of a given type - */ - private class CreditCardNumberFactory extends ObservingChildFactory { - - private final BinResult bin; - - private CreditCardNumberFactory(BinResult bin) { - this.bin = bin; - } - - @Override - protected boolean createKeys(List list) { - - String query - = "SELECT blackboard_artifacts.artifact_id " //NON-NLS - + " FROM blackboard_artifacts " //NON-NLS - + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS - + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS - + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER.getTypeID() //NON-NLS - + " AND blackboard_attributes.value_text >= \"" + bin.getBINStart() + "\" AND blackboard_attributes.value_text < \"" + (bin.getBINEnd() + 1) + "\"" //NON-NLS - + getRejectedArtifactFilterClause() - + " ORDER BY blackboard_attributes.value_text"; //NON-NLS - try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); - ResultSet rs = results.getResultSet();) { - while (rs.next()) { - list.add(rs.getLong("artifact_id")); //NON-NLS - } - } catch (TskCoreException | SQLException ex) { - LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS - return false; - } - return true; - } - - @Override - protected Node createNodeForKey(Long artifactID) { - if (skCase == null) { - return null; - } - - try { - BlackboardArtifact art = skCase.getBlackboardArtifact(artifactID); - return new AccountArtifactNode(art); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Error creating BlackboardArtifactNode for artifact with ID " + artifactID, ex); //NON-NLS - return null; - } - } - } - private class AccountArtifactNode extends BlackboardArtifactNode { private final BlackboardArtifact artifact; @@ -1122,6 +1123,4 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } } - - } From e5e791bbbe94467d4170336cb71a5c4c36d6a9ed Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 26 Sep 2016 15:25:17 +0200 Subject: [PATCH 31/54] make inner classes final --- .../autopsy/datamodel/_private/Accounts.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java index 70adc98f16..d79e5eae20 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java @@ -162,13 +162,13 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { * Top-level node for the accounts tree */ @NbBundle.Messages({"Accounts.RootNode.displayName=Accounts"}) - public class AccountsRootNode extends DisplayableItemNode { + final public class AccountsRootNode extends DisplayableItemNode { /** * Creates child nodes for each account type (currently hard coded to * make one for Credit Cards) */ - private class AccountTypeFactory extends ObservingChildFactory { + final private class AccountTypeFactory extends ObservingChildFactory { /* * The pcl is in this class because it has the easiest mechanisms to @@ -301,9 +301,9 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } - public class DefaultAccountTypeNode extends DisplayableItemNode { + final public class DefaultAccountTypeNode extends DisplayableItemNode { - private class DefaultAccountFactory extends ChildFactory.Detachable { + final private class DefaultAccountFactory extends ChildFactory.Detachable { private final String accountTypeName; @@ -376,13 +376,13 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { * * NOTE: currently hard coded to work for Credit Card only */ - public class CreditCardNumberAccountTypeNode extends DisplayableItemNode { + final public class CreditCardNumberAccountTypeNode extends DisplayableItemNode { /** * ChildFactory that makes nodes for the different account organizations * (by file, by BIN) */ - private class ViewModeFactory extends ObservingChildFactory { + final private class ViewModeFactory extends ObservingChildFactory { @Override protected boolean createKeys(List list) { @@ -425,12 +425,12 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { * Node that is the root of the "by file" accounts tree. Its children are * FileWithCCNNodes. */ - public class ByFileNode extends DisplayableItemNode implements Observer { + final public class ByFileNode extends DisplayableItemNode implements Observer { /** * Factory for the children of the ByFiles Node. */ - private class FileWithCCNFactory extends ObservingChildFactory { + final private class FileWithCCNFactory extends ObservingChildFactory { @Override protected boolean createKeys(List list) { @@ -530,12 +530,12 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { * Node that is the root of the "By BIN" accounts tree. Its children are * BINNodes. */ - public class ByBINNode extends DisplayableItemNode implements Observer { + final public class ByBINNode extends DisplayableItemNode implements Observer { /** * Factory that generates the children of the ByBin node. */ - private class BINFactory extends ObservingChildFactory { + final private class BINFactory extends ObservingChildFactory { @Override protected boolean createKeys(List list) { @@ -627,7 +627,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { * associated accounts. */ @Immutable - private static class FileWithCCN { + final private static class FileWithCCN { private final long objID; private final String solrDocumentId; @@ -690,7 +690,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { /** * Node that represents a file or chunk of an unallocated space file. */ - public class FileWithCCNNode extends DisplayableItemNode { + final public class FileWithCCNNode extends DisplayableItemNode { private final FileWithCCN fileKey; private final String fileName; @@ -779,12 +779,12 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } - public class BINNode extends DisplayableItemNode implements Observer { + final public class BINNode extends DisplayableItemNode implements Observer { /** * Creates the nodes for the accounts of a given type */ - private class CreditCardNumberFactory extends ObservingChildFactory { + final private class CreditCardNumberFactory extends ObservingChildFactory { private final BinResult bin; @@ -943,7 +943,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { * accounts found with the BIN. */ @Immutable - static private class BinResult implements CreditCards.BankIdentificationNumber { + final static private class BinResult implements CreditCards.BankIdentificationNumber { /** * The number of accounts with this BIN @@ -1030,7 +1030,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } - private class AccountArtifactNode extends BlackboardArtifactNode { + final private class AccountArtifactNode extends BlackboardArtifactNode { private final BlackboardArtifact artifact; @@ -1079,7 +1079,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } - private class ApproveAccounts extends AbstractAction { + final private class ApproveAccounts extends AbstractAction { private final Collection artifacts; @@ -1101,7 +1101,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } - private class RejectAccounts extends AbstractAction { + final private class RejectAccounts extends AbstractAction { private final Collection artifacts; From df3886317891665b5b568be2f7db01ba400d4c17 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Mon, 26 Sep 2016 10:15:49 -0400 Subject: [PATCH 32/54] Changed datetime value type attributes to be formatted as dates instead of longs --- .../datamodel/ArtifactStringContent.java | 75 ++++++++----------- 1 file changed, 31 insertions(+), 44 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java index fa59de87c1..53523be839 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java @@ -27,7 +27,6 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskException; @@ -68,7 +67,7 @@ public class ArtifactStringContent implements StringContent { buffer.append(""); //NON-NLS buffer.append("\n"); //NON-NLS - // cycle through each attribute and display in a row in the table. + // cycle through each attribute and display in a row in the table. for (BlackboardAttribute attr : artifact.getAttributes()) { // name column @@ -78,48 +77,36 @@ public class ArtifactStringContent implements StringContent { // value column buffer.append(""); //NON-NLS - if (attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID() - || attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID() - || attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID() - || attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED.getTypeID() - || attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_RCVD.getTypeID() - || attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID() - || attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID() - || attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID()) { - long epoch = attr.getValueLong(); - String time = "0000-00-00 00:00:00"; - if (epoch != 0) { - dateFormatter.setTimeZone(getTimeZone(artifact)); - time = dateFormatter.format(new java.util.Date(epoch * 1000)); - } - buffer.append(time); - } else { - switch (attr.getAttributeType().getValueType()) { - case STRING: - String str = attr.getValueString(); - str = str.replaceAll(" ", " "); //NON-NLS - str = str.replaceAll("<", "<"); //NON-NLS - str = str.replaceAll(">", ">"); //NON-NLS - str = str.replaceAll("(\r\n|\n)", "
"); //NON-NLS - buffer.append(str); - break; - case INTEGER: - buffer.append(attr.getValueInt()); - break; - case LONG: - buffer.append(attr.getValueLong()); - break; - case DOUBLE: - buffer.append(attr.getValueDouble()); - break; - case BYTE: - buffer.append(Arrays.toString(attr.getValueBytes())); - break; - case DATETIME: - buffer.append(attr.getValueLong()); - break; - - } + switch (attr.getAttributeType().getValueType()) { + case STRING: + String str = attr.getValueString(); + str = str.replaceAll(" ", " "); //NON-NLS + str = str.replaceAll("<", "<"); //NON-NLS + str = str.replaceAll(">", ">"); //NON-NLS + str = str.replaceAll("(\r\n|\n)", "
"); //NON-NLS + buffer.append(str); + break; + case INTEGER: + buffer.append(attr.getValueInt()); + break; + case LONG: + buffer.append(attr.getValueLong()); + break; + case DOUBLE: + buffer.append(attr.getValueDouble()); + break; + case BYTE: + buffer.append(Arrays.toString(attr.getValueBytes())); + break; + case DATETIME: + long epoch = attr.getValueLong(); + String time = "0000-00-00 00:00:00"; + if (epoch != 0) { + dateFormatter.setTimeZone(getTimeZone(artifact)); + time = dateFormatter.format(new java.util.Date(epoch * 1000)); + } + buffer.append(time); + break; } if (!"".equals(attr.getContext())) { buffer.append(" ("); From 905975e5686fa56e15b009d714c935b98c236e25 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 26 Sep 2016 16:46:09 +0200 Subject: [PATCH 33/54] remove credit from attribute names --- .../autopsy/datamodel/_private/Accounts.java | 6 ++-- .../keywordsearch/ExtractedContentViewer.java | 2 +- .../keywordsearch/KeywordSearchList.java | 2 +- .../keywordsearch/TermComponentQuery.java | 31 ++++++++++--------- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java index d79e5eae20..915ddf694b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java @@ -547,7 +547,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS - + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER.getTypeID() //NON-NLS + + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + getRejectedArtifactFilterClause() + " GROUP BY BIN " //NON-NLS + " ORDER BY BIN "; //NON-NLS @@ -800,7 +800,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS - + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER.getTypeID() //NON-NLS + + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + " AND blackboard_attributes.value_text >= \"" + bin.getBINStart() + "\" AND blackboard_attributes.value_text < \"" + (bin.getBINEnd() + 1) + "\"" //NON-NLS + getRejectedArtifactFilterClause() + " ORDER BY blackboard_attributes.value_text"; //NON-NLS @@ -976,7 +976,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { return binEnd; } - public long getCount() { + long getCount() { return count; } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java index 1de41b5eab..f147e16170 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/ExtractedContentViewer.java @@ -148,7 +148,7 @@ public class ExtractedContentViewer implements DataContentViewer { } } - BlackboardAttribute keyWordAttr = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER)); + BlackboardAttribute keyWordAttr = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER)); if (keyWordAttr != null) { String valueString = keyWordAttr.getValueString(); if (StringUtils.isNotBlank(valueString)) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchList.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchList.java index 3e437caaa8..028908dc34 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchList.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchList.java @@ -122,7 +122,7 @@ abstract class KeywordSearchList { //CCN List ccns = new ArrayList<>(); - ccns.add(new Keyword(CCN_REGEX, false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER)); + ccns.add(new Keyword(CCN_REGEX, false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER)); lockedLists.add("Credit Card Numbers"); addList("Credit Card Numbers", ccns, true, false, true); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java index 7888010d87..7dcb605c18 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java @@ -54,8 +54,6 @@ final class TermComponentQuery implements KeywordSearchQuery { private static final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName(); private static final BlackboardAttribute.Type KEYWORD_SEARCH_DOCUMENT_ID = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID); - private static final BlackboardAttribute.Type CREDIT_CARD_NUMBER = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER); - private static final BlackboardAttribute.Type ACOUNT_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE); //TODO: move these regex and the luhn check to a new class, something like: CreditCardNumberValidator /* @@ -188,9 +186,12 @@ final class TermComponentQuery implements KeywordSearchQuery { Collection attributes = new ArrayList<>(); try { //if the keyword hit matched the credit card number keyword/regex... - if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER) { + if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) { newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT); - newArtifact.addAttribute(new BlackboardAttribute(ACOUNT_TYPE, MODULE_NAME, Account.Type.CREDIT_CARD.name())); + final BlackboardAttribute attr = new BlackboardAttribute( + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE), + MODULE_NAME, Account.Type.CREDIT_CARD.name()); + newArtifact.addAttribute(attr); // make account artifact //try to match it against the track 1 regex @@ -212,18 +213,18 @@ final class TermComponentQuery implements KeywordSearchQuery { } } - String ccn = newArtifact.getAttribute(CREDIT_CARD_NUMBER).getValueString(); + String ccn = newArtifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER)).getValueString(); final int bin = Integer.parseInt(ccn.substring(0, 8)); CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin); if (binInfo != null) { binInfo.getScheme().ifPresent(scheme - -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_SCHEME, scheme)); + -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_CARD_SCHEME, scheme)); binInfo.getCardType().ifPresent(cardType - -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_PAYMENT_CARD_TYPE, cardType)); + -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_CARD_TYPE, cardType)); binInfo.getBrand().ifPresent(brand - -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_BRAND, brand)); + -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_BRAND_NAME, brand)); binInfo.getBankName().ifPresent(bankName -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_BANK_NAME, bankName)); binInfo.getBankPhoneNumber().ifPresent(phoneNumber @@ -327,7 +328,7 @@ final class TermComponentQuery implements KeywordSearchQuery { for (Term term : terms) { final String termStr = KeywordSearchUtil.escapeLuceneQuery(term.getTerm()); - if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER) { + if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) { //If the keyword is a credit card number, pass it through luhn validator Matcher matcher = CCN_PATTERN.matcher(term.getTerm()); matcher.find(); @@ -387,7 +388,7 @@ final class TermComponentQuery implements KeywordSearchQuery { BlackboardAttribute.Type type = new BlackboardAttribute.Type(attrType); if (artifact.getAttribute(type) == null) { String value = matcher.group(groupName); - if (attrType.equals(ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER)) { + if (attrType.equals(ATTRIBUTE_TYPE.TSK_CARD_NUMBER)) { value = CharMatcher.anyOf(" -").removeFrom(value); } if (StringUtils.isNotBlank(value)) { @@ -408,11 +409,11 @@ final class TermComponentQuery implements KeywordSearchQuery { */ static private void parseTrack2Data(BlackboardArtifact artifact, Matcher matcher) throws IllegalArgumentException, TskCoreException { //try to add all the attrributes common to track 1 and 2 - addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_NUMBER, "accountNumber", matcher); - addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_EXPIRATION, "expiration", matcher); - addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_SERVICE_CODE, "serviceCode", matcher); - addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_DISCRETIONARY, "discretionary", matcher); - addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_LRC, "LRC", matcher); + addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CARD_NUMBER, "accountNumber", matcher); + addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CARD_EXPIRATION, "expiration", matcher); + addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CARD_SERVICE_CODE, "serviceCode", matcher); + addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CARD_DISCRETIONARY, "discretionary", matcher); + addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CARD_LRC, "LRC", matcher); } From d99d53056864a03605d10b03bd9eb4519bf77aeb Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 26 Sep 2016 14:33:08 -0400 Subject: [PATCH 34/54] Made 7zip packages public --- Core/nbproject/project.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 216a8e0f82..62fef4adaf 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -222,6 +222,10 @@ + net.sf.sevenzipjbinding + net.sf.sevenzipjbinding.impl + net.sf.sevenzipjbinding.simple + net.sf.sevenzipjbinding.simple.impl org.sleuthkit.autopsy.actions org.sleuthkit.autopsy.casemodule org.sleuthkit.autopsy.casemodule.events From e7a5f59081ddf25d3f7951bcf9a25e1a81a82f25 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Tue, 27 Sep 2016 09:44:04 -0400 Subject: [PATCH 35/54] Modified button behavior and text, disallowed empty tags --- .../casemodule/services/Bundle.properties | 4 +- .../services/NewUserTagNameDialog.java | 21 ++++++---- .../services/TagNamesSettingsPanel.form | 12 +++--- .../services/TagNamesSettingsPanel.java | 30 +++++++------- .../casemodule/services/TagsManager.java | 40 +++++++++---------- 5 files changed, 57 insertions(+), 50 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index 226b661523..c117fe5186 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -13,7 +13,6 @@ TagsManagerOptionsPanel.addTagNameButton.empty=Tag name text is empty. TagsManagerOptionsPanel.addTagNameButton.containInvalidCharacter=Tag name may not contain any of the following symbols\: \\ \: * ? " < > | , ; TagsManagerOptionsPanel.addTagNameButton.alreadyExists=Tag name already exists. TagNamesSettingsPanel.deleteTagNameButton.text=Delete Tag Name -TagNamesSettingsPanel.addTagNameButton.text=Add Tag Name TagNamesSettingsPanel.tagNamesListLabel.text=Your tag names: NewUserTagNameDialog.tagNameTextField.text= NewUserTagNameDialog.newTagNameLabel.text=New Tag Name: @@ -24,4 +23,7 @@ NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.message=Tag name may n NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.title=Invalid character in tag name TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.message=The tag name already exists in your settings TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.title=Tag name already exists +NewUserTagNameDialog.JOptionPane.tagNameEmpty.message=The tag name cannot be empty +NewUserTagNameDialog.JOptionPane.tagNameEmpty.title=Empty tag name TagNamesSettingsPanel.panelDescriptionLabel.text=Autopsy keeps a list of the tag names you have created in the past. Add more or delete them here. +TagNamesSettingsPanel.newTagNameButton.text=New Tag Name diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java index 778ae3886d..12fc8cb22b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java @@ -45,7 +45,6 @@ public class NewUserTagNameDialog extends javax.swing.JDialog { super(new JFrame(NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.title.text")), NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.title.text"), true); initComponents(); - String test = ""; this.display(); } @@ -74,7 +73,7 @@ public class NewUserTagNameDialog extends javax.swing.JDialog { }); /* - * Add a listener to enable the save button when the text field changes. + * Add a listener to enable the OK button when the text field changes. */ tagNameTextField.getDocument().addDocumentListener(new DocumentListener() { @Override @@ -109,21 +108,27 @@ public class NewUserTagNameDialog extends javax.swing.JDialog { */ private void doButtonAction(boolean okPressed) { if (okPressed) { - String newTagDisplayName = tagNameTextField.getText(); + String newTagDisplayName = tagNameTextField.getText().trim(); + if (newTagDisplayName.isEmpty()) { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameEmpty.message"), + NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameEmpty.title"), + JOptionPane.ERROR_MESSAGE); + return; + } if (TagsManager.containsIllegalCharacters(newTagDisplayName)) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.message"), NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.title"), JOptionPane.ERROR_MESSAGE); - } else { - userTagDisplayName = newTagDisplayName; - result = BUTTON_PRESSED.OK; - setVisible(false); + return; } + userTagDisplayName = newTagDisplayName; + result = BUTTON_PRESSED.OK; } else { result = BUTTON_PRESSED.CANCEL; - setVisible(false); } + setVisible(false); } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form index 59cac6e9bc..3e71ffdeeb 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form @@ -92,10 +92,10 @@ - + - + @@ -112,7 +112,7 @@ - + @@ -150,17 +150,17 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java index e0da98adb6..576b375b5d 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java @@ -80,7 +80,7 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options tagNamesListLabel = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); tagNamesList = new javax.swing.JList<>(); - addTagNameButton = new javax.swing.JButton(); + newTagNameButton = new javax.swing.JButton(); deleteTagNameButton = new javax.swing.JButton(); tagNameAdditionalPanel = new javax.swing.JPanel(); @@ -100,11 +100,11 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options }); jScrollPane1.setViewportView(tagNamesList); - addTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add-tag.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(addTagNameButton, org.openide.util.NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.addTagNameButton.text")); // NOI18N - addTagNameButton.addActionListener(new java.awt.event.ActionListener() { + newTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add-tag.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(newTagNameButton, org.openide.util.NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.newTagNameButton.text")); // NOI18N + newTagNameButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - addTagNameButtonActionPerformed(evt); + newTagNameButtonActionPerformed(evt); } }); @@ -125,10 +125,10 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options .addGroup(modifyTagNameListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(tagNamesListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(modifyTagNameListPanelLayout.createSequentialGroup() - .addComponent(addTagNameButton) + .addComponent(newTagNameButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(deleteTagNameButton) - .addGap(0, 115, Short.MAX_VALUE)) + .addGap(0, 113, Short.MAX_VALUE)) .addComponent(jScrollPane1)) .addContainerGap()) ); @@ -141,7 +141,7 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 383, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(modifyTagNameListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(addTagNameButton) + .addComponent(newTagNameButton) .addComponent(deleteTagNameButton)) .addContainerGap()) ); @@ -196,7 +196,7 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options ); }// //GEN-END:initComponents - private void addTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addTagNameButtonActionPerformed + private void newTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagNameButtonActionPerformed NewUserTagNameDialog dialog = new NewUserTagNameDialog(); NewUserTagNameDialog.BUTTON_PRESSED result = dialog.getResult(); if (result == NewUserTagNameDialog.BUTTON_PRESSED.OK) { @@ -209,24 +209,26 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options JOptionPane.showMessageDialog(null, NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.message"), NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.title"), - JOptionPane.ERROR_MESSAGE); + JOptionPane.INFORMATION_MESSAGE); } else { tagNames.add(newTagName); updateTagNamesListModel(); /* * Set the selection to the tag name that was just added. */ - tagNamesList.setSelectedIndex(tagNames.size() - 1); + int index = tagNames.indexOf(newTagName); + tagNamesList.setSelectedIndex(index); enableButtons(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } } - }//GEN-LAST:event_addTagNameButtonActionPerformed + }//GEN-LAST:event_newTagNameButtonActionPerformed private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagNameButtonActionPerformed UserTagName tagName = tagNamesList.getSelectedValue(); tagNames.remove(tagName); updateTagNamesListModel(); + enableButtons(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_deleteTagNameButtonActionPerformed @@ -235,12 +237,12 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options }//GEN-LAST:event_tagNamesListMouseClicked // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton addTagNameButton; private javax.swing.JButton deleteTagNameButton; private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JSplitPane jSplitPane1; private javax.swing.JPanel modifyTagNameListPanel; + private javax.swing.JButton newTagNameButton; private javax.swing.JLabel panelDescriptionLabel; private javax.swing.JPanel tagNameAdditionalPanel; private javax.swing.JList tagNamesList; @@ -252,6 +254,7 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options */ private void updateTagNamesListModel() { tagNamesListModel.clear(); + Collections.sort(tagNames); for (UserTagName tagName : tagNames) { tagNamesListModel.addElement(tagName); } @@ -294,7 +297,6 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options tagNames.add(new UserTagName(tagNameAttributes[0], tagNameAttributes[1], tagNameAttributes[2])); } } - Collections.sort(tagNames); updateTagNamesListModel(); enableButtons(); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 5727fde423..e2b3fd6ab1 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -15,7 +15,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. -*/ + */ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; @@ -83,7 +83,7 @@ public class TagsManager implements Closeable { /** * Gets a list of all tag names currently being used or tag names loaded * from the properties file. - * + * * @return A list, possibly empty, of TagName data transfer objects (DTOs). * * @throws TskCoreException If there is an error reading from the case @@ -147,7 +147,7 @@ public class TagsManager implements Closeable { * @return A TagName data transfer object (DTO) representing the new tag * name. * - * @throws TagNameAlreadyExistsException If the tag name would be a + * @throws TagNameAlreadyExistsException If the tag name would be a * duplicate. * @throws TskCoreException If there is an error adding the tag * to the case database. @@ -168,7 +168,7 @@ public class TagsManager implements Closeable { * @return A TagName data transfer object (DTO) representing the new tag * name. * - * @throws TagNameAlreadyExistsException If the tag name would be a + * @throws TagNameAlreadyExistsException If the tag name would be a * duplicate. * @throws TskCoreException If there is an error adding the tag * to the case database. @@ -190,7 +190,7 @@ public class TagsManager implements Closeable { * @return A TagName data transfer object (DTO) representing the new tag * name. * - * @throws TagNameAlreadyExistsException If the tag name would be a + * @throws TagNameAlreadyExistsException If the tag name would be a * duplicate. * @throws TskCoreException If there is an error adding the tag * to the case database. @@ -291,33 +291,33 @@ public class TagsManager implements Closeable { ContentTag tag; synchronized (this) { lazyLoadExistingTagNames(); - + if (null == comment) { throw new IllegalArgumentException("Passed null comment argument"); } - + if (beginByteOffset >= 0 && endByteOffset >= 1) { if (beginByteOffset > content.getSize() - 1) { throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.beginByteOffsetOOR.msg", beginByteOffset, content.getSize() - 1)); } - + if (endByteOffset > content.getSize() - 1) { throw new IllegalArgumentException( NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endByteOffsetOOR.msg", endByteOffset, content.getSize() - 1)); } - + if (endByteOffset < beginByteOffset) { throw new IllegalArgumentException( NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endLTbegin.msg")); } } - + tag = caseDb.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); } - + try { Case.getCurrentCase().notifyContentTagAdded(tag); } catch (IllegalStateException ex) { @@ -342,7 +342,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); caseDb.deleteContentTag(tag); } - + try { Case.getCurrentCase().notifyContentTagDeleted(tag); } catch (IllegalStateException ex) { @@ -509,7 +509,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); caseDb.deleteBlackboardArtifactTag(tag); } - + try { Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); } catch (IllegalStateException ex) { @@ -618,7 +618,6 @@ public class TagsManager implements Closeable { @Override @Deprecated public synchronized void close() throws IOException { - //saveTagNamesToTagsSettings(); caseDb = null; } @@ -660,7 +659,7 @@ public class TagsManager implements Closeable { if (null != setting && !setting.isEmpty()) { // Read the tag name setting and break it into tag name tuples. List tagNameTuples = Arrays.asList(setting.split(";")); - + // Parse each tuple and add the tag names to the current case, one // at a time to gracefully discard any duplicates or corrupt tuples. for (String tagNameTuple : tagNameTuples) { @@ -671,7 +670,7 @@ public class TagsManager implements Closeable { uniqueTagNames.put(tagName.getDisplayName(), tagName); } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add saved tag name " + tagNameAttributes[0], ex); //NON-NLS - } + } } } } @@ -695,7 +694,7 @@ public class TagsManager implements Closeable { /** * Adds any user defined tag name to the case db and also to uniqueTagNames, * to allow user tag names to be displayed while tagging. - * + * * @param userTagNames a List of UserTagName objects to be potentially added */ void storeNewUserTagNames(List userTagNames) { @@ -720,8 +719,7 @@ public class TagsManager implements Closeable { String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); if (setting == null || setting.isEmpty()) { setting = ""; - } - else { + } else { setting += ";"; } setting += tagName.getDisplayName() + "," + tagName.getDescription() + "," + tagName.getColor().toString(); @@ -731,7 +729,7 @@ public class TagsManager implements Closeable { /** * Returns true if the tag display name contains an illegal character. Used * after a tag display name is retrieved from user input. - * + * * @param content Display name of the tag being added. * @return boolean indicating whether the name has an invalid character. */ @@ -752,7 +750,7 @@ public class TagsManager implements Closeable { * Exception thrown if there is an attempt to add a duplicate tag name. */ public static class TagNameAlreadyExistsException extends Exception { - + private static final long serialVersionUID = 1L; } From a32b95943f5b997c0a722025dd71774954ededd2 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Tue, 27 Sep 2016 11:17:31 -0400 Subject: [PATCH 36/54] Made TagsManager methods more general, moved tag name display logic to TagsManager clients --- .../autopsy/actions/AddTagAction.java | 11 ++++-- .../actions/GetTagNameAndCommentDialog.java | 9 ++++- .../autopsy/actions/GetTagNameDialog.java | 8 ++++- .../services/TagNamesSettingsPanel.form | 1 + .../services/TagNamesSettingsPanel.java | 7 ++++ .../casemodule/services/TagsManager.java | 36 +++++++++---------- 6 files changed, 50 insertions(+), 22 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index 7db5a5e0ee..2729e5e6ff 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -19,8 +19,12 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.TreeSet; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.JMenu; @@ -89,8 +93,11 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); List tagNames = null; try { - tagNames = tagsManager.getAllTagNamesForDisplay(); - Collections.sort(tagNames); + Set tagNamesSet = new TreeSet<>(); + tagNamesSet.addAll(tagsManager.getUserTagNames()); + tagNamesSet.addAll(tagsManager.getTagNamesInUse()); + tagNamesSet.addAll(tagsManager.getPredefinedTagNames()); + tagNames = new ArrayList(tagNamesSet); } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index 19b32e3905..9d9dbaa7c2 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -21,8 +21,11 @@ package org.sleuthkit.autopsy.actions; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Set; +import java.util.TreeSet; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.ActionMap; @@ -117,7 +120,11 @@ public class GetTagNameAndCommentDialog extends JDialog { TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); List currentTagNames = null; try { - currentTagNames = tagsManager.getAllTagNamesForDisplay(); + Set tagNamesSet = new TreeSet<>(); + tagNamesSet.addAll(tagsManager.getUserTagNames()); + tagNamesSet.addAll(tagsManager.getTagNamesInUse()); + tagNamesSet.addAll(tagsManager.getPredefinedTagNames()); + currentTagNames = new ArrayList(tagNamesSet); } catch (TskCoreException ex) { Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index fd8634e123..f055469fef 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -24,6 +24,8 @@ import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Set; +import java.util.TreeSet; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.ActionMap; @@ -98,7 +100,11 @@ public class GetTagNameDialog extends JDialog { TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); List currentTagNames = null; try { - currentTagNames = tagsManager.getAllTagNamesForDisplay(); + Set tagNamesSet = new TreeSet<>(); + tagNamesSet.addAll(tagsManager.getUserTagNames()); + tagNamesSet.addAll(tagsManager.getTagNamesInUse()); + tagNamesSet.addAll(tagsManager.getPredefinedTagNames()); + currentTagNames = new ArrayList(tagNamesSet); } catch (TskCoreException ex) { Logger.getLogger(GetTagNameDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form index 3e71ffdeeb..2ebeee3142 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form @@ -143,6 +143,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java index 576b375b5d..9905869ae5 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java @@ -97,6 +97,9 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options public void mouseClicked(java.awt.event.MouseEvent evt) { tagNamesListMouseClicked(evt); } + public void mousePressed(java.awt.event.MouseEvent evt) { + tagNamesListMousePressed(evt); + } }); jScrollPane1.setViewportView(tagNamesList); @@ -236,6 +239,10 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options enableButtons(); }//GEN-LAST:event_tagNamesListMouseClicked + private void tagNamesListMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tagNamesListMousePressed + enableButtons(); + }//GEN-LAST:event_tagNamesListMousePressed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton deleteTagNameButton; private javax.swing.JPanel jPanel1; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index e2b3fd6ab1..3d29b17ebb 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -64,8 +64,7 @@ public class TagsManager implements Closeable { } /** - * Gets a list of all tag names currently available for tagging content or - * artifacts. + * Gets a list of all tag names currently in the case database. * * @return A list, possibly empty, of TagName data transfer objects (DTOs). * @@ -81,33 +80,34 @@ public class TagsManager implements Closeable { } /** - * Gets a list of all tag names currently being used or tag names loaded - * from the properties file. + * Gets a list of all user tag names from the preference file. * * @return A list, possibly empty, of TagName data transfer objects (DTOs). - * - * @throws TskCoreException If there is an error reading from the case - * database. */ - public synchronized List getAllTagNamesForDisplay() throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } + public synchronized List getUserTagNames() { lazyLoadExistingTagNames(); - Set tagNameSet = new HashSet<>(); - // Add bookmark tag and other tag names that are in use - tagNameSet.add(uniqueTagNames.get(NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"))); - tagNameSet.addAll(getTagNamesInUse()); - // Add any tag names defined by the user + List tagNameList = new ArrayList<>(); String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); if (null != setting && !setting.isEmpty()) { List tagNameTuples = Arrays.asList(setting.split(";")); for (String tagNameTuple : tagNameTuples) { String[] tagNameAttributes = tagNameTuple.split(","); - tagNameSet.add(uniqueTagNames.get(tagNameAttributes[0])); + tagNameList.add(uniqueTagNames.get(tagNameAttributes[0])); } } - return new ArrayList<>(tagNameSet); + return tagNameList; + } + + /** + * Gets a list of all predefined tag names. + * + * @return A list of TagName data transfer objects (DTOs). + */ + public synchronized List getPredefinedTagNames() { + lazyLoadExistingTagNames(); + List tagNameList = new ArrayList<>(); + tagNameList.add(uniqueTagNames.get(NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"))); + return tagNameList; } /** From cdcd0fa45e17eb57427284a193bbb0d9e41af855 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Tue, 27 Sep 2016 15:19:44 -0400 Subject: [PATCH 37/54] Updated TagsManager for multiuser loading, changed some UI text --- Core/src/org/sleuthkit/autopsy/actions/Bundle.properties | 4 ++-- .../sleuthkit/autopsy/casemodule/services/Bundle.properties | 4 ++-- .../autopsy/casemodule/services/NewUserTagNameDialog.java | 2 +- .../autopsy/casemodule/services/TagNamesSettingsPanel.java | 4 ++-- .../sleuthkit/autopsy/casemodule/services/TagsManager.java | 3 +++ 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties index ba828aed5d..d964d91fc7 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties @@ -1,7 +1,7 @@ GetTagNameDialog.tagNameField.text= GetTagNameDialog.cancelButton.text=Cancel GetTagNameDialog.okButton.text=OK -GetTagNameDialog.preexistingLabel.text=Pre-existing Tags: +GetTagNameDialog.preexistingLabel.text=Pre-existing Tag Names: GetTagNameDialog.newTagPanel.border.title=New Tag GetTagNameDialog.tagNameLabel.text=Tag Name: GetTagNameAndCommentDialog.newTagButton.text=New Tag Name @@ -58,4 +58,4 @@ OpenOutputFolder.CouldNotOpenOutputFolder=Could not open output folder ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot OpenPythonModulesFolderAction.actionName.text=Python Plugins OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python plugins folder not found: {0} -CTL_OpenPythonModulesFolderAction=Python Plugins \ No newline at end of file +CTL_OpenPythonModulesFolderAction=Python Plugins diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index c117fe5186..8fbcb50595 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -1,4 +1,4 @@ -OptionsCategory_Name_TagNamesOptions=My Tag Names +OptionsCategory_Name_TagNamesOptions=Tags OptionsCategory_TagNames=TagNames TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0} out of content size range (0 - {1}) TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} out of content size range (0 - {1}) @@ -13,7 +13,7 @@ TagsManagerOptionsPanel.addTagNameButton.empty=Tag name text is empty. TagsManagerOptionsPanel.addTagNameButton.containInvalidCharacter=Tag name may not contain any of the following symbols\: \\ \: * ? " < > | , ; TagsManagerOptionsPanel.addTagNameButton.alreadyExists=Tag name already exists. TagNamesSettingsPanel.deleteTagNameButton.text=Delete Tag Name -TagNamesSettingsPanel.tagNamesListLabel.text=Your tag names: +TagNamesSettingsPanel.tagNamesListLabel.text=Tag names: NewUserTagNameDialog.tagNameTextField.text= NewUserTagNameDialog.newTagNameLabel.text=New Tag Name: NewUserTagNameDialog.okButton.text=OK diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java index 12fc8cb22b..bd04678ba9 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java @@ -29,7 +29,7 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.openide.util.NbBundle; -public class NewUserTagNameDialog extends javax.swing.JDialog { +class NewUserTagNameDialog extends javax.swing.JDialog { private String userTagDisplayName; private BUTTON_PRESSED result; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java index 9905869ae5..051e8e9549 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java @@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; * properties file, able to be used across cases. Potentially room to add other * tag name options in the future. */ -public class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsPanel { +final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsPanel { private static final Logger logger = Logger.getLogger(TagNamesSettingsPanel.class.getName()); @@ -53,7 +53,7 @@ public class TagNamesSettingsPanel extends javax.swing.JPanel implements Options /** * Creates new form TagsManagerOptionsPanel */ - public TagNamesSettingsPanel() { + TagNamesSettingsPanel() { initComponents(); customizeComponents(); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 3d29b17ebb..9cd7a72183 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -631,6 +631,9 @@ public class TagsManager implements Closeable { addPredefinedTagNames(); addTagNamesFromTagsSettings(); tagNamesLoaded = true; + } else { + // Reload case db tag names in case another user has added some. + addTagNamesFromCurrentCase(); } } From ba4640648c2d4087083b0384683fc58b4fa3f226 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Tue, 27 Sep 2016 15:30:57 -0400 Subject: [PATCH 38/54] Updated listener method for list selection --- .../services/TagNamesSettingsPanel.form | 4 --- .../services/TagNamesSettingsPanel.java | 26 +++++++------------ 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form index 2ebeee3142..4412f20274 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form @@ -141,10 +141,6 @@ - - - - diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java index 051e8e9549..d6f4953824 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java @@ -24,6 +24,8 @@ import java.util.Collections; import java.util.List; 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 org.sleuthkit.autopsy.casemodule.Case; @@ -57,11 +59,17 @@ final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsP initComponents(); customizeComponents(); } - + private void customizeComponents() { tagNamesListModel = new DefaultListModel<>(); tagNamesList.setModel(tagNamesListModel); tagNames = new ArrayList<>(); + tagNamesList.addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + enableButtons(); + } + }); } /** @@ -93,14 +101,6 @@ final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsP org.openide.awt.Mnemonics.setLocalizedText(tagNamesListLabel, org.openide.util.NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.tagNamesListLabel.text")); // NOI18N - tagNamesList.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - tagNamesListMouseClicked(evt); - } - public void mousePressed(java.awt.event.MouseEvent evt) { - tagNamesListMousePressed(evt); - } - }); jScrollPane1.setViewportView(tagNamesList); newTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add-tag.png"))); // NOI18N @@ -235,14 +235,6 @@ final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsP firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_deleteTagNameButtonActionPerformed - private void tagNamesListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tagNamesListMouseClicked - enableButtons(); - }//GEN-LAST:event_tagNamesListMouseClicked - - private void tagNamesListMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tagNamesListMousePressed - enableButtons(); - }//GEN-LAST:event_tagNamesListMousePressed - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton deleteTagNameButton; private javax.swing.JPanel jPanel1; From d2942263f279fa836408a7d75c2e66be9209deab Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 27 Sep 2016 17:28:55 -0400 Subject: [PATCH 39/54] Fix cause of IndexOutOfBounds exception for DataResultViewerThumbnail --- .../DataResultViewerThumbnail.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java index 990d83eee5..08a1f26b14 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerThumbnail.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -61,6 +61,7 @@ import org.sleuthkit.datamodel.TskCoreException; //@ServiceProvider(service = DataResultViewer.class) final class DataResultViewerThumbnail extends AbstractDataResultViewer { + private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(DataResultViewerThumbnail.class.getName()); //flag to keep track if images are being loaded private int curPage; @@ -95,7 +96,7 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer { iconView.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); em.addPropertyChangeListener(new ExplorerManagerNodeSelectionListener()); - thumbnailSizeComboBox.setModel(new javax.swing.DefaultComboBoxModel( + thumbnailSizeComboBox.setModel(new javax.swing.DefaultComboBoxModel<>( new String[] { Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_small(), Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_medium(), Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_large() })); @@ -395,11 +396,8 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer { private void switchPage() { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - } + EventQueue.invokeLater(() -> { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); }); //Note the nodes factories are likely creating nodes in EDT anyway, but worker still helps @@ -437,7 +435,7 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer { ex.getMessage()), NotifyDescriptor.ERROR_MESSAGE); DialogDisplayer.getDefault().notify(d); - logger.log(Level.SEVERE, "Error making thumbnails: " + ex.getMessage()); //NON-NLS + logger.log(Level.SEVERE, "Error making thumbnails: {0}", ex.getMessage()); //NON-NLS } // catch and ignore if we were cancelled catch (java.util.concurrent.CancellationException ex) { } @@ -453,6 +451,7 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer { goToPageField.setEnabled(false); pageNumLabel.setText(""); imagesRangeLabel.setText(""); + thumbnailSizeComboBox.setEnabled(false); } else { pageNumLabel.setText( NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.pageNumbers.curOfTotal", @@ -464,7 +463,7 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer { pageNextButton.setEnabled(!(curPage == totalPages)); pagePrevButton.setEnabled(!(curPage == 1)); goToPageField.setEnabled(totalPages > 1); - + thumbnailSizeComboBox.setEnabled(true); } } From c78dab32a0d8da3d2323f3d906e621edc1bfd3fc Mon Sep 17 00:00:00 2001 From: millmanorama Date: Wed, 28 Sep 2016 13:43:52 +0200 Subject: [PATCH 40/54] clarify comments --- .../sleuthkit/autopsy/report/ReportHTML.java | 8 ++--- .../autopsy/report/TableReportGenerator.java | 34 ++++++++++++------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index dfd4975aa7..f3057a946d 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -266,10 +266,10 @@ class ReportHTML implements TableReportModule { } } else if (dataType.startsWith(ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName())) { /* TSK_ACCOUNT artifacts get separated by their TSK_ACCOUNT_TYPE - * attribute, with a compound dataType name, so they are not caught - * by the switch statement above. For now we just give them all the - * general account icon, but we could do something else in the - * future. + * attribute, with a synthetic compound dataType name, so they are + * not caught by the switch statement above. For now we just give + * them all the general account icon, but we could do something else + * in the future. */ in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/accounts.png"); //NON-NLS iconFileName = "accounts.png"; //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java index 7d0a41fd43..8ba53127d5 100755 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -18,7 +18,9 @@ */ package org.sleuthkit.autopsy.report; +import com.google.common.collect.ListMultimap; import com.google.common.collect.Lists; +import com.google.common.collect.Multimaps; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; @@ -35,7 +37,6 @@ import java.util.Objects; import java.util.Set; import java.util.TreeSet; import java.util.logging.Level; -import java.util.stream.Collectors; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.EscapeUtil; @@ -157,21 +158,30 @@ class TableReportGenerator { } /* TSK_ACCOUNT artifacts get grouped by their TSK_ACCOUNT_TYPE - * attribute, and then handed off the default method for writing + * attribute, and then handed off to the standard method for writing * tables. */ if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { - Map> collect = artifactList.stream().collect(Collectors.groupingBy((ArtifactData artifactData) -> { - try { - return artifactData.getArtifact().getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE)).getValueString(); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Unable to get value of TSK_ACCOUNT_TYPE attribute. Defaulting to \"unknown\"", ex); - return "unknown"; - } - })); - for (Map.Entry> x : collect.entrySet()) { - writeTableForDataType(x.getValue(), type, BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + x.getKey(), comment); + //Group account artifacts by their account type + ListMultimap groupedArtifacts = Multimaps.index(artifactList, + artifactData -> { + try { + return artifactData.getArtifact().getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE)).getValueString(); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Unable to get value of TSK_ACCOUNT_TYPE attribute. Defaulting to \"unknown\"", ex); + return "unknown"; + } + }); + for (String accountType : groupedArtifacts.keySet()) { + /* If the report is a ReportHTML, the data type name + * eventualy makes it to useDataTypeIcon which expects but + * does not require a artifact name, so we make a synthetic + * compund name by appending a ":" and the account type. + */ + final String compundDataTypeName = BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + accountType; + writeTableForDataType(groupedArtifacts.get(accountType), type, compundDataTypeName, comment); } } else { + //all other artifact types are sent to writeTableForDataType directly writeTableForDataType(artifactList, type, type.getDisplayName(), comment); } } From b7f227b76ccb8b17874bf0e04524a82d6016bc68 Mon Sep 17 00:00:00 2001 From: Sophie Mori Date: Wed, 28 Sep 2016 15:09:28 -0400 Subject: [PATCH 41/54] Updated implementation to not automatically add user tag names --- .../autopsy/actions/AddTagAction.java | 54 +++++++---- .../actions/GetTagNameAndCommentDialog.java | 42 +++++---- .../autopsy/actions/GetTagNameDialog.java | 41 +++----- .../casemodule/services/Bundle.properties | 3 - .../services/TagNamesSettingsPanel.java | 6 ++ .../casemodule/services/TagsManager.java | 94 ++++++++++--------- 6 files changed, 134 insertions(+), 106 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index 2729e5e6ff..3d394e9215 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -19,12 +19,8 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; +import java.util.Map; +import java.util.TreeMap; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.JMenu; @@ -91,13 +87,12 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { // Get the current set of tag names. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - List tagNames = null; + Map tagNamesMap = null; try { - Set tagNamesSet = new TreeSet<>(); - tagNamesSet.addAll(tagsManager.getUserTagNames()); - tagNamesSet.addAll(tagsManager.getTagNamesInUse()); - tagNamesSet.addAll(tagsManager.getPredefinedTagNames()); - tagNames = new ArrayList(tagNamesSet); + tagNamesMap = new TreeMap<>(); + tagNamesMap.putAll(tagsManager.getUserTagNamesMap()); + tagNamesMap.putAll(tagsManager.getPredefinedTagNamesMap()); + tagNamesMap.putAll(tagsManager.getTagNamesInUseMap()); } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } @@ -109,11 +104,11 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { // Each tag name in the current set of tags gets its own menu item in // the "Quick Tags" sub-menu. Selecting one of these menu items adds // a tag with the associated tag name. - if (null != tagNames && !tagNames.isEmpty()) { - for (final TagName tagName : tagNames) { - JMenuItem tagNameItem = new JMenuItem(tagName.getDisplayName()); + if (null != tagNamesMap && !tagNamesMap.isEmpty()) { + for (Map.Entry entry : tagNamesMap.entrySet()) { + JMenuItem tagNameItem = new JMenuItem(entry.getKey()); tagNameItem.addActionListener((ActionEvent e) -> { - addTag(tagName, NO_COMMENT); + getAndAddTag(entry.getKey(), entry.getValue(), NO_COMMENT); }); quickTagMenu.add(tagNameItem); } @@ -121,7 +116,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { JMenuItem empty = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.noTags")); empty.setEnabled(false); quickTagMenu.add(empty); - } + } quickTagMenu.addSeparator(); @@ -150,5 +145,30 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { }); add(tagAndCommentItem); } + + /** + * Method to add to the action listener for each menu item. Allows a tag + * display name to be added to the menu with an action listener without + * having to instantiate a TagName object for it. + * When the method is called, the TagName object is created here if it + * doesn't already exist. + * + * @param tagDisplayName display name for the tag name + * @param tagName TagName object associated with the tag name, + * may be null + * @param comment comment for the content or artifact tag + */ + private void getAndAddTag(String tagDisplayName, TagName tagName, String comment) { + if (tagName == null) { + try { + tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName); + } catch (TagsManager.TagNameAlreadyExistsException ex) { + Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, tagDisplayName + " already exists in database.", ex); //NON-NLS + } catch (TskCoreException ex) { + Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS + } + } + addTag(tagName, comment); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index 9d9dbaa7c2..fa2b1b1593 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -21,11 +21,8 @@ package org.sleuthkit.autopsy.actions; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; +import java.util.Map; +import java.util.TreeMap; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.ActionMap; @@ -46,7 +43,7 @@ public class GetTagNameAndCommentDialog extends JDialog { private static final long serialVersionUID = 1L; private static final String NO_TAG_NAMES_MESSAGE = NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.noTags"); - private final HashMap tagNames = new HashMap<>(); + private final Map tagNamesMap = new TreeMap<>(); private TagNameAndComment tagNameAndComment = null; public static class TagNameAndComment { @@ -117,23 +114,21 @@ public class GetTagNameAndCommentDialog extends JDialog { // Populate the combo box with the available tag names and save the // tag name DTOs to be enable to return the one the user selects. + // Tag name DTOs may be null (user tag names that have not been used do + // not exist in the database). TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - List currentTagNames = null; try { - Set tagNamesSet = new TreeSet<>(); - tagNamesSet.addAll(tagsManager.getUserTagNames()); - tagNamesSet.addAll(tagsManager.getTagNamesInUse()); - tagNamesSet.addAll(tagsManager.getPredefinedTagNames()); - currentTagNames = new ArrayList(tagNamesSet); + tagNamesMap.putAll(tagsManager.getUserTagNamesMap()); + tagNamesMap.putAll(tagsManager.getPredefinedTagNamesMap()); + tagNamesMap.putAll(tagsManager.getTagNamesInUseMap()); } catch (TskCoreException ex) { Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } - if (null != currentTagNames && currentTagNames.isEmpty()) { + if (null != tagNamesMap && tagNamesMap.isEmpty()) { tagCombo.addItem(NO_TAG_NAMES_MESSAGE); } else { - for (TagName tagName : currentTagNames) { - tagNames.put(tagName.getDisplayName(), tagName); - tagCombo.addItem(tagName.getDisplayName()); + for (String tagDisplayName : tagNamesMap.keySet()) { + tagCombo.addItem(tagDisplayName); } } @@ -247,7 +242,18 @@ public class GetTagNameAndCommentDialog extends JDialog { }// //GEN-END:initComponents private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - tagNameAndComment = new TagNameAndComment(tagNames.get((String) tagCombo.getSelectedItem()), commentText.getText()); + String tagDisplayName = (String) tagCombo.getSelectedItem(); + TagName tagNameFromCombo = tagNamesMap.get(tagDisplayName); + if (tagNameFromCombo == null) { + try { + tagNameFromCombo = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName); + } catch (TagsManager.TagNameAlreadyExistsException ex) { + Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, tagDisplayName + " already exists in database.", ex); //NON-NLS + } catch (TskCoreException ex) { + Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS + } + } + tagNameAndComment = new TagNameAndComment(tagNameFromCombo, commentText.getText()); dispose(); }//GEN-LAST:event_okButtonActionPerformed @@ -264,7 +270,7 @@ public class GetTagNameAndCommentDialog extends JDialog { private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed TagName newTagName = GetTagNameDialog.doDialog(this); if (newTagName != null) { - tagNames.put(newTagName.getDisplayName(), newTagName); + tagNamesMap.put(newTagName.getDisplayName(), newTagName); tagCombo.addItem(newTagName.getDisplayName()); tagCombo.setSelectedItem(newTagName.getDisplayName()); } diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index f055469fef..5386af785a 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -22,10 +22,9 @@ import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Set; -import java.util.TreeSet; +import java.util.Map; +import java.util.TreeMap; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.ActionMap; @@ -47,7 +46,7 @@ import org.sleuthkit.datamodel.TskCoreException; public class GetTagNameDialog extends JDialog { private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS - private final HashMap tagNames = new HashMap<>(); + private final Map tagNamesMap = new TreeMap<>(); private TagName tagName = null; /** @@ -98,26 +97,16 @@ public class GetTagNameDialog extends JDialog { // Get the current set of tag names and hash them for a speedy lookup in // case the user chooses an existing tag name from the tag names table. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - List currentTagNames = null; try { - Set tagNamesSet = new TreeSet<>(); - tagNamesSet.addAll(tagsManager.getUserTagNames()); - tagNamesSet.addAll(tagsManager.getTagNamesInUse()); - tagNamesSet.addAll(tagsManager.getPredefinedTagNames()); - currentTagNames = new ArrayList(tagNamesSet); + tagNamesMap.putAll(tagsManager.getUserTagNamesMap()); + tagNamesMap.putAll(tagsManager.getPredefinedTagNamesMap()); + tagNamesMap.putAll(tagsManager.getTagNamesInUseMap()); } catch (TskCoreException ex) { Logger.getLogger(GetTagNameDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } - if (null != currentTagNames) { - for (TagName name : currentTagNames) { - this.tagNames.put(name.getDisplayName(), name); - } - } else { - currentTagNames = new ArrayList<>(); - } // Populate the tag names table. - tagsTable.setModel(new TagsTableModel(currentTagNames)); + tagsTable.setModel(new TagsTableModel(new ArrayList(tagNamesMap.keySet()))); tagsTable.setTableHeader(null); tagsTable.setCellSelectionEnabled(false); tagsTable.setFocusable(false); @@ -130,17 +119,17 @@ public class GetTagNameDialog extends JDialog { private class TagsTableModel extends AbstractTableModel { - private final ArrayList tagNames = new ArrayList<>(); + private final ArrayList tagDisplayNames = new ArrayList<>(); - TagsTableModel(List tagNames) { - for (TagName tagName : tagNames) { - this.tagNames.add(tagName); + TagsTableModel(List tagDisplayNames) { + for (String tagDisplayName : tagDisplayNames) { + this.tagDisplayNames.add(tagDisplayName); } } @Override public int getRowCount() { - return tagNames.size(); + return tagDisplayNames.size(); } @Override @@ -155,7 +144,7 @@ public class GetTagNameDialog extends JDialog { @Override public String getValueAt(int rowIndex, int columnIndex) { - return tagNames.get(rowIndex).getDisplayName(); + return tagDisplayNames.get(rowIndex); } } @@ -306,7 +295,7 @@ public class GetTagNameDialog extends JDialog { NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalCharsErr"), JOptionPane.ERROR_MESSAGE); } else { - tagName = tagNames.get(tagDisplayName); + tagName = tagNamesMap.get(tagDisplayName); if (tagName == null) { try { tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName); @@ -321,7 +310,7 @@ public class GetTagNameDialog extends JDialog { JOptionPane.ERROR_MESSAGE); tagName = null; } catch (TagsManager.TagNameAlreadyExistsException ex) { - Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS + Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, tagDisplayName + " already exists in database.", ex); //NON-NLS JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagNameAlreadyDef.msg", diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index 8fbcb50595..ed80e8696e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -9,9 +9,6 @@ TagsManager.deleteContentTag.noCaseWarning=Failed to publish content tag deleted TagsManager.addBlackboardArtifactTag.noCaseWarning=Failed to publish new blackboard artifact tag event. There is no case open. TagsManager.deleteBlackboardArtifactTag.noCaseWarning=Failed to publish blackboard artifact tag deleted event. There is no case open. Blackboard.unableToIndexArtifact.error.msg=Unable to index blackboard artifact {0} -TagsManagerOptionsPanel.addTagNameButton.empty=Tag name text is empty. -TagsManagerOptionsPanel.addTagNameButton.containInvalidCharacter=Tag name may not contain any of the following symbols\: \\ \: * ? " < > | , ; -TagsManagerOptionsPanel.addTagNameButton.alreadyExists=Tag name already exists. TagNamesSettingsPanel.deleteTagNameButton.text=Delete Tag Name TagNamesSettingsPanel.tagNamesListLabel.text=Tag names: NewUserTagNameDialog.tagNameTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java index d6f4953824..91a24e7ad2 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java @@ -21,7 +21,9 @@ package org.sleuthkit.autopsy.casemodule.services; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import javax.swing.DefaultListModel; import javax.swing.JOptionPane; import javax.swing.event.ListSelectionEvent; @@ -253,6 +255,10 @@ final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsP */ private void updateTagNamesListModel() { tagNamesListModel.clear(); + Set tagNameSet = new HashSet<>(); + tagNameSet.addAll(tagNames); + tagNames.clear(); + tagNames.addAll(tagNameSet); Collections.sort(tagNames); for (UserTagName tagName : tagNames) { tagNamesListModel.addElement(tagName); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 9cd7a72183..7798d3cf3a 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -25,6 +25,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.logging.Level; import org.openide.util.NbBundle; @@ -80,34 +81,55 @@ public class TagsManager implements Closeable { } /** - * Gets a list of all user tag names from the preference file. + * Gets a mapping of user tag name display names to TagName DTOs if they + * have been added to the database. Otherwise, the display name maps to + * null. * - * @return A list, possibly empty, of TagName data transfer objects (DTOs). + * @return A map of String display name to TagName DTO, TagName may be null */ - public synchronized List getUserTagNames() { + public synchronized Map getUserTagNamesMap() { lazyLoadExistingTagNames(); - List tagNameList = new ArrayList<>(); + Map tagNamesMap = new HashMap<>(); String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); if (null != setting && !setting.isEmpty()) { List tagNameTuples = Arrays.asList(setting.split(";")); for (String tagNameTuple : tagNameTuples) { String[] tagNameAttributes = tagNameTuple.split(","); - tagNameList.add(uniqueTagNames.get(tagNameAttributes[0])); + tagNamesMap.put(tagNameAttributes[0], uniqueTagNames.get(tagNameAttributes[0])); } } - return tagNameList; + return tagNamesMap; + } + + /** + * Gets a mapping of predefined tag names to their TagName DTOs. Currently + * only for the bookmark tag. + * + * @return A map of String display name to TagName DTO + */ + public synchronized Map getPredefinedTagNamesMap() { + Map tagNamesMap = new HashMap<>(); + TagName bookmarkTagName = uniqueTagNames.get(NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text")); + tagNamesMap.put(NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"), bookmarkTagName); + return tagNamesMap; } /** - * Gets a list of all predefined tag names. + * Gets a mapping of the display names of predefined tag names and tag names + * that are in use to their TagName DTOs. * - * @return A list of TagName data transfer objects (DTOs). + * @return A map of String display name to TagName DTO + * + * @throws TskCoreException If there is an error reading from the case + * database. */ - public synchronized List getPredefinedTagNames() { - lazyLoadExistingTagNames(); - List tagNameList = new ArrayList<>(); - tagNameList.add(uniqueTagNames.get(NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"))); - return tagNameList; + public synchronized Map getTagNamesInUseMap() throws TskCoreException { + List tagNames = getTagNamesInUse(); + Map tagNamesMap = new HashMap<>(); + for (TagName tagName : tagNames) { + tagNamesMap.put(tagName.getDisplayName(), tagName); + } + return tagNamesMap; } /** @@ -136,7 +158,8 @@ public class TagsManager implements Closeable { */ public synchronized boolean tagNameExists(String tagDisplayName) { lazyLoadExistingTagNames(); - return uniqueTagNames.containsKey(tagDisplayName); + return uniqueTagNames.containsKey(tagDisplayName) && + (uniqueTagNames.get(tagDisplayName) != null); } /** @@ -201,31 +224,28 @@ public class TagsManager implements Closeable { } lazyLoadExistingTagNames(); - + /* * It is possible user is trying to add back a tag after having deleted - * it. + * it. It is also possible a user tag name was never added to the + * database. */ if (uniqueTagNames.containsKey(displayName)) { - TagName existingTagName = uniqueTagNames.get(displayName); - long count = getContentTagsCountByTagName(existingTagName) + getBlackboardArtifactTagsCountByTagName(existingTagName); - if (count == 0) { - addNewTagNameToTagsSettings(existingTagName); - return existingTagName; - } else { - throw new TagNameAlreadyExistsException(); + if (uniqueTagNames.get(displayName) != null) { + TagName existingTagName = uniqueTagNames.get(displayName); + long count = getContentTagsCountByTagName(existingTagName) + getBlackboardArtifactTagsCountByTagName(existingTagName); + if (count == 0) { + addNewTagNameToTagsSettings(existingTagName); + return existingTagName; + } else { + throw new TagNameAlreadyExistsException(); + } } } - - /* - * Add the tag name to the case. - */ + TagName newTagName = caseDb.addTagName(displayName, description, color); uniqueTagNames.put(newTagName.getDisplayName(), newTagName); - /* - * Add the tag name to the tags settings. - */ addNewTagNameToTagsSettings(newTagName); return newTagName; @@ -668,12 +688,7 @@ public class TagsManager implements Closeable { for (String tagNameTuple : tagNameTuples) { String[] tagNameAttributes = tagNameTuple.split(","); if (!uniqueTagNames.containsKey(tagNameAttributes[0])) { - try { - TagName tagName = caseDb.addTagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2])); - uniqueTagNames.put(tagName.getDisplayName(), tagName); - } catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add saved tag name " + tagNameAttributes[0], ex); //NON-NLS - } + uniqueTagNames.put(tagNameAttributes[0], null); } } } @@ -704,12 +719,7 @@ public class TagsManager implements Closeable { lazyLoadExistingTagNames(); for (UserTagName utn : userTagNames) { if (!uniqueTagNames.containsKey(utn.getDisplayName())) { - try { - TagName tagName = caseDb.addTagName(utn.getDisplayName(), utn.getDescription(), TagName.HTML_COLOR.getColorByName(utn.getColorName())); - uniqueTagNames.put(tagName.getDisplayName(), tagName); - } catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add saved tag name " + utn.getDisplayName(), ex); //NON-NLS - } + uniqueTagNames.put(utn.getDisplayName(), null); } } } From 1c65426cfbd51ce965290a244699acd195018492 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Thu, 29 Sep 2016 13:03:31 +0200 Subject: [PATCH 42/54] simplify visitor --- .../autopsy/datamodel/_private/Accounts.java | 10 +- .../directorytree/DataResultFilterNode.java | 185 +----------------- 2 files changed, 6 insertions(+), 189 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java index 070be60da1..0aced63213 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java @@ -315,7 +315,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { private final String accountTypeName; - public DefaultAccountFactory(String accountTypeName) { + private DefaultAccountFactory(String accountTypeName) { this.accountTypeName = accountTypeName; } @@ -380,10 +380,9 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } /** - * Node for an account type. + * Node for the Credit Card account type. * - * NOTE: currently hard coded to work for Credit Card only - */ + */ final public class CreditCardNumberAccountTypeNode extends DisplayableItemNode { /** @@ -1122,8 +1121,9 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { @Override public void actionPerformed(ActionEvent e) { - super.actionPerformed(e); + Collection targets = Utilities.actionsGlobalContext().lookupAll(Node.class); + super.actionPerformed(e); System.out.println(targets); // //find the node to select after the target is removed from the UI // List siblings = Arrays.asList(target.getParentNode().getChildren().getNodes()); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 5d7981b677..ec66a5d4c7 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -37,38 +37,15 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; -import org.sleuthkit.autopsy.datamodel._private.Accounts; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; -import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode; -import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode; import org.sleuthkit.autopsy.datamodel.DirectoryNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; -import org.sleuthkit.autopsy.datamodel.EmailExtracted; -import org.sleuthkit.autopsy.datamodel.EmailExtracted.AccountNode; -import org.sleuthkit.autopsy.datamodel.EmailExtracted.FolderNode; -import org.sleuthkit.autopsy.datamodel.ExtractedContent; -import org.sleuthkit.autopsy.datamodel.ExtractedContent.TypeNode; import org.sleuthkit.autopsy.datamodel.FileNode; -import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode; -import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode; -import org.sleuthkit.autopsy.datamodel.FileTypeNode; -import org.sleuthkit.autopsy.datamodel.FileTypesNode; -import org.sleuthkit.autopsy.datamodel.HashsetHits; -import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetNameNode; -import org.sleuthkit.autopsy.datamodel.ImageNode; -import org.sleuthkit.autopsy.datamodel.InterestingHits; -import org.sleuthkit.autopsy.datamodel.KeywordHits; -import org.sleuthkit.autopsy.datamodel.KeywordHits.ListNode; -import org.sleuthkit.autopsy.datamodel.KeywordHits.TermNode; import org.sleuthkit.autopsy.datamodel.LayoutFileNode; import org.sleuthkit.autopsy.datamodel.LocalFileNode; -import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode; -import org.sleuthkit.autopsy.datamodel.RecentFilesNode; import org.sleuthkit.autopsy.datamodel.Reports; -import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode; -import org.sleuthkit.autopsy.datamodel.VolumeNode; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -301,112 +278,12 @@ public class DataResultFilterNode extends FilterNode { */ private class GetPreferredActionsDisplayableItemNodeVisitor extends DisplayableItemNodeVisitor.Default { - @Override - public AbstractAction visit(ImageNode in) { - return openChild(in); - } - - @Override - public AbstractAction visit(VolumeNode vn) { - return openChild(vn); - } - - @Override - public AbstractAction visit(ExtractedContent.RootNode ecn) { - return openChild(ecn); - } - - @Override - public AbstractAction visit(KeywordHits.RootNode khrn) { - return openChild(khrn); - } - - @Override - public AbstractAction visit(HashsetHits.RootNode hhrn) { - return openChild(hhrn); - } - - @Override - public AbstractAction visit(HashsetNameNode hhsn) { - return openChild(hhsn); - } - - @Override - public AbstractAction visit(InterestingHits.RootNode iarn) { - return openChild(iarn); - } - - @Override - public AbstractAction visit(InterestingHits.SetNameNode iasn) { - return openChild(iasn); - } - - @Override - public AbstractAction visit(EmailExtracted.RootNode eern) { - return openChild(eern); - } - - @Override - public AbstractAction visit(AccountNode eean) { - return openChild(eean); - } - - @Override - public AbstractAction visit(FolderNode eefn) { - return openChild(eefn); - } - - @Override - public AbstractAction visit(RecentFilesNode rfn) { - return openChild(rfn); - } - - @Override - public AbstractAction visit(DeletedContentsNode dcn) { - return openChild(dcn); - } - - @Override - public AbstractAction visit(DeletedContentNode dcn) { - return openChild(dcn); - } - - @Override - public AbstractAction visit(FileSizeRootNode fsrn) { - return openChild(fsrn); - } - - @Override - public AbstractAction visit(FileSizeNode fsn) { - return openChild(fsn); - } - @Override public AbstractAction visit(BlackboardArtifactNode ban) { return new ViewContextAction( NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewInDir.text"), ban); } - @Override - public AbstractAction visit(TypeNode atn) { - return openChild(atn); - } - - @Override - public AbstractAction visit(Tags.TagNameNode node) { - return openChild(node); - } - - @Override - public AbstractAction visit(Tags.ContentTagTypeNode node) { - return openChild(node); - } - - @Override - public AbstractAction visit(Tags.BlackboardArtifactTagTypeNode node) { - return openChild(node); - } - @Override public AbstractAction visit(DirectoryNode dn) { if (dn.getDisplayName().equals(DirectoryNode.DOTDOTDIR)) { @@ -418,11 +295,6 @@ public class DataResultFilterNode extends FilterNode { } } - @Override - public AbstractAction visit(VirtualDirectoryNode ldn) { - return openChild(ldn); - } - @Override public AbstractAction visit(FileNode fn) { if (fn.hasContentChildren()) { @@ -441,69 +313,14 @@ public class DataResultFilterNode extends FilterNode { } } - @Override - public AbstractAction visit(FileTypeNode fsfn) { - return openChild(fsfn); - } - - @Override - public AbstractAction visit(FileTypesNode sfn) { - return openChild(sfn); - } - - @Override - public AbstractAction visit(RecentFilesFilterNode rffn) { - return openChild(rffn); - } - - @Override - public AbstractAction visit(ListNode khsn) { - return openChild(khsn); - } - - @Override - public AbstractAction visit(TermNode khmln) { - return openChild(khmln); - } - @Override public AbstractAction visit(Reports.ReportNode reportNode) { return reportNode.getPreferredAction(); } - @Override - public AbstractAction visit(Accounts.BINNode node) { - return openChild(node); - } - - @Override - public AbstractAction visit(Accounts.FileWithCCNNode node) { - return openChild(node); - } - - @Override - public AbstractAction visit(Accounts.ByFileNode node) { - return openChild(node); - } - - @Override - public AbstractAction visit(Accounts.ByBINNode node) { - return openChild(node); - } - - @Override - public AbstractAction visit(Accounts.AccountsRootNode node) { - return openChild(node); - } - - @Override - public AbstractAction visit(Accounts.CreditCardNumberAccountTypeNode node) { - return openChild(node); - } - @Override protected AbstractAction defaultVisit(DisplayableItemNode c) { - return null; + return openChild(c); } /** From 371a85ffd14d426a15c7b6c524951116f6385368 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Fri, 30 Sep 2016 17:08:19 +0200 Subject: [PATCH 43/54] refactoring to maintain selection, but now it computes nodes too eagerly, and doesn't get the counts on the first update... --- .../autopsy/datamodel/_private/Accounts.java | 305 +++++++++++------- 1 file changed, 188 insertions(+), 117 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java index 0aced63213..6732878def 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java @@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.datamodel._private; import com.google.common.collect.Range; import com.google.common.collect.RangeMap; import com.google.common.collect.TreeRangeMap; +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -32,8 +34,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.Observable; -import java.util.Observer; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Function; @@ -76,7 +77,7 @@ import org.sleuthkit.datamodel.TskCoreException; * AutopsyVisitableItem for the Accounts section of the tree. All nodes, * factories, and data objects related to accounts are inner classes. */ -final public class Accounts extends Observable implements AutopsyVisitableItem { +final public class Accounts implements AutopsyVisitableItem { private static final Logger LOGGER = Logger.getLogger(Accounts.class.getName()); @@ -84,6 +85,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { final public static String NAME = Bundle.AccountsRootNode_name(); private SleuthkitCase skCase; + private final EventBus reviewStatusBus = new EventBus("ReviewStatusBus"); /** * Should rejected accounts be shown in the accounts section of the tree. @@ -121,15 +123,6 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { return showRejected ? " " : " AND blackboard_artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID(); //NON-NLS } - /** - * Notify all observers that something has changed, causing a refresh of the - * accounts section of the tree. - */ - private void update() { - setChanged(); - notifyObservers(); - } - /** * Gets a new Action that when invoked toggles showing rejected artifacts on * or off. @@ -146,23 +139,41 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { * * @param The type of keys used by this factory. */ - private abstract class ObservingChildFactory extends ChildFactory.Detachable implements Observer { + private abstract class ObservingChildren extends Children.Keys { @Override - public void update(Observable o, Object arg) { - refresh(true); + protected Node[] createNodes(X key) { + return new Node[]{createNodeForKey(key)}; } + abstract protected Node createNodeForKey(X key); + + /** + * + */ + abstract protected Collection createKeys(); + + /** + * Update the keys for this Children + */ + void updateKeys() { + setKeys(createKeys()); + } + + @Subscribe + abstract void handleReviewStatusChange(ReviewStatusChangeEvent event); + @Override protected void removeNotify() { super.removeNotify(); - Accounts.this.deleteObserver(this); + reviewStatusBus.unregister(ObservingChildren.this); } @Override protected void addNotify() { super.addNotify(); - Accounts.this.addObserver(this); + updateKeys(); + reviewStatusBus.register(ObservingChildren.this); } } @@ -176,7 +187,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { * Creates child nodes for each account type (currently hard coded to * make one for Credit Cards) */ - final private class AccountTypeFactory extends ObservingChildFactory { + final private class AccountTypeFactory extends ObservingChildren { /* * The pcl is in this class because it has the easiest mechanisms to @@ -205,7 +216,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { - Accounts.this.update(); + updateKeys(); } } catch (IllegalStateException notUsed) { // Case is closed, do nothing. @@ -220,7 +231,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { */ try { Case.getCurrentCase(); - Accounts.this.update(); + updateKeys(); } catch (IllegalStateException notUsed) { // Case is closed, do nothing. } @@ -234,10 +245,18 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } }; + @Subscribe @Override + public void handleReviewStatusChange(ReviewStatusChangeEvent event) { + updateKeys(); + } - protected boolean createKeys(List list) { - + /** + * + */ + @Override + protected List createKeys() { + List list = new ArrayList<>(); try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery( "SELECT DISTINCT blackboard_attributes.value_text as account_type " + " FROM blackboard_attributes " @@ -249,9 +268,8 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } catch (TskCoreException | SQLException ex) { Exceptions.printStackTrace(ex); - return false; } - return true; + return list; } @Override @@ -285,13 +303,13 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { IngestManager.getInstance().addIngestModuleEventListener(pcl); Case.addPropertyChangeListener(pcl); super.addNotify(); - Accounts.this.update(); + updateKeys(); } } public AccountsRootNode() { super(Children.LEAF, Lookups.singleton(Accounts.this)); - setChildren(Children.create(new AccountTypeFactory(), true)); + setChildren(Children.createLazy(AccountTypeFactory::new)); setName(Accounts.NAME); setDisplayName(Bundle.Accounts_RootNode_displayName()); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/accounts.png"); //NON-NLS @@ -306,7 +324,6 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); } - } final public class DefaultAccountTypeNode extends DisplayableItemNode { @@ -374,7 +391,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { /** * Enum for the children under the credit card AccountTypeNode. */ - private enum CreditCardViewMode { + enum CreditCardViewMode { BY_FILE, BY_BIN; } @@ -382,19 +399,28 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { /** * Node for the Credit Card account type. * - */ + */ final public class CreditCardNumberAccountTypeNode extends DisplayableItemNode { /** * ChildFactory that makes nodes for the different account organizations * (by file, by BIN) */ - final private class ViewModeFactory extends ObservingChildFactory { + final private class ViewModeFactory extends ObservingChildren { + @Subscribe @Override - protected boolean createKeys(List list) { + public void handleReviewStatusChange(ReviewStatusChangeEvent event) { + updateKeys(); + } + + /** + * + */ + @Override + protected List createKeys() { list.addAll(Arrays.asList(CreditCardViewMode.values())); - return true; + return list; } @Override @@ -412,7 +438,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { private CreditCardNumberAccountTypeNode() { super(Children.LEAF); - setChildren(Children.create(new ViewModeFactory(), true)); + setChildren(new ViewModeFactory()); setName(Account.Type.CREDIT_CARD.getDisplayName()); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS } @@ -432,15 +458,24 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { * Node that is the root of the "by file" accounts tree. Its children are * FileWithCCNNodes. */ - final public class ByFileNode extends DisplayableItemNode implements Observer { + final public class ByFileNode extends DisplayableItemNode { /** * Factory for the children of the ByFiles Node. */ - final private class FileWithCCNFactory extends ObservingChildFactory { + final private class FileWithCCNFactory extends ObservingChildren { + @Subscribe @Override - protected boolean createKeys(List list) { + public void handleReviewStatusChange(ReviewStatusChangeEvent event) { + updateKeys(); + } + + /** + * + */ + @Override + protected List createKeys() { String query = "SELECT blackboard_artifacts.obj_id," //NON-NLS + " solr_attribute.value_text AS solr_document_id, " //NON-NLS @@ -469,9 +504,9 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } catch (TskCoreException | SQLException ex) { LOGGER.log(Level.SEVERE, "Error querying for files with ccn hits.", ex); //NON-NLS - return false; + } - return true; + return list; } @Override @@ -490,31 +525,22 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { return null; } } - - @Override - public void update(Observable o, Object arg) { - refresh(true); - } } - private final FileWithCCNFactory fileFactory; private ByFileNode() { super(Children.LEAF); - fileFactory = new FileWithCCNFactory(); - setChildren(Children.create(fileFactory, true)); + setChildren(Children.createLazy(FileWithCCNFactory::new)); setName("By File"); //NON-NLS updateDisplayName(); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon.png"); //NON-NLS - Accounts.this.addObserver(this); + reviewStatusBus.register(this); } @NbBundle.Messages({ "# {0} - number of children", "Accounts.ByFileNode.displayName=By File ({0})"}) private void updateDisplayName() { - ArrayList keys = new ArrayList<>(); - fileFactory.createKeys(keys); - setDisplayName(Bundle.Accounts_ByFileNode_displayName(keys.size())); + setDisplayName(Bundle.Accounts_ByFileNode_displayName(getChildren().getNodesCount(true))); } @Override @@ -527,8 +553,8 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { return v.visit(this); } - @Override - public void update(Observable o, Object arg) { + @Subscribe + public void handleReviewStatusChange(ReviewStatusChangeEvent event) { updateDisplayName(); } } @@ -537,15 +563,24 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { * Node that is the root of the "By BIN" accounts tree. Its children are * BINNodes. */ - final public class ByBINNode extends DisplayableItemNode implements Observer { + final public class ByBINNode extends DisplayableItemNode { /** * Factory that generates the children of the ByBin node. */ - final private class BINFactory extends ObservingChildFactory { + final private class BINFactory extends ObservingChildren { + @Subscribe @Override - protected boolean createKeys(List list) { + public void handleReviewStatusChange(ReviewStatusChangeEvent event) { + updateKeys(); + } + + /** + * + */ + @Override + protected List createKeys() { RangeMap ranges = TreeRangeMap.create(); String query @@ -581,9 +616,9 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { ranges.asMapOfRanges().values().forEach(list::add); } catch (TskCoreException | SQLException ex) { LOGGER.log(Level.SEVERE, "Error querying for BINs.", ex); //NON-NLS - return false; + } - return true; + return list; } @Override @@ -592,25 +627,20 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } - private final BINFactory binFactory; - private ByBINNode() { super(Children.LEAF); - binFactory = new BINFactory(); - setChildren(Children.create(binFactory, true)); + setChildren(Children.createLazy(BINFactory::new)); setName("By BIN"); //NON-NLS updateDisplayName(); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/bank.png"); //NON-NLS - Accounts.this.addObserver(this); + reviewStatusBus.register(this); } @NbBundle.Messages({ "# {0} - number of children", "Accounts.ByBINNode.displayName=By BIN ({0})"}) private void updateDisplayName() { - ArrayList keys = new ArrayList<>(); - binFactory.createKeys(keys); - setDisplayName(Bundle.Accounts_ByBINNode_displayName(keys.size())); + setDisplayName(Bundle.Accounts_ByBINNode_displayName(getChildren().getNodesCount(true))); } @Override @@ -623,8 +653,8 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { return v.visit(this); } - @Override - public void update(Observable o, Object arg) { + @Subscribe + public void handleReviewStatusChange(ReviewStatusChangeEvent event) { updateDisplayName(); } } @@ -636,6 +666,35 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { @Immutable final private static class FileWithCCN { + @Override + public int hashCode() { + int hash = 5; + hash = 89 * hash + (int) (this.objID ^ (this.objID >>> 32)); + hash = 89 * hash + Objects.hashCode(this.solrDocumentId); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final FileWithCCN other = (FileWithCCN) obj; + if (this.objID != other.objID) { + return false; + } + if (!Objects.equals(this.solrDocumentId, other.solrDocumentId)) { + return false; + } + return true; + } + private final long objID; private final String solrDocumentId; private final List artifactIDS; @@ -785,15 +844,24 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } - final public class BINNode extends DisplayableItemNode implements Observer { + final public class BINNode extends DisplayableItemNode { /** * Creates the nodes for the accounts of a given type */ - final private class CreditCardNumberFactory extends ObservingChildFactory { + final private class CreditCardNumberFactory extends ObservingChildren { + @Subscribe @Override - protected boolean createKeys(List list) { + public void handleReviewStatusChange(ReviewStatusChangeEvent event) { + updateKeys(); + } + + /** + * + */ + @Override + protected List createKeys() { String query = "SELECT blackboard_artifacts.artifact_id " //NON-NLS @@ -811,9 +879,9 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } catch (TskCoreException | SQLException ex) { LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS - return false; + } - return true; + return list; } @Override @@ -832,26 +900,26 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { } } private final BinResult bin; - private final CreditCardNumberFactory accountFactory; +// private final CreditCardNumberFactory accountFactory; private BINNode(BinResult bin) { super(Children.LEAF); + setChildren(Children.createLazy(CreditCardNumberFactory::new)); this.bin = bin; - accountFactory = new CreditCardNumberFactory(); - setChildren(Children.create(accountFactory, true)); setName(getBinRangeString()); updateDisplayName(); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/bank.png"); //NON-NLS - Accounts.this.addObserver(this); + reviewStatusBus.register(this); } - @Override - public void update(Observable o, Object arg) { + @Subscribe + public void handleReviewStatusChange(ReviewStatusChangeEvent event) { updateDisplayName(); } private void updateDisplayName() { - setDisplayName(getBinRangeString() + " (" + bin.getCount() + ")"); //NON-NLS + + setDisplayName(getBinRangeString() + " (" + getChildren().getNodesCount(true) + ")"); //NON-NLS } private String getBinRangeString() { @@ -944,6 +1012,35 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { @Immutable final static private class BinResult implements CreditCards.BankIdentificationNumber { + @Override + public int hashCode() { + int hash = 3; + hash = 97 * hash + this.binEnd; + hash = 97 * hash + this.binStart; + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final BinResult other = (BinResult) obj; + if (this.binEnd != other.binEnd) { + return false; + } + if (this.binStart != other.binStart) { + return false; + } + return true; + } + /** * The number of accounts with this BIN */ @@ -1077,7 +1174,7 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { @Override public void actionPerformed(ActionEvent e) { showRejected = !showRejected; - Accounts.this.update(); + reviewStatusBus.post(new ReviewStatusChangeEvent(Collections.emptySet(), null)); } } @@ -1093,14 +1190,15 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { @Override public void actionPerformed(ActionEvent e) { - Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).forEach(artifact -> { + final Collection lookupAll = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); + lookupAll.forEach(artifact -> { try { skCase.setReviewStatus(artifact, newStatus); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error changing artifact review status.", ex); //NON-NLS } }); - Accounts.this.update(); + reviewStatusBus.post(new ReviewStatusChangeEvent(lookupAll, newStatus)); } } @@ -1118,43 +1216,16 @@ final public class Accounts extends Observable implements AutopsyVisitableItem { private RejectAccounts() { super(Bundle.RejectAccountsAction_name(), BlackboardArtifact.ReviewStatus.REJECTED); } + } - @Override - public void actionPerformed(ActionEvent e) { + class ReviewStatusChangeEvent { - Collection targets = Utilities.actionsGlobalContext().lookupAll(Node.class); - super.actionPerformed(e); - System.out.println(targets); -// //find the node to select after the target is removed from the UI -// List siblings = Arrays.asList(target.getParentNode().getChildren().getNodes()); -// if (siblings.size() <= 1) { -// Accounts.this.update(); -// } else { -// final int indexOf = siblings.indexOf(target); -// -// final Node sibling = indexOf < siblings.size() - 1 // if it is not the last in the list -// ? siblings.get(indexOf + 1) //select the next element -// : siblings.get(indexOf - 1);//else select the previous element -// String nodeToSelectName = sibling.getName(); -// Accounts.this.update(); -// -// if (showRejected == false && siblings.size() > 1) { -// SwingUtilities.invokeLater(() -> { -// final DirectoryTreeTopComponent directoryTree = DirectoryTreeTopComponent.findInstance(); -// final DataResultTopComponent directoryListing = directoryTree.getDirectoryListing(); -// final Node rootNode = directoryListing.getRootNode(); -// -// Node child = NodeOp.findChild(rootNode, nodeToSelectName); -// -// try { -// directoryTree.getExplorerManager().setSelectedNodes(new Node[]{child.getParentNode()}); -// directoryListing.setSelectedNodes(new Node[]{child.getParentNode()}); -// } catch (PropertyVetoException ex) { -// Exceptions.printStackTrace(ex); -// } -// }); -// } -// } + Collection artifacts; + BlackboardArtifact.ReviewStatus newReviewStatus; + + public ReviewStatusChangeEvent(Collection artifacts, BlackboardArtifact.ReviewStatus newReviewStatus) { + this.artifacts = artifacts; + this.newReviewStatus = newReviewStatus; } } } From f380dbc42911ef71fbca46f644fb2cabd80ff254 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 30 Sep 2016 11:22:58 -0400 Subject: [PATCH 44/54] Fix transaction error handling in FileManager --- .../casemodule/services/FileManager.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java index e10e3d7ad5..57a6712282 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode; import org.sleuthkit.autopsy.ingest.IngestServices; @@ -43,6 +44,7 @@ import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.datamodel.LocalFilesDataSource; import org.sleuthkit.datamodel.TskDataException; import org.apache.commons.lang3.StringUtils; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.CarvingResult; import org.sleuthkit.datamodel.TskData; @@ -53,6 +55,7 @@ import org.sleuthkit.datamodel.TskData; */ public class FileManager implements Closeable { + private static final Logger LOGGER = Logger.getLogger(FileManager.class.getName()); private SleuthkitCase caseDb; /** @@ -343,7 +346,7 @@ public class FileManager implements Closeable { } return caseDb.addCarvedFiles(carvingResult); } - + /** * Interface for receiving a notification for each file or directory added * to the case database by a FileManager add files operation. @@ -427,7 +430,11 @@ public class FileManager implements Closeable { } catch (TskCoreException ex) { if (null != trans) { - trans.rollback(); + try { + trans.rollback(); + } catch (TskCoreException ex2) { + LOGGER.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2); + } } throw ex; } @@ -506,7 +513,7 @@ public class FileManager implements Closeable { * @throws TskCoreException If there is a problem completing a database * operation. */ - private AbstractFile addLocalFile(CaseDbTransaction trans, VirtualDirectory parentDirectory, java.io.File localFile, + private AbstractFile addLocalFile(CaseDbTransaction trans, VirtualDirectory parentDirectory, java.io.File localFile, TskData.EncodingType encodingType, FileAddProgressUpdater progressUpdater) throws TskCoreException { if (localFile.isDirectory()) { /* @@ -542,7 +549,7 @@ public class FileManager implements Closeable { public synchronized void close() throws IOException { caseDb = null; } - + /** * Adds a set of local/logical files and/or directories to the case database * as data source. @@ -624,7 +631,7 @@ public class FileManager implements Closeable { } return caseDb.addCarvedFiles(filesToAdd); } - + /** * Adds a derived file to the case. * @@ -652,7 +659,7 @@ public class FileManager implements Closeable { * * @throws TskCoreException if there is a problem adding the file to the * case database. - * + * * @Deprecated Use the version with explicit EncodingType instead */ @Deprecated @@ -663,10 +670,10 @@ public class FileManager implements Closeable { boolean isFile, AbstractFile parentFile, String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException { - return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, parentFile, + return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, parentFile, rederiveDetails, toolName, toolVersion, otherDetails, TskData.EncodingType.NONE); } - + /** * Adds a file or directory of logical/local files data source to the case * database, recursively adding the contents of directories. @@ -686,7 +693,7 @@ public class FileManager implements Closeable { * * @throws TskCoreException If there is a problem completing a database * operation. - * + * * @Deprecated Use the version with explicit EncodingType instead */ @Deprecated From 32e35011265a68ef6a55b9b76072e00c5459fe0f Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 30 Sep 2016 15:27:08 -0400 Subject: [PATCH 45/54] 2025: disable cmd file context menu of 'open in external viewer' --- .../sleuthkit/autopsy/directorytree/ExternalViewerAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerAction.java index 4a904042c7..a52dd2cbf5 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerAction.java @@ -40,7 +40,7 @@ public class ExternalViewerAction extends AbstractAction { private final static Logger logger = Logger.getLogger(ExternalViewerAction.class.getName()); private org.sleuthkit.datamodel.AbstractFile fileObject; - final static String[] EXECUTABLE_EXT = {".exe", ".dll", ".com", ".bat", ".msi", ".reg", ".scr"}; //NON-NLS + final static String[] EXECUTABLE_EXT = {".exe", ".dll", ".com", ".bat", ".msi", ".reg", ".scr", ".cmd"}; //NON-NLS public ExternalViewerAction(String title, Node fileNode) { super(title); From f056196db1157ec66272071ff0ef69bbf59d2148 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Sun, 2 Oct 2016 22:12:27 +0200 Subject: [PATCH 46/54] WIP --- .../autopsy/datamodel/_private/{ => accounts}/Accounts.java | 0 .../autopsy/datamodel/_private/{ => accounts}/BINRange.java | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Core/src/org/sleuthkit/autopsy/datamodel/_private/{ => accounts}/Accounts.java (100%) rename Core/src/org/sleuthkit/autopsy/datamodel/_private/{ => accounts}/BINRange.java (100%) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/accounts/Accounts.java similarity index 100% rename from Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java rename to Core/src/org/sleuthkit/autopsy/datamodel/_private/accounts/Accounts.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/BINRange.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/accounts/BINRange.java similarity index 100% rename from Core/src/org/sleuthkit/autopsy/datamodel/_private/BINRange.java rename to Core/src/org/sleuthkit/autopsy/datamodel/_private/accounts/BINRange.java From 476ec23eaf32afd356253f83faf5306e59b17290 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Sun, 2 Oct 2016 22:47:19 +0200 Subject: [PATCH 47/54] remove accounts package --- .../autopsy/datamodel/AbstractContentChildren.java | 11 ++++++----- .../datamodel/_private/{accounts => }/Accounts.java | 8 ++++++-- .../datamodel/_private/{accounts => }/BINRange.java | 0 .../directorytree/DirectoryTreeTopComponent.java | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) rename Core/src/org/sleuthkit/autopsy/datamodel/_private/{accounts => }/Accounts.java (99%) rename Core/src/org/sleuthkit/autopsy/datamodel/_private/{accounts => }/BINRange.java (100%) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index 86f247395e..891361ccec 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -18,15 +18,16 @@ */ package org.sleuthkit.autopsy.datamodel; -import org.sleuthkit.autopsy.datamodel._private.Accounts; -import org.sleuthkit.autopsy.datamodel._private.FileTypeExtensionFilters; -import org.sleuthkit.autopsy.datamodel._private.RecentFiles; -import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; -import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children.Keys; import org.openide.nodes.Node; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor; +import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem; +import org.sleuthkit.autopsy.datamodel._private.FileTypeExtensionFilters; +import org.sleuthkit.autopsy.datamodel._private.RecentFiles; +import org.sleuthkit.autopsy.datamodel._private.Accounts; +import org.sleuthkit.autopsy.datamodel._private.Accounts.AccountsRootNode; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.Directory; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/datamodel/_private/accounts/Accounts.java rename to Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java index 6732878def..f635845e77 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/_private/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java @@ -419,8 +419,8 @@ final public class Accounts implements AutopsyVisitableItem { */ @Override protected List createKeys() { - list.addAll(Arrays.asList(CreditCardViewMode.values())); - return list; + return Arrays.asList(CreditCardViewMode.values()); + } @Override @@ -476,6 +476,7 @@ final public class Accounts implements AutopsyVisitableItem { */ @Override protected List createKeys() { + List list = new ArrayList<>(); String query = "SELECT blackboard_artifacts.obj_id," //NON-NLS + " solr_attribute.value_text AS solr_document_id, " //NON-NLS @@ -581,6 +582,8 @@ final public class Accounts implements AutopsyVisitableItem { */ @Override protected List createKeys() { + List list = new ArrayList<>(); + RangeMap ranges = TreeRangeMap.create(); String query @@ -862,6 +865,7 @@ final public class Accounts implements AutopsyVisitableItem { */ @Override protected List createKeys() { + List list = new ArrayList<>(); String query = "SELECT blackboard_artifacts.artifact_id " //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/accounts/BINRange.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/BINRange.java similarity index 100% rename from Core/src/org/sleuthkit/autopsy/datamodel/_private/accounts/BINRange.java rename to Core/src/org/sleuthkit/autopsy/datamodel/_private/BINRange.java diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 6db8d46a6e..67cb358f6a 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -57,7 +57,6 @@ import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.datamodel._private.Accounts; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.DataSources; import org.sleuthkit.autopsy.datamodel.DataSourcesNode; @@ -71,6 +70,7 @@ import org.sleuthkit.autopsy.datamodel.RootContentChildren; import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.autopsy.datamodel.Views; import org.sleuthkit.autopsy.datamodel.ViewsNode; +import org.sleuthkit.autopsy.datamodel._private.Accounts; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; From 6e60f9a9788c5a1c2c0a2362a53196c54d3ddccd Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Sun, 2 Oct 2016 23:31:56 -0400 Subject: [PATCH 48/54] Changes to tags management (partial) --- .../autopsy/actions/AddTagAction.java | 9 +- .../actions/GetTagNameAndCommentDialog.java | 4 +- .../autopsy/actions/GetTagNameDialog.java | 4 +- .../services/TagNamesSettingsPanel.form | 5 +- .../services/TagNamesSettingsPanel.java | 153 ++--- .../autopsy/casemodule/services/TagType.java | 177 +++++ .../casemodule/services/TagsManager.java | 639 ++++++------------ .../casemodule/services/UserTagName.java | 86 --- 8 files changed, 453 insertions(+), 624 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/services/TagType.java delete mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/UserTagName.java diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index 3d394e9215..5a9d371b50 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-15 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -82,6 +82,8 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { // to be reworked. private class TagMenu extends JMenu { + private static final long serialVersionUID = 1L; + TagMenu() { super(getActionDisplayName()); @@ -89,10 +91,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); Map tagNamesMap = null; try { - tagNamesMap = new TreeMap<>(); - tagNamesMap.putAll(tagsManager.getUserTagNamesMap()); - tagNamesMap.putAll(tagsManager.getPredefinedTagNamesMap()); - tagNamesMap.putAll(tagsManager.getTagNamesInUseMap()); + tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap()); } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index fa2b1b1593..5a30a49c72 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -118,9 +118,7 @@ public class GetTagNameAndCommentDialog extends JDialog { // not exist in the database). TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); try { - tagNamesMap.putAll(tagsManager.getUserTagNamesMap()); - tagNamesMap.putAll(tagsManager.getPredefinedTagNamesMap()); - tagNamesMap.putAll(tagsManager.getTagNamesInUseMap()); + tagNamesMap.putAll(tagsManager.getDisplayNamesToTagNamesMap()); } catch (TskCoreException ex) { Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index 5386af785a..268512898e 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -98,9 +98,7 @@ public class GetTagNameDialog extends JDialog { // case the user chooses an existing tag name from the tag names table. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); try { - tagNamesMap.putAll(tagsManager.getUserTagNamesMap()); - tagNamesMap.putAll(tagsManager.getPredefinedTagNamesMap()); - tagNamesMap.putAll(tagsManager.getTagNamesInUseMap()); + tagNamesMap.putAll(tagsManager.getDisplayNamesToTagNamesMap()); } catch (TskCoreException ex) { Logger.getLogger(GetTagNameDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form index 4412f20274..5b896fdd36 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form @@ -138,8 +138,11 @@ - + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java index 91a24e7ad2..1a74acc4ae 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java @@ -1,39 +1,35 @@ /* -* Autopsy Forensic Browser -* -* Copyright 2011-2016 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. -*/ + * Autopsy Forensic Browser + * + * Copyright 2011-2016 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.sleuthkit.autopsy.casemodule.services; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashSet; -import java.util.List; import java.util.Set; +import java.util.TreeSet; 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 org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.ModuleSettings; /** * A panel to allow the user to create new tag names or to delete tag names that @@ -43,34 +39,26 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; */ final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsPanel { - private static final Logger logger = Logger.getLogger(TagNamesSettingsPanel.class.getName()); - - private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS - private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS - + private static final long serialVersionUID = 1L; private static final String DEFAULT_DESCRIPTION = ""; private static final String DEFAULT_COLOR_STRING = "NONE"; - - private DefaultListModel tagNamesListModel; - private List tagNames; + private final DefaultListModel tagTypesListModel; + private final Set tagTypes; /** * Creates new form TagsManagerOptionsPanel */ TagNamesSettingsPanel() { + tagTypesListModel = new DefaultListModel<>(); + tagTypes = new TreeSet<>(TagType.getCustomTagTypes()); initComponents(); customizeComponents(); } - + private void customizeComponents() { - tagNamesListModel = new DefaultListModel<>(); - tagNamesList.setModel(tagNamesListModel); - tagNames = new ArrayList<>(); - tagNamesList.addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - enableButtons(); - } + tagNamesList.setModel(tagTypesListModel); + tagNamesList.addListSelectionListener((ListSelectionEvent event) -> { + enableButtons(); }); } @@ -103,6 +91,12 @@ final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsP org.openide.awt.Mnemonics.setLocalizedText(tagNamesListLabel, org.openide.util.NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.tagNamesListLabel.text")); // NOI18N + tagNamesList.setModel(new javax.swing.AbstractListModel() { + String[] strings = { "TagType" }; + public int getSize() { return strings.length; } + public Object getElementAt(int i) { return strings[i]; } + }); + tagNamesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); jScrollPane1.setViewportView(tagNamesList); newTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add-tag.png"))); // NOI18N @@ -200,38 +194,38 @@ final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsP .addGap(0, 0, Short.MAX_VALUE)) ); }// //GEN-END:initComponents - + private void newTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagNameButtonActionPerformed NewUserTagNameDialog dialog = new NewUserTagNameDialog(); NewUserTagNameDialog.BUTTON_PRESSED result = dialog.getResult(); if (result == NewUserTagNameDialog.BUTTON_PRESSED.OK) { String newTagDisplayName = dialog.getTagName(); - UserTagName newTagName = new UserTagName(newTagDisplayName, DEFAULT_DESCRIPTION, DEFAULT_COLOR_STRING); + TagType newTagType = new TagType(newTagDisplayName, DEFAULT_DESCRIPTION, DEFAULT_COLOR_STRING); /* * If tag name already exists, don't add the tag name. */ - if (tagNames.contains(newTagName)) { + if (tagTypes.contains(newTagType)) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.message"), NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.title"), JOptionPane.INFORMATION_MESSAGE); } else { - tagNames.add(newTagName); + tagTypes.add(newTagType); updateTagNamesListModel(); /* * Set the selection to the tag name that was just added. */ - int index = tagNames.indexOf(newTagName); + int index = tagTypes.indexOf(newTagType); tagNamesList.setSelectedIndex(index); enableButtons(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } } }//GEN-LAST:event_newTagNameButtonActionPerformed - + private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagNameButtonActionPerformed - UserTagName tagName = tagNamesList.getSelectedValue(); - tagNames.remove(tagName); + TagType tagName = tagNamesList.getSelectedValue(); + tagTypes.remove(tagName); updateTagNamesListModel(); enableButtons(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); @@ -254,17 +248,28 @@ final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsP * Updates the tag names model for the tag names list component. */ private void updateTagNamesListModel() { - tagNamesListModel.clear(); - Set tagNameSet = new HashSet<>(); - tagNameSet.addAll(tagNames); - tagNames.clear(); - tagNames.addAll(tagNameSet); - Collections.sort(tagNames); - for (UserTagName tagName : tagNames) { - tagNamesListModel.addElement(tagName); + tagTypesListModel.clear(); + Set tagNameSet = new HashSet<>(); + tagNameSet.addAll(tagTypes); + tagTypes.clear(); + tagTypes.addAll(tagNameSet); + Collections.sort(tagTypes); + for (TagType tagName : tagTypes) { + tagTypesListModel.addElement(tagName); } } + /** + * Updates the tag names list component with tag names from the properties + * file. + */ + @Override + public void load() { + tagTypes = TagType.getCustomTagTypes(); + updateTagNamesListModel(); + enableButtons(); + } + /** * Stores tag name changes in the properties file, called when OK or Apply * is selected in the options panel. @@ -274,43 +279,15 @@ final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsP */ @Override public void store() { - StringBuilder setting = new StringBuilder(); - for (UserTagName tagName : tagNames) { - if (setting.length() != 0) { - setting.append(";"); - } - setting.append(tagName.toSettingsFormat()); - } - ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); - if (Case.isCaseOpen()) { - Case.getCurrentCase().getServices().getTagsManager().storeNewUserTagNames(tagNames); - } + TagType.setCustomTagTypes(tagTypes); } /** - * Updates the tag names list component with tag names from the properties - * file. - */ - @Override - public void load() { - String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); - tagNames.clear(); - if (null != setting && !setting.isEmpty()) { - List tagNameTuples = Arrays.asList(setting.split(";")); - for (String tagNameTuple : tagNameTuples) { - String[] tagNameAttributes = tagNameTuple.split(","); - tagNames.add(new UserTagName(tagNameAttributes[0], tagNameAttributes[1], tagNameAttributes[2])); - } - } - updateTagNamesListModel(); - enableButtons(); - } - - /** - * Only enable delete button when there is a tag name selected in the list. + * Only enable the delete button when there is a tag type selected in the + * tag types JList. */ private void enableButtons() { - boolean ruleIsSelected = tagNamesList.getSelectedIndex() != -1; - deleteTagNameButton.setEnabled(ruleIsSelected); + deleteTagNameButton.setEnabled(tagNamesList.getSelectedIndex() != -1); } + } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagType.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagType.java new file mode 100644 index 0000000000..71415cb615 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagType.java @@ -0,0 +1,177 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2016 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.casemodule.services; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.datamodel.TagName; + +/** + * A tag type definition consisting of a display name, description and color. + */ +@Immutable +final class TagType implements Comparable { + + private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS + private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS + private final String displayName; + private final String description; + private final TagName.HTML_COLOR color; + + /** + * Constructs a tag type definition consisting of a display name, + * description and color. + * + * @param displayName The display name for the tag type. + * @param description The dcescription of the tag type. + * @param color The color to associate with the tag type. + */ + TagType(String displayName, String description, TagName.HTML_COLOR color) { + this.displayName = displayName; + this.description = description; + this.color = color; + } + + /** + * Gets the display name for a tag type. + * + * @return The display name. + */ + String getDisplayName() { + return displayName; + } + + /** + * Gets the description of a tag type. + * + * @return The description. + */ + String getDescription() { + return description; + } + + /** + * Gets the color associated with the tag type. + * + * @return The color. + */ + TagName.HTML_COLOR getColor() { + return color; + } + + /** + * Compares this tag type with the specified tag type for order. + * + * @param other The tag type to which to compare this tag type. + * + * @return Negative integer, zero, or a positive integer to indicate that + * this tag type is less than, equal to, or greater than the + * specified tag type. + */ + @Override + public int compareTo(TagType other) { + return this.getDisplayName().toLowerCase().compareTo(other.getDisplayName().toLowerCase()); + } + + /** + * Returns a hash code value for this tag type. + * + * @return The has code. + */ + @Override + public int hashCode() { + int hash = 7; + hash = 83 * hash + Objects.hashCode(this.displayName); + return hash; + } + + /** + * Indicates whether some other object is "equal to" this tag type. + * + * @param obj The object to test for equality. + * + * @return True or false. + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof TagType)) { + return false; + } + TagType thatTagName = (TagType) obj; + return this.getDisplayName().equals(thatTagName.getDisplayName()); + } + + /** + * A string representation of this tag type. + * + * @return The display name of the tag type. + */ + @Override + public String toString() { + return displayName; + } + + /** + * @return A string representation of the tag name in the format that is + * used by the properties file. + */ + private String toSettingsFormat() { + return displayName + "," + description + "," + color.name(); + } + + /** + * Gets the custom tag types for the current user. + * + * @return A set of tag type objects. + */ + static synchronized Set getCustomTagTypes() { + Set tagTypes = new HashSet<>(); + String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); + if (null != setting && !setting.isEmpty()) { + List tagNameTuples = Arrays.asList(setting.split(";")); + for (String tagNameTuple : tagNameTuples) { + String[] tagNameAttributes = tagNameTuple.split(","); + tagTypes.add(new TagType(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.valueOf(tagNameAttributes[2]))); + } + } + return tagTypes; + } + + /** + * Sets the custom tag types for the current user. + * + * @param tagTypes A set of tag type objects. + */ + static synchronized void setCustomTagTypes(Set tagTypes) { + StringBuilder setting = new StringBuilder(); + for (TagType tagType : tagTypes) { + if (setting.length() != 0) { + setting.append(";"); + } + setting.append(tagType.toSettingsFormat()); + } + ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 7798d3cf3a..9b7a62bc9c 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -1,37 +1,32 @@ /* -* Autopsy Forensic Browser -* -* Copyright 2011-2016 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. + * Autopsy Forensic Browser + * + * Copyright 2011-2016 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; -import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.Content; @@ -41,22 +36,17 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** - * A per case Autopsy service that manages the creation, updating, and deletion - * of tags applied to content and blackboard artifacts by users. + * A per case Autopsy service that manages the addition of content and artifact + * tags to the case database. */ public class TagsManager implements Closeable { - private static final Logger logger = Logger.getLogger(TagsManager.class.getName()); - private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS - private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS - private SleuthkitCase caseDb; - private final HashMap uniqueTagNames = new HashMap<>(); - private boolean tagNamesLoaded = false; + private static final Logger LOGGER = Logger.getLogger(TagsManager.class.getName()); + private final SleuthkitCase caseDb; /** - * Constructs a per case Autopsy service that manages the creation, - * updating, and deletion of tags applied to content and blackboard - * artifacts by users. + * Constructs a per case Autopsy service that manages the addition of + * content and artifact tags to the case database. * * @param caseDb The case database. */ @@ -67,205 +57,148 @@ public class TagsManager implements Closeable { /** * Gets a list of all tag names currently in the case database. * - * @return A list, possibly empty, of TagName data transfer objects (DTOs). + * @return A list, possibly empty, of TagName objects. * - * @throws TskCoreException If there is an error reading from the case - * database. + * @throws TskCoreException If there is an error querying the case database. */ - public synchronized List getAllTagNames() throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - lazyLoadExistingTagNames(); + public List getAllTagNames() throws TskCoreException { return caseDb.getAllTagNames(); } /** - * Gets a mapping of user tag name display names to TagName DTOs if they - * have been added to the database. Otherwise, the display name maps to - * null. + * Gets a list of all tag names currently in use in the case database for + * tagging content or artifacts. * - * @return A map of String display name to TagName DTO, TagName may be null - */ - public synchronized Map getUserTagNamesMap() { - lazyLoadExistingTagNames(); - Map tagNamesMap = new HashMap<>(); - String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); - if (null != setting && !setting.isEmpty()) { - List tagNameTuples = Arrays.asList(setting.split(";")); - for (String tagNameTuple : tagNameTuples) { - String[] tagNameAttributes = tagNameTuple.split(","); - tagNamesMap.put(tagNameAttributes[0], uniqueTagNames.get(tagNameAttributes[0])); - } - } - return tagNamesMap; - } - - /** - * Gets a mapping of predefined tag names to their TagName DTOs. Currently - * only for the bookmark tag. - * - * @return A map of String display name to TagName DTO - */ - public synchronized Map getPredefinedTagNamesMap() { - Map tagNamesMap = new HashMap<>(); - TagName bookmarkTagName = uniqueTagNames.get(NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text")); - tagNamesMap.put(NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"), bookmarkTagName); - return tagNamesMap; - } - - /** - * Gets a mapping of the display names of predefined tag names and tag names - * that are in use to their TagName DTOs. - * - * @return A map of String display name to TagName DTO - * - * @throws TskCoreException If there is an error reading from the case - * database. - */ - public synchronized Map getTagNamesInUseMap() throws TskCoreException { - List tagNames = getTagNamesInUse(); - Map tagNamesMap = new HashMap<>(); - for (TagName tagName : tagNames) { - tagNamesMap.put(tagName.getDisplayName(), tagName); - } - return tagNamesMap; - } - - /** - * Gets a list of all tag names currently in use for tagging content or - * artifacts. + * @return A list, possibly empty, of TagName objects. * - * @return A list, possibly empty, of TagName data transfer objects (DTOs). - * - * @throws TskCoreException If there is an error reading from the case - * database. + * @throws TskCoreException If there is an error querying the case database. */ - public synchronized List getTagNamesInUse() throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - lazyLoadExistingTagNames(); + public List getTagNamesInUse() throws TskCoreException { return caseDb.getTagNamesInUse(); } /** - * Checks whether a tag name with a given display name exists. + * Gets a map of tag display names to tag name entries in the case database. + * It has keys for the display names of the standard tag types, the current + * user's custom tag types, and the tags in the case database. The value for + * a given key will be null if the corresponding tag type is defined, but a + * tag name entry has not yet added to the case database. In that case, + * addTagName may be called to add the tag name entry. * - * @param tagDisplayName The display name to check. + * @return A map of tag display names to possibly null TagName object + * references. * - * @return True or false. + * @throws TskCoreException if there is an error querying the case database. */ - public synchronized boolean tagNameExists(String tagDisplayName) { - lazyLoadExistingTagNames(); - return uniqueTagNames.containsKey(tagDisplayName) && - (uniqueTagNames.get(tagDisplayName) != null); + public synchronized Map getDisplayNamesToTagNamesMap() throws TskCoreException { + /** + * Order is important here. The keys (display names) for the standard + * tag types and current user's custom tag types are added to the map + * first, with null TagName values. If tag name entries exist for those + * keys, loading of the tag names from the database supplies the missing + * values. + * + * Note that creating the map on demand increases the probability that + * the display names of newly added custom tag types and the display + * names of tags added to a multi-user case by other users appear in the + * map. + */ + Map tagNames = new HashMap<>(); + tagNames.put("TagsManager.predefTagNames.bookmark.text", null); + Set customTypes = TagType.getCustomTagTypes(); + for (TagType tagType : customTypes) { + tagNames.put(tagType.getDisplayName(), null); + } + for (TagName tagName : caseDb.getAllTagNames()) { + tagNames.put(tagName.getDisplayName(), tagName); + } + return new HashMap<>(tagNames); } /** - * Adds a new tag name to the current case and to the tags settings. + * Adds a tag name entry to the case database and adds a corresponding + * tag type to the current user's custom tag types. * - * @param displayName The display name for the new tag name. + * @param displayName The display name for the new tag type. * - * @return A TagName data transfer object (DTO) representing the new tag - * name. + * @return A TagName representing the tag name database entry that can be + * used to add instances of the tag type to the case database. * - * @throws TagNameAlreadyExistsException If the tag name would be a - * duplicate. + * @throws TagNameAlreadyExistsException If the tag name already exists in + * the case database. * @throws TskCoreException If there is an error adding the tag - * to the case database. + * name to the case database. */ - public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } + public synchronized TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException { return addTagName(displayName, "", TagName.HTML_COLOR.NONE); } /** - * Adds a new tag name to the current case and to the tags settings. + * Adds a tag name entry to the case database and adds a corresponding + * tag type to the current user's custom tag types. * - * @param displayName The display name for the new tag name. - * @param description The description for the new tag name. + * @param displayName The display name for the new tag type. + * @param description The description for the new tag type. * - * @return A TagName data transfer object (DTO) representing the new tag - * name. + * @return A TagName object that can be used to add instances of the tag + * type to the case database. * - * @throws TagNameAlreadyExistsException If the tag name would be a - * duplicate. + * @throws TagNameAlreadyExistsException If the tag name already exists in + * the case database. * @throws TskCoreException If there is an error adding the tag - * to the case database. + * name to the case database. */ - public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } + public synchronized TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException { return addTagName(displayName, description, TagName.HTML_COLOR.NONE); } /** - * Adds a new tag name to the current case and to the tags settings. + * Adds a tag name entry to the case database and adds a corresponding + * tag type to the current user's custom tag types. * - * @param displayName The display name for the new tag name. - * @param description The description for the new tag name. - * @param color The HTML color to associate with the new tag name. + * @param displayName The display name for the new tag type. + * @param description The description for the new tag type. + * @param color The color to associate with the new tag type. * - * @return A TagName data transfer object (DTO) representing the new tag - * name. + * @return A TagName object that can be used to add instances of the tag + * type to the case database. * - * @throws TagNameAlreadyExistsException If the tag name would be a - * duplicate. + * @throws TagNameAlreadyExistsException If the tag name already exists. * @throws TskCoreException If there is an error adding the tag - * to the case database. + * name to the case database. */ public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - - lazyLoadExistingTagNames(); - - /* - * It is possible user is trying to add back a tag after having deleted - * it. It is also possible a user tag name was never added to the - * database. - */ - if (uniqueTagNames.containsKey(displayName)) { - if (uniqueTagNames.get(displayName) != null) { - TagName existingTagName = uniqueTagNames.get(displayName); - long count = getContentTagsCountByTagName(existingTagName) + getBlackboardArtifactTagsCountByTagName(existingTagName); - if (count == 0) { - addNewTagNameToTagsSettings(existingTagName); - return existingTagName; - } else { + try { + TagName tagName = caseDb.addTagName(displayName, description, color); + Set customTypes = TagType.getCustomTagTypes(); + customTypes.add(new TagType(displayName, description, color)); + TagType.setCustomTagTypes(customTypes); + return tagName; + } catch (TskCoreException ex) { + List existingTagNames = caseDb.getAllTagNames(); + for (TagName tagName : existingTagNames) { + if (tagName.getDisplayName().equals(displayName)) { throw new TagNameAlreadyExistsException(); } } + throw ex; } - - TagName newTagName = caseDb.addTagName(displayName, description, color); - uniqueTagNames.put(newTagName.getDisplayName(), newTagName); - - addNewTagNameToTagsSettings(newTagName); - - return newTagName; } /** * Tags a content object. * * @param content The content to tag. - * @param tagName The name to use for the tag. + * @param tagName The representation of the desired tag type in the case + * database, which can be obtained by calling getTagNames + * and/or addTagName. * - * @return A ContentTag data transfer object (DTO) representing the new tag. + * @return A ContentTag object representing the new tag. * * @throws TskCoreException If there is an error adding the tag to the case * database. */ public ContentTag addContentTag(Content content, TagName tagName) throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } return addContentTag(content, tagName, "", -1, -1); } @@ -273,18 +206,17 @@ public class TagsManager implements Closeable { * Tags a content object. * * @param content The content to tag. - * @param tagName The name to use for the tag. + * @param tagName The representation of the desired tag type in the case + * database, which can be obtained by calling getTagNames + * and/or addTagName. * @param comment A comment to store with the tag. * - * @return A ContentTag data transfer object (DTO) representing the new tag. + * @return A ContentTag object representing the new tag. * * @throws TskCoreException If there is an error adding the tag to the case * database. */ public ContentTag addContentTag(Content content, TagName tagName, String comment) throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } return addContentTag(content, tagName, comment, -1, -1); } @@ -292,56 +224,25 @@ public class TagsManager implements Closeable { * Tags a content object or a section of a content object. * * @param content The content to tag. - * @param tagName The name to use for the tag. + * @param tagName The representation of the desired tag type in the + * case database, which can be obtained by calling + * getTagNames and/or addTagName. * @param comment A comment to store with the tag. * @param beginByteOffset Designates the beginning of a tagged section. * @param endByteOffset Designates the end of a tagged section. * - * @return A ContentTag data transfer object (DTO) representing the new tag. + * @return A ContentTag object representing the new tag. * - * @throws IllegalArgumentException If a requested byte offset is out of - * range. - * @throws TskCoreException If there is an error adding the tag to - * the case database. + * @throws TskCoreException If there is an error adding the tag to the case + * database. */ - public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } + public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException { ContentTag tag; - synchronized (this) { - lazyLoadExistingTagNames(); - - if (null == comment) { - throw new IllegalArgumentException("Passed null comment argument"); - } - - if (beginByteOffset >= 0 && endByteOffset >= 1) { - if (beginByteOffset > content.getSize() - 1) { - throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), - "TagsManager.addContentTag.exception.beginByteOffsetOOR.msg", - beginByteOffset, content.getSize() - 1)); - } - - if (endByteOffset > content.getSize() - 1) { - throw new IllegalArgumentException( - NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endByteOffsetOOR.msg", - endByteOffset, content.getSize() - 1)); - } - - if (endByteOffset < beginByteOffset) { - throw new IllegalArgumentException( - NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endLTbegin.msg")); - } - } - - tag = caseDb.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); - } - + tag = caseDb.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); try { Case.getCurrentCase().notifyContentTagAdded(tag); } catch (IllegalStateException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(TagsManager.class, "TagsManager.addContentTag.noCaseWarning"), ex); + LOGGER.log(Level.SEVERE, "Added a tag to a closed case", ex); } return tag; } @@ -355,18 +256,11 @@ public class TagsManager implements Closeable { * case database. */ public void deleteContentTag(ContentTag tag) throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - synchronized (this) { - lazyLoadExistingTagNames(); - caseDb.deleteContentTag(tag); - } - + caseDb.deleteContentTag(tag); try { Case.getCurrentCase().notifyContentTagDeleted(tag); } catch (IllegalStateException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(TagsManager.class, "TagsManager.deleteContentTag.noCaseWarning"), ex); + LOGGER.log(Level.SEVERE, "Deleted a tag from a closed case", ex); } } @@ -379,17 +273,15 @@ public class TagsManager implements Closeable { * case database. */ public synchronized List getAllContentTags() throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - lazyLoadExistingTagNames(); return caseDb.getAllContentTags(); } /** * Gets content tags count by tag name. * - * @param tagName The tag name of interest. + * @param tagName The representation of the desired tag type in the case + * database, which can be obtained by calling getTagNames + * and/or addTagName. * * @return A count of the content tags with the specified tag name. * @@ -397,29 +289,21 @@ public class TagsManager implements Closeable { * the case database. */ public synchronized long getContentTagsCountByTagName(TagName tagName) throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - lazyLoadExistingTagNames(); return caseDb.getContentTagsCountByTagName(tagName); } /** * Gets a content tag by tag id. * - * @param tagID The tag id of interest. + * @param tagId The tag id of interest. * * @return The content tag with the specified tag id. * * @throws TskCoreException If there is an error getting the tag from the * case database. */ - public synchronized ContentTag getContentTagByTagID(long tagID) throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - lazyLoadExistingTagNames(); - return caseDb.getContentTagByID(tagID); + public synchronized ContentTag getContentTagByTagID(long tagId) throws TskCoreException { + return caseDb.getContentTagByID(tagId); } /** @@ -434,10 +318,6 @@ public class TagsManager implements Closeable { * case database. */ public synchronized List getContentTagsByTagName(TagName tagName) throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - lazyLoadExistingTagNames(); return caseDb.getContentTagsByTagName(tagName); } @@ -447,172 +327,136 @@ public class TagsManager implements Closeable { * @param content The content of interest. * * @return A list, possibly empty, of the tags that have been applied to the - * artifact. + * content. * * @throws TskCoreException If there is an error getting the tags from the * case database. */ public synchronized List getContentTagsByContent(Content content) throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - lazyLoadExistingTagNames(); return caseDb.getContentTagsByContent(content); } /** - * Tags a blackboard artifact object. + * Tags an artifact. * - * @param artifact The blackboard artifact to tag. - * @param tagName The name to use for the tag. + * @param artifact The artifact to tag. + * @param tagName The representation of the desired tag type in the case + * database, which can be obtained by calling getTagNames + * and/or addTagName. * - * @return A BlackboardArtifactTag data transfer object (DTO) representing - * the new tag. + * @return A BlackboardArtifactTag object representing the new tag. * * @throws TskCoreException If there is an error adding the tag to the case * database. */ - public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } + public synchronized BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException { return addBlackboardArtifactTag(artifact, tagName, ""); } /** - * Tags a blackboard artifact object. + * Tags an artifact. * - * @param artifact The blackboard artifact to tag. - * @param tagName The name to use for the tag. + * @param artifact The artifact to tag. + * @param tagName The representation of the desired tag type in the case + * database, which can be obtained by calling getTagNames + * and/or addTagName. * @param comment A comment to store with the tag. * - * @return A BlackboardArtifactTag data transfer object (DTO) representing - * the new tag. + * @return A BlackboardArtifactTag object representing the new tag. * * @throws TskCoreException If there is an error adding the tag to the case * database. */ - public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - BlackboardArtifactTag tag; - synchronized (this) { - lazyLoadExistingTagNames(); - if (null == comment) { - throw new IllegalArgumentException("Passed null comment argument"); - } - tag = caseDb.addBlackboardArtifactTag(artifact, tagName, comment); - } - + public synchronized BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { + BlackboardArtifactTag tag = caseDb.addBlackboardArtifactTag(artifact, tagName, comment); try { Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(tag); } catch (IllegalStateException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(TagsManager.class, "TagsManager.addBlackboardArtifactTag.noCaseWarning"), ex); + LOGGER.log(Level.SEVERE, "Added a tag to a closed case", ex); } return tag; } /** - * Deletes a blackboard artifact tag. + * Deletes an artifact tag. * * @param tag The tag to delete. * * @throws TskCoreException If there is an error deleting the tag from the * case database. */ - public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - synchronized (this) { - lazyLoadExistingTagNames(); - caseDb.deleteBlackboardArtifactTag(tag); - } - + public synchronized void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { + caseDb.deleteBlackboardArtifactTag(tag); try { Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); } catch (IllegalStateException ex) { - logger.log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.deleteBlackboardArtifactTag.noCaseWarning"), ex); + LOGGER.log(Level.SEVERE, "Deleted a tag from a closed case", ex); } } /** - * Gets all blackboard artifact tags for the current case. + * Gets all artifact tags for the current case. * - * @return A list, possibly empty, of blackboard artifact tags. + * @return A list, possibly empty, of artifact tags. * * @throws TskCoreException If there is an error getting the tags from the * case database. */ public synchronized List getAllBlackboardArtifactTags() throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - lazyLoadExistingTagNames(); return caseDb.getAllBlackboardArtifactTags(); } /** - * Gets blackboard artifact tags count by tag name. + * Gets an artifact tags count by tag name. * - * @param tagName The tag name of interest. + * @param tagName The representation of the desired tag type in the case + * database, which can be obtained by calling getTagNames + * and/or addTagName. * - * @return A count of the blackboard artifact tags with the specified tag - * name. + * @return A count of the artifact tags with the specified tag name. * * @throws TskCoreException If there is an error getting the tags count from * the case database. */ public synchronized long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - lazyLoadExistingTagNames(); return caseDb.getBlackboardArtifactTagsCountByTagName(tagName); } /** - * Gets a blackboard artifact tag by tag id. + * Gets an artifact tag by tag id. * - * @param tagID The tag id of interest. + * @param tagId The tag id of interest. * - * @return the blackboard artifact tag with the specified tag id. + * @return The artifact tag with the specified tag id. * * @throws TskCoreException If there is an error getting the tag from the * case database. */ - public synchronized BlackboardArtifactTag getBlackboardArtifactTagByTagID(long tagID) throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - lazyLoadExistingTagNames(); - return caseDb.getBlackboardArtifactTagByID(tagID); + public synchronized BlackboardArtifactTag getBlackboardArtifactTagByTagID(long tagId) throws TskCoreException { + return caseDb.getBlackboardArtifactTagByID(tagId); } /** - * Gets blackboard artifact tags by tag name. + * Gets artifact tags by tag name. * - * @param tagName The tag name of interest. + * @param tagName The representation of the desired tag type in the case + * database, which can be obtained by calling getTagNames + * and/or addTagName. * - * @return A list, possibly empty, of the blackboard artifact tags with the - * specified tag name. + * @return A list, possibly empty, of the artifact tags with the specified + * tag name. * * @throws TskCoreException If there is an error getting the tags from the * case database. */ public synchronized List getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - lazyLoadExistingTagNames(); return caseDb.getBlackboardArtifactTagsByTagName(tagName); } /** - * Gets blackboard artifact tags for a particular blackboard artifact. + * Gets artifact tags for a particular artifact. * - * @param artifact The blackboard artifact of interest. + * @param artifact The artifact of interest. * * @return A list, possibly empty, of the tags that have been applied to the * artifact. @@ -621,129 +465,15 @@ public class TagsManager implements Closeable { * case database. */ public synchronized List getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException { - if (null == caseDb) { - throw new TskCoreException("Tags manager has been closed"); - } - lazyLoadExistingTagNames(); return caseDb.getBlackboardArtifactTagsByArtifact(artifact); } - /** - * Closes the tags manager, saving the available tag names to secondary - * storage. - * - * @throws IOException If there is a problem closing the tags manager. - * @deprecated Tags manager clients should not close the tags manager. - */ - @Override - @Deprecated - public synchronized void close() throws IOException { - caseDb = null; - } - - /** - * Populates the tag names collection and the tag names table in the case - * database with the existing tag names from all sources. - */ - private void lazyLoadExistingTagNames() { - if (!tagNamesLoaded) { - addTagNamesFromCurrentCase(); - addPredefinedTagNames(); - addTagNamesFromTagsSettings(); - tagNamesLoaded = true; - } else { - // Reload case db tag names in case another user has added some. - addTagNamesFromCurrentCase(); - } - } - - /** - * Adds any tag names that are in the case database to the tag names - * collection. - */ - private void addTagNamesFromCurrentCase() { - try { - List currentTagNames = caseDb.getAllTagNames(); - for (TagName tagName : currentTagNames) { - uniqueTagNames.put(tagName.getDisplayName(), tagName); - } - } catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); //NON-NLS - } - } - - /** - * Adds any tag names that are in the properties file to the tag names - * collection and to the case database. The properties file is used to make - * it possible to use tag names across cases. - */ - private void addTagNamesFromTagsSettings() { - String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); - if (null != setting && !setting.isEmpty()) { - // Read the tag name setting and break it into tag name tuples. - List tagNameTuples = Arrays.asList(setting.split(";")); - - // Parse each tuple and add the tag names to the current case, one - // at a time to gracefully discard any duplicates or corrupt tuples. - for (String tagNameTuple : tagNameTuples) { - String[] tagNameAttributes = tagNameTuple.split(","); - if (!uniqueTagNames.containsKey(tagNameAttributes[0])) { - uniqueTagNames.put(tagNameAttributes[0], null); - } - } - } - } - - /** - * Adds the standard tag names to the tag names collection. - */ - private void addPredefinedTagNames() { - if (!uniqueTagNames.containsKey(NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"))) { - try { - TagName tagName = caseDb.addTagName( - NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"), "", TagName.HTML_COLOR.NONE); - uniqueTagNames.put(tagName.getDisplayName(), tagName); - } catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add standard 'Bookmark' tag name to case database", ex); //NON-NLS - } - } - } - - /** - * Adds any user defined tag name to the case db and also to uniqueTagNames, - * to allow user tag names to be displayed while tagging. - * - * @param userTagNames a List of UserTagName objects to be potentially added - */ - void storeNewUserTagNames(List userTagNames) { - lazyLoadExistingTagNames(); - for (UserTagName utn : userTagNames) { - if (!uniqueTagNames.containsKey(utn.getDisplayName())) { - uniqueTagNames.put(utn.getDisplayName(), null); - } - } - } - - /** - * Adds a new tag name to the settings file, used when user creates a new - * tag name. - */ - private void addNewTagNameToTagsSettings(TagName tagName) { - String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); - if (setting == null || setting.isEmpty()) { - setting = ""; - } else { - setting += ";"; - } - setting += tagName.getDisplayName() + "," + tagName.getDescription() + "," + tagName.getColor().toString(); - ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting); - } - /** * Returns true if the tag display name contains an illegal character. Used * after a tag display name is retrieved from user input. * * @param content Display name of the tag being added. + * * @return boolean indicating whether the name has an invalid character. */ public static boolean containsIllegalCharacters(String content) { @@ -757,6 +487,7 @@ public class TagsManager implements Closeable { || content.contains("|") || content.contains(",") || content.contains(";")); + } /** @@ -767,4 +498,36 @@ public class TagsManager implements Closeable { private static final long serialVersionUID = 1L; } + /** + * Checks whether a tag name with a given display name exists in the case + * database. + * + * @param tagDisplayName The display name. + * + * @return True or false. + * + * @deprecated Not reliable for multi-user cases. + */ + @Deprecated + public synchronized boolean tagNameExists(String tagDisplayName) { + try { + Map tagNames = getDisplayNamesToTagNamesMap(); + return tagNames.containsKey(tagDisplayName) && (tagNames.get(tagDisplayName) != null); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error querying case database for tag names", ex); + return false; + } + } + + /** + * Closes the tags manager. + * + * @throws IOException If there is a problem closing the tags manager. + * @deprecated Tags manager clients should not close the tags manager. + */ + @Override + @Deprecated + public synchronized void close() throws IOException { + } + } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/UserTagName.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/UserTagName.java deleted file mode 100755 index c761665c08..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/UserTagName.java +++ /dev/null @@ -1,86 +0,0 @@ -/* -* Autopsy Forensic Browser -* -* Copyright 2011-2016 Basis Technology Corp. -* Contact: carrier sleuthkit org -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package org.sleuthkit.autopsy.casemodule.services; - -import java.util.Objects; - -/** - * Because the DTO TagName constructor can not be called outside of its class - * package, UserTagName is used to keep track of user tag names while - * preserving properties that will potentially be implemented in the future - * (tag name description and tag name color). - */ -class UserTagName implements Comparable { - - private final String displayName; - private final String description; - private final String colorName; - - UserTagName(String displayName, String description, String colorName) { - this.displayName = displayName; - this.description = description; - this.colorName = colorName; - } - - String getDisplayName() { - return displayName; - } - - String getDescription() { - return description; - } - - String getColorName() { - return colorName; - } - - @Override - public int compareTo(UserTagName other) { - return this.getDisplayName().toLowerCase().compareTo(other.getDisplayName().toLowerCase()); - } - - @Override - public int hashCode() { - int hash = 7; - hash = 83 * hash + Objects.hashCode(this.displayName); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof UserTagName)) { - return false; - } - UserTagName thatTagName = (UserTagName) obj; - return this.getDisplayName().equals(thatTagName.getDisplayName()); - } - - @Override - public String toString() { - return displayName; - } - - /** - * @return A string representation of the tag name in the format that is - * used by the properties file. - */ - public String toSettingsFormat() { - return displayName + "," + description + "," + colorName; - } -} From 4115dab3334d4153a83d9723d791f4321cf94ed5 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 3 Oct 2016 00:23:47 -0400 Subject: [PATCH 49/54] Changes to tags management (partial) --- .../autopsy/actions/AddTagAction.java | 1 + .../actions/GetTagNameAndCommentDialog.java | 14 +- .../autopsy/actions/GetTagNameDialog.java | 27 ++- .../casemodule/services/Bundle.properties | 8 +- ...ettingsPanel.form => TagOptionsPanel.form} | 42 ++--- ...ettingsPanel.java => TagOptionsPanel.java} | 171 ++++++++---------- ...r.java => TagsOptionsPanelController.java} | 17 +- 7 files changed, 135 insertions(+), 145 deletions(-) rename Core/src/org/sleuthkit/autopsy/casemodule/services/{TagNamesSettingsPanel.form => TagOptionsPanel.form} (85%) rename Core/src/org/sleuthkit/autopsy/casemodule/services/{TagNamesSettingsPanel.java => TagOptionsPanel.java} (55%) rename Core/src/org/sleuthkit/autopsy/casemodule/services/{TagNamesOptionsPanelController.java => TagsOptionsPanelController.java} (85%) diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index 5a9d371b50..26288a54a2 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -39,6 +39,7 @@ import org.sleuthkit.datamodel.TskCoreException; */ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { + private static final long serialVersionUID = 1L; private static final String NO_COMMENT = ""; AddTagAction(String menuText) { diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index 5a30a49c72..73290602e9 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -91,13 +91,18 @@ public class GetTagNameAndCommentDialog extends JDialog { * dialog. */ public static TagNameAndComment doDialog(Window owner) { - return new GetTagNameAndCommentDialog(owner).tagNameAndComment; + GetTagNameAndCommentDialog dialog = new GetTagNameAndCommentDialog(owner); + dialog.display(); + return dialog.tagNameAndComment; } private GetTagNameAndCommentDialog(Window owner) { super(owner, NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.createTag"), ModalityType.APPLICATION_MODAL); + } + + private void display() { initComponents(); // Set up the dialog to close when Esc is pressed. @@ -106,6 +111,7 @@ public class GetTagNameAndCommentDialog extends JDialog { inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); ActionMap actionMap = getRootPane().getActionMap(); actionMap.put(cancelName, new AbstractAction() { + private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { dispose(); @@ -131,10 +137,10 @@ public class GetTagNameAndCommentDialog extends JDialog { } // Center and show the dialog box. - this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); - setVisible(true); + this.setLocationRelativeTo(this.getOwner()); + setVisible(true); } - + /** * 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 diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index 268512898e..3d1057a041 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -45,6 +45,7 @@ import org.sleuthkit.datamodel.TskCoreException; public class GetTagNameDialog extends JDialog { + private static final long serialVersionUID = 1L; private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS private final Map tagNamesMap = new TreeMap<>(); private TagName tagName = null; @@ -71,14 +72,19 @@ public class GetTagNameDialog extends JDialog { * @return a TagName instance selected by the user, or null if the user * canceled the dialog. */ - public static TagName doDialog(final Window owner) { - return new GetTagNameDialog(owner).tagName; + public static TagName doDialog(Window owner) { + GetTagNameDialog dialog = new GetTagNameDialog(owner); + dialog.display(); + return dialog.tagName; } - private GetTagNameDialog(final Window owner) { - super(owner, + private GetTagNameDialog(Window owner) { + super(owner, NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.createTag"), ModalityType.APPLICATION_MODAL); + } + + private void display() { setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH)); initComponents(); @@ -88,6 +94,8 @@ public class GetTagNameDialog extends JDialog { inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); ActionMap actionMap = getRootPane().getActionMap(); actionMap.put(cancelName, new AbstractAction() { + private static final long serialVersionUID = 1L; + @Override public void actionPerformed(ActionEvent e) { cancelButtonActionPerformed(e); @@ -104,19 +112,20 @@ public class GetTagNameDialog extends JDialog { } // Populate the tag names table. - tagsTable.setModel(new TagsTableModel(new ArrayList(tagNamesMap.keySet()))); + tagsTable.setModel(new TagsTableModel(new ArrayList<>(tagNamesMap.keySet()))); tagsTable.setTableHeader(null); tagsTable.setCellSelectionEnabled(false); tagsTable.setFocusable(false); tagsTable.setRowHeight(tagsTable.getRowHeight() + 5); // Center and show the dialog box. - this.setLocationRelativeTo(owner); - setVisible(true); + this.setLocationRelativeTo(this.getOwner()); + setVisible(true); } - + private class TagsTableModel extends AbstractTableModel { + private static final long serialVersionUID = 1L; private final ArrayList tagDisplayNames = new ArrayList<>(); TagsTableModel(List tagDisplayNames) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index ed80e8696e..3550c648f6 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -9,8 +9,6 @@ TagsManager.deleteContentTag.noCaseWarning=Failed to publish content tag deleted TagsManager.addBlackboardArtifactTag.noCaseWarning=Failed to publish new blackboard artifact tag event. There is no case open. TagsManager.deleteBlackboardArtifactTag.noCaseWarning=Failed to publish blackboard artifact tag deleted event. There is no case open. Blackboard.unableToIndexArtifact.error.msg=Unable to index blackboard artifact {0} -TagNamesSettingsPanel.deleteTagNameButton.text=Delete Tag Name -TagNamesSettingsPanel.tagNamesListLabel.text=Tag names: NewUserTagNameDialog.tagNameTextField.text= NewUserTagNameDialog.newTagNameLabel.text=New Tag Name: NewUserTagNameDialog.okButton.text=OK @@ -22,5 +20,7 @@ TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.message=The tag name alre TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.title=Tag name already exists NewUserTagNameDialog.JOptionPane.tagNameEmpty.message=The tag name cannot be empty NewUserTagNameDialog.JOptionPane.tagNameEmpty.title=Empty tag name -TagNamesSettingsPanel.panelDescriptionLabel.text=Autopsy keeps a list of the tag names you have created in the past. Add more or delete them here. -TagNamesSettingsPanel.newTagNameButton.text=New Tag Name +TagOptionsPanel.newTagTypeButton.text=New Tag Type +TagOptionsPanel.tagTypesListLabel.text=Tag Types: +TagOptionsPanel.panelDescriptionLabel.text=Autopsy keeps a list of the tag names you have created in the past. Add more or delete them here. +TagOptionsPanel.deleteTagTypeButton.text=Delete Tag Type diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form similarity index 85% rename from Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form rename to Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form index 5b896fdd36..4b3a77eb92 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form @@ -65,7 +65,7 @@ - + @@ -77,7 +77,7 @@ - + @@ -90,12 +90,12 @@ - + - + - - + + @@ -107,13 +107,13 @@ - + - - + + @@ -121,10 +121,10 @@ - + - + @@ -138,47 +138,45 @@ - - - + - + - + - + - + - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java similarity index 55% rename from Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java rename to Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java index 1a74acc4ae..d1fcfdd992 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java @@ -18,37 +18,31 @@ */ package org.sleuthkit.autopsy.casemodule.services; -import java.util.Collections; -import java.util.HashSet; import java.util.Set; import java.util.TreeSet; 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 org.sleuthkit.autopsy.corecomponents.OptionsPanel; -import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.TagName; /** - * A panel to allow the user to create new tag names or to delete tag names that - * user has created in the past. List of user tag names is maintained in a - * properties file, able to be used across cases. Potentially room to add other - * tag name options in the future. + * A panel to allow the user to create and delete custom tag types. */ -final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsPanel { +final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { private static final long serialVersionUID = 1L; private static final String DEFAULT_DESCRIPTION = ""; - private static final String DEFAULT_COLOR_STRING = "NONE"; + private static final TagName.HTML_COLOR DEFAULT_COLOR = TagName.HTML_COLOR.NONE; private final DefaultListModel tagTypesListModel; - private final Set tagTypes; + private Set tagTypes; /** * Creates new form TagsManagerOptionsPanel */ - TagNamesSettingsPanel() { + TagOptionsPanel() { tagTypesListModel = new DefaultListModel<>(); tagTypes = new TreeSet<>(TagType.getCustomTagTypes()); initComponents(); @@ -74,91 +68,86 @@ final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsP jPanel1 = new javax.swing.JPanel(); panelDescriptionLabel = new javax.swing.JLabel(); jSplitPane1 = new javax.swing.JSplitPane(); - modifyTagNameListPanel = new javax.swing.JPanel(); - tagNamesListLabel = new javax.swing.JLabel(); + modifyTagTypesListPanel = new javax.swing.JPanel(); + tagTypesListLabel = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); tagNamesList = new javax.swing.JList<>(); - newTagNameButton = new javax.swing.JButton(); - deleteTagNameButton = new javax.swing.JButton(); - tagNameAdditionalPanel = new javax.swing.JPanel(); + newTagTypeButton = new javax.swing.JButton(); + deleteTagTypeButton = new javax.swing.JButton(); + tagTypesAdditionalPanel = new javax.swing.JPanel(); jPanel1.setPreferredSize(new java.awt.Dimension(750, 500)); - org.openide.awt.Mnemonics.setLocalizedText(panelDescriptionLabel, org.openide.util.NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.panelDescriptionLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(panelDescriptionLabel, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.panelDescriptionLabel.text")); // NOI18N jSplitPane1.setDividerLocation(400); jSplitPane1.setDividerSize(1); - org.openide.awt.Mnemonics.setLocalizedText(tagNamesListLabel, org.openide.util.NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.tagNamesListLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(tagTypesListLabel, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.tagTypesListLabel.text")); // NOI18N - tagNamesList.setModel(new javax.swing.AbstractListModel() { - String[] strings = { "TagType" }; - public int getSize() { return strings.length; } - public Object getElementAt(int i) { return strings[i]; } - }); tagNamesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); jScrollPane1.setViewportView(tagNamesList); - newTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add-tag.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(newTagNameButton, org.openide.util.NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.newTagNameButton.text")); // NOI18N - newTagNameButton.addActionListener(new java.awt.event.ActionListener() { + newTagTypeButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add-tag.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(newTagTypeButton, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.newTagTypeButton.text")); // NOI18N + newTagTypeButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - newTagNameButtonActionPerformed(evt); + newTagTypeButtonActionPerformed(evt); } }); - deleteTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete-tag.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(deleteTagNameButton, org.openide.util.NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.deleteTagNameButton.text")); // NOI18N - deleteTagNameButton.addActionListener(new java.awt.event.ActionListener() { + deleteTagTypeButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete-tag.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteTagTypeButton, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.deleteTagTypeButton.text")); // NOI18N + deleteTagTypeButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - deleteTagNameButtonActionPerformed(evt); + deleteTagTypeButtonActionPerformed(evt); } }); - javax.swing.GroupLayout modifyTagNameListPanelLayout = new javax.swing.GroupLayout(modifyTagNameListPanel); - modifyTagNameListPanel.setLayout(modifyTagNameListPanelLayout); - modifyTagNameListPanelLayout.setHorizontalGroup( - modifyTagNameListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(modifyTagNameListPanelLayout.createSequentialGroup() + javax.swing.GroupLayout modifyTagTypesListPanelLayout = new javax.swing.GroupLayout(modifyTagTypesListPanel); + modifyTagTypesListPanel.setLayout(modifyTagTypesListPanelLayout); + modifyTagTypesListPanelLayout.setHorizontalGroup( + modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup() .addContainerGap() - .addGroup(modifyTagNameListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(tagNamesListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(modifyTagNameListPanelLayout.createSequentialGroup() - .addComponent(newTagNameButton) + .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(tagTypesListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup() + .addComponent(newTagTypeButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deleteTagNameButton) - .addGap(0, 113, Short.MAX_VALUE)) + .addComponent(deleteTagTypeButton) + .addGap(0, 121, Short.MAX_VALUE)) .addComponent(jScrollPane1)) .addContainerGap()) ); - modifyTagNameListPanelLayout.setVerticalGroup( - modifyTagNameListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(modifyTagNameListPanelLayout.createSequentialGroup() + modifyTagTypesListPanelLayout.setVerticalGroup( + modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup() .addContainerGap() - .addComponent(tagNamesListLabel) + .addComponent(tagTypesListLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 383, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(modifyTagNameListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(newTagNameButton) - .addComponent(deleteTagNameButton)) + .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(newTagTypeButton) + .addComponent(deleteTagTypeButton)) .addContainerGap()) ); - jSplitPane1.setLeftComponent(modifyTagNameListPanel); + jSplitPane1.setLeftComponent(modifyTagTypesListPanel); - javax.swing.GroupLayout tagNameAdditionalPanelLayout = new javax.swing.GroupLayout(tagNameAdditionalPanel); - tagNameAdditionalPanel.setLayout(tagNameAdditionalPanelLayout); - tagNameAdditionalPanelLayout.setHorizontalGroup( - tagNameAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + javax.swing.GroupLayout tagTypesAdditionalPanelLayout = new javax.swing.GroupLayout(tagTypesAdditionalPanel); + tagTypesAdditionalPanel.setLayout(tagTypesAdditionalPanelLayout); + tagTypesAdditionalPanelLayout.setHorizontalGroup( + tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 356, Short.MAX_VALUE) ); - tagNameAdditionalPanelLayout.setVerticalGroup( - tagNameAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + tagTypesAdditionalPanelLayout.setVerticalGroup( + tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 456, Short.MAX_VALUE) ); - jSplitPane1.setRightComponent(tagNameAdditionalPanel); + jSplitPane1.setRightComponent(tagTypesAdditionalPanel); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); @@ -195,53 +184,49 @@ final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsP ); }// //GEN-END:initComponents - private void newTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagNameButtonActionPerformed + private void newTagTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagTypeButtonActionPerformed NewUserTagNameDialog dialog = new NewUserTagNameDialog(); NewUserTagNameDialog.BUTTON_PRESSED result = dialog.getResult(); if (result == NewUserTagNameDialog.BUTTON_PRESSED.OK) { String newTagDisplayName = dialog.getTagName(); - TagType newTagType = new TagType(newTagDisplayName, DEFAULT_DESCRIPTION, DEFAULT_COLOR_STRING); + TagType newTagType = new TagType(newTagDisplayName, DEFAULT_DESCRIPTION, DEFAULT_COLOR); /* * If tag name already exists, don't add the tag name. */ - if (tagTypes.contains(newTagType)) { - JOptionPane.showMessageDialog(null, - NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.message"), - NbBundle.getMessage(TagNamesSettingsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.title"), - JOptionPane.INFORMATION_MESSAGE); - } else { + if (!tagTypes.contains(newTagType)) { tagTypes.add(newTagType); updateTagNamesListModel(); - /* - * Set the selection to the tag name that was just added. - */ - int index = tagTypes.indexOf(newTagType); - tagNamesList.setSelectedIndex(index); + tagNamesList.setSelectedValue(newTagType, true); enableButtons(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + } else { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(TagOptionsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.message"), + NbBundle.getMessage(TagOptionsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.title"), + JOptionPane.INFORMATION_MESSAGE); } } - }//GEN-LAST:event_newTagNameButtonActionPerformed + }//GEN-LAST:event_newTagTypeButtonActionPerformed - private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagNameButtonActionPerformed + private void deleteTagTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagTypeButtonActionPerformed TagType tagName = tagNamesList.getSelectedValue(); tagTypes.remove(tagName); updateTagNamesListModel(); enableButtons(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - }//GEN-LAST:event_deleteTagNameButtonActionPerformed + }//GEN-LAST:event_deleteTagTypeButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton deleteTagNameButton; + private javax.swing.JButton deleteTagTypeButton; private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JSplitPane jSplitPane1; - private javax.swing.JPanel modifyTagNameListPanel; - private javax.swing.JButton newTagNameButton; + private javax.swing.JPanel modifyTagTypesListPanel; + private javax.swing.JButton newTagTypeButton; private javax.swing.JLabel panelDescriptionLabel; - private javax.swing.JPanel tagNameAdditionalPanel; - private javax.swing.JList tagNamesList; - private javax.swing.JLabel tagNamesListLabel; + private javax.swing.JList tagNamesList; + private javax.swing.JPanel tagTypesAdditionalPanel; + private javax.swing.JLabel tagTypesListLabel; // End of variables declaration//GEN-END:variables /** @@ -249,33 +234,23 @@ final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsP */ private void updateTagNamesListModel() { tagTypesListModel.clear(); - Set tagNameSet = new HashSet<>(); - tagNameSet.addAll(tagTypes); - tagTypes.clear(); - tagTypes.addAll(tagNameSet); - Collections.sort(tagTypes); for (TagType tagName : tagTypes) { tagTypesListModel.addElement(tagName); } } /** - * Updates the tag names list component with tag names from the properties - * file. + * Loads the stored custom tag types. */ @Override public void load() { - tagTypes = TagType.getCustomTagTypes(); + tagTypes = new TreeSet<>(TagType.getCustomTagTypes()); updateTagNamesListModel(); enableButtons(); } /** - * Stores tag name changes in the properties file, called when OK or Apply - * is selected in the options panel. - * - * Adds all new tag names to the case database for displaying usable tag - * names when tagging. + * Stores the custom tag types. */ @Override public void store() { @@ -283,11 +258,15 @@ final class TagNamesSettingsPanel extends javax.swing.JPanel implements OptionsP } /** - * Only enable the delete button when there is a tag type selected in the - * tag types JList. + * Enables the button components based on the state of the tag types list + * component. */ private void enableButtons() { - deleteTagNameButton.setEnabled(tagNamesList.getSelectedIndex() != -1); + /* + * Only enable the delete button when there is a tag type selected in + * the tag types JList. + */ + deleteTagTypeButton.setEnabled(tagNamesList.getSelectedIndex() != -1); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java similarity index 85% rename from Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesOptionsPanelController.java rename to Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java index 20c478d966..48947d51f1 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNamesOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java @@ -33,9 +33,9 @@ import org.openide.util.Lookup; keywordsCategory = "CustomTagNames", position = 8 ) -public final class TagNamesOptionsPanelController extends OptionsPanelController { +public final class TagsOptionsPanelController extends OptionsPanelController { - private TagNamesSettingsPanel panel; + private TagOptionsPanel panel; private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private boolean changed; @@ -106,15 +106,12 @@ public final class TagNamesOptionsPanelController extends OptionsPanelController pcs.removePropertyChangeListener(l); } - private TagNamesSettingsPanel getPanel() { + private TagOptionsPanel getPanel() { if (panel == null) { - panel = new TagNamesSettingsPanel(); - panel.addPropertyChangeListener(new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(OptionsPanelController.PROP_CHANGED)) { - changed(); - } + panel = new TagOptionsPanel(); + panel.addPropertyChangeListener((PropertyChangeEvent evt) -> { + if (evt.getPropertyName().equals(OptionsPanelController.PROP_CHANGED)) { + changed(); } }); } From 9f43ec1b6f01084239450aa337ff1747dbdf7e09 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 3 Oct 2016 17:48:07 +0200 Subject: [PATCH 50/54] query database for children count to avoid making nodes --- .../autopsy/datamodel/_private/Accounts.java | 57 +++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java index f635845e77..13ce6cbbbe 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java @@ -120,7 +120,7 @@ final public class Accounts implements AutopsyVisitableItem { * based on the state of showRejected. */ private String getRejectedArtifactFilterClause() { - return showRejected ? " " : " AND blackboard_artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID(); //NON-NLS + return showRejected ? " " : " AND blackboard_artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() + " "; //NON-NLS } /** @@ -541,7 +541,26 @@ final public class Accounts implements AutopsyVisitableItem { "# {0} - number of children", "Accounts.ByFileNode.displayName=By File ({0})"}) private void updateDisplayName() { - setDisplayName(Bundle.Accounts_ByFileNode_displayName(getChildren().getNodesCount(true))); + String query + = "SELECT count(*) FROM ( SELECT count(*) AS documents " + + " FROM blackboard_artifacts " //NON-NLS + + " LEFT JOIN blackboard_attributes as solr_attribute ON blackboard_artifacts.artifact_id = solr_attribute.artifact_id " //NON-NLS + + " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS + + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS + + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + + " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.name() + "'" //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + getRejectedArtifactFilterClause() + + " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text )"; + try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); + ResultSet rs = results.getResultSet();) { + while (rs.next()) { + setDisplayName(Bundle.Accounts_ByFileNode_displayName(rs.getLong("count(*)"))); + } + } catch (TskCoreException | SQLException ex) { + LOGGER.log(Level.SEVERE, "Error querying for files with ccn hits.", ex); //NON-NLS + + } } @Override @@ -643,7 +662,21 @@ final public class Accounts implements AutopsyVisitableItem { "# {0} - number of children", "Accounts.ByBINNode.displayName=By BIN ({0})"}) private void updateDisplayName() { - setDisplayName(Bundle.Accounts_ByBINNode_displayName(getChildren().getNodesCount(true))); + String query + = "SELECT count(distinct SUBSTR(blackboard_attributes.value_text,1,8)) AS BINs " //NON-NLS + + " FROM blackboard_artifacts " //NON-NLS + + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + + getRejectedArtifactFilterClause(); //NON-NLS + try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query)) { + ResultSet resultSet = results.getResultSet(); + while (resultSet.next()) { + setDisplayName(Bundle.Accounts_ByBINNode_displayName(resultSet.getLong("BINs"))); + } + } catch (TskCoreException | SQLException ex) { + LOGGER.log(Level.SEVERE, "Error querying for BINs.", ex); //NON-NLS + } } @Override @@ -922,8 +955,24 @@ final public class Accounts implements AutopsyVisitableItem { } private void updateDisplayName() { + String query + = "SELECT count(blackboard_artifacts.artifact_id ) AS count" //NON-NLS + + " FROM blackboard_artifacts " //NON-NLS + + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS + + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + + " AND blackboard_attributes.value_text >= \"" + bin.getBINStart() + "\" AND blackboard_attributes.value_text < \"" + (bin.getBINEnd() + 1) + "\"" //NON-NLS + + getRejectedArtifactFilterClause(); + try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); + ResultSet rs = results.getResultSet();) { + while (rs.next()) { + setDisplayName(getBinRangeString() + " (" + rs.getLong("count") + ")"); //NON-NLS + } + } catch (TskCoreException | SQLException ex) { + LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS + + } - setDisplayName(getBinRangeString() + " (" + getChildren().getNodesCount(true) + ")"); //NON-NLS } private String getBinRangeString() { From 1464fc973dca756e96118eb43af363c78cc5d17b Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 3 Oct 2016 18:12:08 -0400 Subject: [PATCH 51/54] Improve/fix tags option panel implementation --- .../casemodule/services/Bundle.properties | 22 ++---- .../casemodule/services/Bundle_ja.properties | 7 -- ...gNameDialog.form => NewTagNameDialog.form} | 8 +- ...gNameDialog.java => NewTagNameDialog.java} | 25 ++++--- .../{TagType.java => TagNameDefiniton.java} | 69 +++++++++--------- .../casemodule/services/TagOptionsPanel.form | 24 +++--- .../casemodule/services/TagOptionsPanel.java | 68 ++++++++--------- .../casemodule/services/TagsManager.java | 31 +++++--- .../services/TagsOptionsPanelController.java | 2 +- ...manager.png => tag-options-panel-icon.png} | Bin 10 files changed, 126 insertions(+), 130 deletions(-) rename Core/src/org/sleuthkit/autopsy/casemodule/services/{NewUserTagNameDialog.form => NewTagNameDialog.form} (90%) rename Core/src/org/sleuthkit/autopsy/casemodule/services/{NewUserTagNameDialog.java => NewTagNameDialog.java} (87%) rename Core/src/org/sleuthkit/autopsy/casemodule/services/{TagType.java => TagNameDefiniton.java} (63%) rename Core/src/org/sleuthkit/autopsy/casemodule/services/{tags-manager.png => tag-options-panel-icon.png} (100%) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index 3550c648f6..229d26af58 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -1,18 +1,6 @@ OptionsCategory_Name_TagNamesOptions=Tags OptionsCategory_TagNames=TagNames -TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0} out of content size range (0 - {1}) -TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} out of content size range (0 - {1}) -TagsManager.addContentTag.exception.endLTbegin.msg=endByteOffset < beginByteOffset -TagsManager.predefTagNames.bookmark.text=Bookmark -TagsManager.addContentTag.noCaseWarning=Failed to publish new content tag event. There is no case open. -TagsManager.deleteContentTag.noCaseWarning=Failed to publish content tag deleted event. There is no case open. -TagsManager.addBlackboardArtifactTag.noCaseWarning=Failed to publish new blackboard artifact tag event. There is no case open. -TagsManager.deleteBlackboardArtifactTag.noCaseWarning=Failed to publish blackboard artifact tag deleted event. There is no case open. Blackboard.unableToIndexArtifact.error.msg=Unable to index blackboard artifact {0} -NewUserTagNameDialog.tagNameTextField.text= -NewUserTagNameDialog.newTagNameLabel.text=New Tag Name: -NewUserTagNameDialog.okButton.text=OK -NewUserTagNameDialog.cancelButton.text=Cancel NewUserTagNameDialog.title.text=New Tag Name NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.message=Tag name may not contain any of the following symbols\: \\ \: * ? " < > | , ; NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.title=Invalid character in tag name @@ -20,7 +8,11 @@ TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.message=The tag name alre TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.title=Tag name already exists NewUserTagNameDialog.JOptionPane.tagNameEmpty.message=The tag name cannot be empty NewUserTagNameDialog.JOptionPane.tagNameEmpty.title=Empty tag name -TagOptionsPanel.newTagTypeButton.text=New Tag Type -TagOptionsPanel.tagTypesListLabel.text=Tag Types: +TagOptionsPanel.tagTypesListLabel.text=Tag Names: TagOptionsPanel.panelDescriptionLabel.text=Autopsy keeps a list of the tag names you have created in the past. Add more or delete them here. -TagOptionsPanel.deleteTagTypeButton.text=Delete Tag Type +NewTagNameDialog.okButton.text=OK +NewTagNameDialog.cancelButton.text=Cancel +NewTagNameDialog.tagNameTextField.text= +NewTagNameDialog.newTagNameLabel.text=New Tag Name: +TagOptionsPanel.deleteTagNameButton.text=Delete Tag Name +TagOptionsPanel.newTagNameButton.text=New Tag Name diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties index ca8ed3431a..a27e3ca586 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties @@ -1,9 +1,2 @@ -TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0} \u30b3\u30f3\u30c6\u30f3\u30c4\u30b5\u30a4\u30ba\u7bc4\u56f2(0 - {1})\u306e\u5916\u3067\u3059 -TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} \u30b3\u30f3\u30c6\u30f3\u30c4\u30b5\u30a4\u30ba\u7bc4\u56f2(0 - {1})\u306e\u5916\u3067\u3059 -TagsManager.addContentTag.exception.endLTbegin.msg=endByteOffset < beginByteOffset TagsManager.predefTagNames.bookmark.text=\u30d6\u30c3\u30af\u30de\u30fc\u30af -TagsManager.addContentTag.noCaseWarning=\u65b0\u3057\u3044\u30bf\u30b0\u30a4\u30d9\u30f3\u30c8\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002 -TagsManager.deleteContentTag.noCaseWarning=\u524a\u9664\u3055\u308c\u305f\u30a4\u30d9\u30f3\u30c8\u306e\u30bf\u30b0\u306e\u30b3\u30f3\u30c6\u30f3\u30c4\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002 -TagsManager.addBlackboardArtifactTag.noCaseWarning=\u30a4\u30d9\u30f3\u30c8\u306e\u30bf\u30b0\u306e\u65b0\u3057\u3044blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002 -TagsManager.deleteBlackboardArtifactTag.noCaseWarning=\u524a\u9664\u3055\u308c\u305f\u30a4\u30d9\u30f3\u30c8\u306e\u30bf\u30b0\u306e\u65b0\u3057\u3044blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002 Blackboard.unableToIndexArtifact.error.msg=blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8{0}\u3092\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/NewTagNameDialog.form similarity index 90% rename from Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.form rename to Core/src/org/sleuthkit/autopsy/casemodule/services/NewTagNameDialog.form index 26ab153c27..b6400b7c31 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/NewTagNameDialog.form @@ -63,21 +63,21 @@ - + - + - + @@ -87,7 +87,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/NewTagNameDialog.java similarity index 87% rename from Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java rename to Core/src/org/sleuthkit/autopsy/casemodule/services/NewTagNameDialog.java index bd04678ba9..fbb7594c44 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewUserTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/NewTagNameDialog.java @@ -29,8 +29,9 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.openide.util.NbBundle; -class NewUserTagNameDialog extends javax.swing.JDialog { +final class NewTagNameDialog extends javax.swing.JDialog { + private static final long serialVersionUID = 1L; private String userTagDisplayName; private BUTTON_PRESSED result; @@ -41,9 +42,9 @@ class NewUserTagNameDialog extends javax.swing.JDialog { /** * Creates a new NewUserTagNameDialog dialog. */ - NewUserTagNameDialog() { - super(new JFrame(NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.title.text")), - NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.title.text"), true); + NewTagNameDialog() { + super(new JFrame(NbBundle.getMessage(NewTagNameDialog.class, "NewUserTagNameDialog.title.text")), + NbBundle.getMessage(NewTagNameDialog.class, "NewUserTagNameDialog.title.text"), true); initComponents(); this.display(); } @@ -111,15 +112,15 @@ class NewUserTagNameDialog extends javax.swing.JDialog { String newTagDisplayName = tagNameTextField.getText().trim(); if (newTagDisplayName.isEmpty()) { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameEmpty.message"), - NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameEmpty.title"), + NbBundle.getMessage(NewTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameEmpty.message"), + NbBundle.getMessage(NewTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameEmpty.title"), JOptionPane.ERROR_MESSAGE); return; } if (TagsManager.containsIllegalCharacters(newTagDisplayName)) { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.message"), - NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.title"), + NbBundle.getMessage(NewTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.message"), + NbBundle.getMessage(NewTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.title"), JOptionPane.ERROR_MESSAGE); return; } @@ -175,18 +176,18 @@ class NewUserTagNameDialog extends javax.swing.JDialog { setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - org.openide.awt.Mnemonics.setLocalizedText(newTagNameLabel, org.openide.util.NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.newTagNameLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(newTagNameLabel, org.openide.util.NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.newTagNameLabel.text")); // NOI18N - tagNameTextField.setText(org.openide.util.NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.tagNameTextField.text")); // NOI18N + tagNameTextField.setText(org.openide.util.NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.tagNameTextField.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.cancelButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.cancelButton.text")); // NOI18N cancelButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { cancelButtonActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(NewUserTagNameDialog.class, "NewUserTagNameDialog.okButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.okButton.text")); // NOI18N okButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { okButtonActionPerformed(evt); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagType.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefiniton.java similarity index 63% rename from Core/src/org/sleuthkit/autopsy/casemodule/services/TagType.java rename to Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefiniton.java index 71415cb615..101d68fa4c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagType.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefiniton.java @@ -28,10 +28,10 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.datamodel.TagName; /** - * A tag type definition consisting of a display name, description and color. + * A tag name definition consisting of a display name, description and color. */ @Immutable -final class TagType implements Comparable { +final class TagNameDefiniton implements Comparable { private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS @@ -40,21 +40,21 @@ final class TagType implements Comparable { private final TagName.HTML_COLOR color; /** - * Constructs a tag type definition consisting of a display name, + * Constructs a tag name definition consisting of a display name, * description and color. * - * @param displayName The display name for the tag type. - * @param description The dcescription of the tag type. - * @param color The color to associate with the tag type. + * @param displayName The display name for the tag name. + * @param description The description for the tag name. + * @param color The color for the tag name. */ - TagType(String displayName, String description, TagName.HTML_COLOR color) { + TagNameDefiniton(String displayName, String description, TagName.HTML_COLOR color) { this.displayName = displayName; this.description = description; this.color = color; } /** - * Gets the display name for a tag type. + * Gets the display name for the tag name. * * @return The display name. */ @@ -63,7 +63,7 @@ final class TagType implements Comparable { } /** - * Gets the description of a tag type. + * Gets the description for the tag name. * * @return The description. */ @@ -72,7 +72,7 @@ final class TagType implements Comparable { } /** - * Gets the color associated with the tag type. + * Gets the color for the tag name. * * @return The color. */ @@ -81,21 +81,23 @@ final class TagType implements Comparable { } /** - * Compares this tag type with the specified tag type for order. + * Compares this tag name definition with the specified tag name definition + * for order. * - * @param other The tag type to which to compare this tag type. + * @param other The tag name definition to which to compare this tag name + * definition. * * @return Negative integer, zero, or a positive integer to indicate that - * this tag type is less than, equal to, or greater than the - * specified tag type. + * this tag name definition is less than, equal to, or greater than + * the specified tag name definition. */ @Override - public int compareTo(TagType other) { + public int compareTo(TagNameDefiniton other) { return this.getDisplayName().toLowerCase().compareTo(other.getDisplayName().toLowerCase()); } /** - * Returns a hash code value for this tag type. + * Returns a hash code value for this tag name definition. * * @return The has code. */ @@ -107,7 +109,8 @@ final class TagType implements Comparable { } /** - * Indicates whether some other object is "equal to" this tag type. + * Indicates whether some other object is "equal to" this tag name + * definition. * * @param obj The object to test for equality. * @@ -115,15 +118,15 @@ final class TagType implements Comparable { */ @Override public boolean equals(Object obj) { - if (!(obj instanceof TagType)) { + if (!(obj instanceof TagNameDefiniton)) { return false; } - TagType thatTagName = (TagType) obj; + TagNameDefiniton thatTagName = (TagNameDefiniton) obj; return this.getDisplayName().equals(thatTagName.getDisplayName()); } /** - * A string representation of this tag type. + * A string representation of this tag name definition. * * @return The display name of the tag type. */ @@ -133,43 +136,43 @@ final class TagType implements Comparable { } /** - * @return A string representation of the tag name in the format that is - * used by the properties file. + * @return A string representation of the tag name definition in the format + * that is used by the tags settings file. */ private String toSettingsFormat() { return displayName + "," + description + "," + color.name(); } /** - * Gets the custom tag types for the current user. + * Gets tag name definitions from the tag settings file. * - * @return A set of tag type objects. + * @return A set of tag name definition objects. */ - static synchronized Set getCustomTagTypes() { - Set tagTypes = new HashSet<>(); + static synchronized Set getTagNameDefinitions() { + Set tagNames = new HashSet<>(); String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); if (null != setting && !setting.isEmpty()) { List tagNameTuples = Arrays.asList(setting.split(";")); for (String tagNameTuple : tagNameTuples) { String[] tagNameAttributes = tagNameTuple.split(","); - tagTypes.add(new TagType(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.valueOf(tagNameAttributes[2]))); + tagNames.add(new TagNameDefiniton(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.valueOf(tagNameAttributes[2]))); } } - return tagTypes; + return tagNames; } /** - * Sets the custom tag types for the current user. + * Sets the tag name definitions in the tag settings file. * - * @param tagTypes A set of tag type objects. + * @param tagNames A set of tag name definition objects. */ - static synchronized void setCustomTagTypes(Set tagTypes) { + static synchronized void setTagNameDefinitions(Set tagNames) { StringBuilder setting = new StringBuilder(); - for (TagType tagType : tagTypes) { + for (TagNameDefiniton tagName : tagNames) { if (setting.length() != 0) { setting.append(";"); } - setting.append(tagType.toSettingsFormat()); + setting.append(tagName.toSettingsFormat()); } ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form index 4b3a77eb92..1f81b4d3aa 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form @@ -92,10 +92,10 @@ - + - - + + @@ -112,8 +112,8 @@ - - + + @@ -143,35 +143,35 @@ - + - + - + - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java index d1fcfdd992..4f761062e8 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java @@ -36,15 +36,15 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { private static final long serialVersionUID = 1L; private static final String DEFAULT_DESCRIPTION = ""; private static final TagName.HTML_COLOR DEFAULT_COLOR = TagName.HTML_COLOR.NONE; - private final DefaultListModel tagTypesListModel; - private Set tagTypes; + private final DefaultListModel tagTypesListModel; + private Set tagTypes; /** * Creates new form TagsManagerOptionsPanel */ TagOptionsPanel() { tagTypesListModel = new DefaultListModel<>(); - tagTypes = new TreeSet<>(TagType.getCustomTagTypes()); + tagTypes = new TreeSet<>(TagNameDefiniton.getTagNameDefinitions()); initComponents(); customizeComponents(); } @@ -72,8 +72,8 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { tagTypesListLabel = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); tagNamesList = new javax.swing.JList<>(); - newTagTypeButton = new javax.swing.JButton(); - deleteTagTypeButton = new javax.swing.JButton(); + newTagNameButton = new javax.swing.JButton(); + deleteTagNameButton = new javax.swing.JButton(); tagTypesAdditionalPanel = new javax.swing.JPanel(); jPanel1.setPreferredSize(new java.awt.Dimension(750, 500)); @@ -88,19 +88,19 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { tagNamesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); jScrollPane1.setViewportView(tagNamesList); - newTagTypeButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add-tag.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(newTagTypeButton, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.newTagTypeButton.text")); // NOI18N - newTagTypeButton.addActionListener(new java.awt.event.ActionListener() { + newTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add-tag.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(newTagNameButton, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.newTagNameButton.text")); // NOI18N + newTagNameButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - newTagTypeButtonActionPerformed(evt); + newTagNameButtonActionPerformed(evt); } }); - deleteTagTypeButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete-tag.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(deleteTagTypeButton, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.deleteTagTypeButton.text")); // NOI18N - deleteTagTypeButton.addActionListener(new java.awt.event.ActionListener() { + deleteTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete-tag.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteTagNameButton, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.deleteTagNameButton.text")); // NOI18N + deleteTagNameButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - deleteTagTypeButtonActionPerformed(evt); + deleteTagNameButtonActionPerformed(evt); } }); @@ -113,10 +113,10 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(tagTypesListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup() - .addComponent(newTagTypeButton) + .addComponent(newTagNameButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deleteTagTypeButton) - .addGap(0, 121, Short.MAX_VALUE)) + .addComponent(deleteTagNameButton) + .addGap(0, 113, Short.MAX_VALUE)) .addComponent(jScrollPane1)) .addContainerGap()) ); @@ -129,8 +129,8 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 383, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(newTagTypeButton) - .addComponent(deleteTagTypeButton)) + .addComponent(newTagNameButton) + .addComponent(deleteTagNameButton)) .addContainerGap()) ); @@ -184,12 +184,12 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { ); }// //GEN-END:initComponents - private void newTagTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagTypeButtonActionPerformed - NewUserTagNameDialog dialog = new NewUserTagNameDialog(); - NewUserTagNameDialog.BUTTON_PRESSED result = dialog.getResult(); - if (result == NewUserTagNameDialog.BUTTON_PRESSED.OK) { + private void newTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagNameButtonActionPerformed + NewTagNameDialog dialog = new NewTagNameDialog(); + NewTagNameDialog.BUTTON_PRESSED result = dialog.getResult(); + if (result == NewTagNameDialog.BUTTON_PRESSED.OK) { String newTagDisplayName = dialog.getTagName(); - TagType newTagType = new TagType(newTagDisplayName, DEFAULT_DESCRIPTION, DEFAULT_COLOR); + TagNameDefiniton newTagType = new TagNameDefiniton(newTagDisplayName, DEFAULT_DESCRIPTION, DEFAULT_COLOR); /* * If tag name already exists, don't add the tag name. */ @@ -206,25 +206,25 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { JOptionPane.INFORMATION_MESSAGE); } } - }//GEN-LAST:event_newTagTypeButtonActionPerformed + }//GEN-LAST:event_newTagNameButtonActionPerformed - private void deleteTagTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagTypeButtonActionPerformed - TagType tagName = tagNamesList.getSelectedValue(); + private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagNameButtonActionPerformed + TagNameDefiniton tagName = tagNamesList.getSelectedValue(); tagTypes.remove(tagName); updateTagNamesListModel(); enableButtons(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - }//GEN-LAST:event_deleteTagTypeButtonActionPerformed + }//GEN-LAST:event_deleteTagNameButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton deleteTagTypeButton; + private javax.swing.JButton deleteTagNameButton; private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JSplitPane jSplitPane1; private javax.swing.JPanel modifyTagTypesListPanel; - private javax.swing.JButton newTagTypeButton; + private javax.swing.JButton newTagNameButton; private javax.swing.JLabel panelDescriptionLabel; - private javax.swing.JList tagNamesList; + private javax.swing.JList tagNamesList; private javax.swing.JPanel tagTypesAdditionalPanel; private javax.swing.JLabel tagTypesListLabel; // End of variables declaration//GEN-END:variables @@ -234,7 +234,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { */ private void updateTagNamesListModel() { tagTypesListModel.clear(); - for (TagType tagName : tagTypes) { + for (TagNameDefiniton tagName : tagTypes) { tagTypesListModel.addElement(tagName); } } @@ -244,7 +244,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { */ @Override public void load() { - tagTypes = new TreeSet<>(TagType.getCustomTagTypes()); + tagTypes = new TreeSet<>(TagNameDefiniton.getTagNameDefinitions()); updateTagNamesListModel(); enableButtons(); } @@ -254,7 +254,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { */ @Override public void store() { - TagType.setCustomTagTypes(tagTypes); + TagNameDefiniton.setTagNameDefinitions(tagTypes); } /** @@ -266,7 +266,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { * Only enable the delete button when there is a tag type selected in * the tag types JList. */ - deleteTagTypeButton.setEnabled(tagNamesList.getSelectedIndex() != -1); + deleteTagNameButton.setEnabled(tagNamesList.getSelectedIndex() != -1); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 9b7a62bc9c..46982397f8 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -20,11 +20,14 @@ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -42,6 +45,8 @@ import org.sleuthkit.datamodel.TskCoreException; public class TagsManager implements Closeable { private static final Logger LOGGER = Logger.getLogger(TagsManager.class.getName()); + @NbBundle.Messages("TagsManager.predefTagNames.bookmark.text=Bookmark") + private static final Set STANDARD_TAG_DISPLAY_NAMES = new HashSet<>(Arrays.asList(Bundle.TagsManager_predefTagNames_bookmark_text())); private final SleuthkitCase caseDb; /** @@ -104,9 +109,9 @@ public class TagsManager implements Closeable { * map. */ Map tagNames = new HashMap<>(); - tagNames.put("TagsManager.predefTagNames.bookmark.text", null); - Set customTypes = TagType.getCustomTagTypes(); - for (TagType tagType : customTypes) { + tagNames.put(NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"), null); + Set customTypes = TagNameDefiniton.getTagNameDefinitions(); + for (TagNameDefiniton tagType : customTypes) { tagNames.put(tagType.getDisplayName(), null); } for (TagName tagName : caseDb.getAllTagNames()) { @@ -116,8 +121,8 @@ public class TagsManager implements Closeable { } /** - * Adds a tag name entry to the case database and adds a corresponding - * tag type to the current user's custom tag types. + * Adds a tag name entry to the case database and adds a corresponding tag + * type to the current user's custom tag types. * * @param displayName The display name for the new tag type. * @@ -134,8 +139,8 @@ public class TagsManager implements Closeable { } /** - * Adds a tag name entry to the case database and adds a corresponding - * tag type to the current user's custom tag types. + * Adds a tag name entry to the case database and adds a corresponding tag + * type to the current user's custom tag types. * * @param displayName The display name for the new tag type. * @param description The description for the new tag type. @@ -153,8 +158,8 @@ public class TagsManager implements Closeable { } /** - * Adds a tag name entry to the case database and adds a corresponding - * tag type to the current user's custom tag types. + * Adds a tag name entry to the case database and adds a corresponding tag + * type to the current user's custom tag types. * * @param displayName The display name for the new tag type. * @param description The description for the new tag type. @@ -170,9 +175,11 @@ public class TagsManager implements Closeable { public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException { try { TagName tagName = caseDb.addTagName(displayName, description, color); - Set customTypes = TagType.getCustomTagTypes(); - customTypes.add(new TagType(displayName, description, color)); - TagType.setCustomTagTypes(customTypes); + if (!STANDARD_TAG_DISPLAY_NAMES.contains(displayName)) { + Set customTypes = TagNameDefiniton.getTagNameDefinitions(); + customTypes.add(new TagNameDefiniton(displayName, description, color)); + TagNameDefiniton.setTagNameDefinitions(customTypes); + } return tagName; } catch (TskCoreException ex) { List existingTagNames = caseDb.getAllTagNames(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java index 48947d51f1..3d36e8ae00 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java @@ -28,7 +28,7 @@ import org.openide.util.Lookup; @OptionsPanelController.TopLevelRegistration( categoryName = "#OptionsCategory_Name_TagNamesOptions", - iconBase = "org/sleuthkit/autopsy/casemodule/services/tags-manager.png", + iconBase = "org/sleuthkit/autopsy/casemodule/services/tag-options-panel-icon.png", keywords = "#OptionsCategory_TagNames", keywordsCategory = "CustomTagNames", position = 8 diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/tags-manager.png b/Core/src/org/sleuthkit/autopsy/casemodule/services/tag-options-panel-icon.png similarity index 100% rename from Core/src/org/sleuthkit/autopsy/casemodule/services/tags-manager.png rename to Core/src/org/sleuthkit/autopsy/casemodule/services/tag-options-panel-icon.png From e18839f2566327bd05670d9ccaf1dc6f666a60d2 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Wed, 5 Oct 2016 13:54:45 +0200 Subject: [PATCH 52/54] fix refresh bugs --- .../autopsy/datamodel/_private/Accounts.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java index 13ce6cbbbe..49559e6ead 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java @@ -705,8 +705,11 @@ final public class Accounts implements AutopsyVisitableItem { @Override public int hashCode() { int hash = 5; - hash = 89 * hash + (int) (this.objID ^ (this.objID >>> 32)); - hash = 89 * hash + Objects.hashCode(this.solrDocumentId); + hash = 79 * hash + (int) (this.objID ^ (this.objID >>> 32)); + hash = 79 * hash + Objects.hashCode(this.solrDocumentId); + hash = 79 * hash + Objects.hashCode(this.artifactIDS); + hash = 79 * hash + (int) (this.hits ^ (this.hits >>> 32)); + hash = 79 * hash + Objects.hashCode(this.statuses); return hash; } @@ -725,9 +728,18 @@ final public class Accounts implements AutopsyVisitableItem { if (this.objID != other.objID) { return false; } + if (this.hits != other.hits) { + return false; + } if (!Objects.equals(this.solrDocumentId, other.solrDocumentId)) { return false; } + if (!Objects.equals(this.artifactIDS, other.artifactIDS)) { + return false; + } + if (!Objects.equals(this.statuses, other.statuses)) { + return false; + } return true; } @@ -891,6 +903,7 @@ final public class Accounts implements AutopsyVisitableItem { @Override public void handleReviewStatusChange(ReviewStatusChangeEvent event) { updateKeys(); + event.artifacts.stream().map(BlackboardArtifact::getArtifactID).forEach(this::refreshKey); } /** @@ -1243,15 +1256,15 @@ final public class Accounts implements AutopsyVisitableItem { @Override public void actionPerformed(ActionEvent e) { - final Collection lookupAll = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); - lookupAll.forEach(artifact -> { + final Collection artifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); + artifacts.forEach(artifact -> { try { skCase.setReviewStatus(artifact, newStatus); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error changing artifact review status.", ex); //NON-NLS } }); - reviewStatusBus.post(new ReviewStatusChangeEvent(lookupAll, newStatus)); + reviewStatusBus.post(new ReviewStatusChangeEvent(artifacts, newStatus)); } } From 9bd01d16139aabb7e87994b6e5a82b59110b2bd6 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Wed, 5 Oct 2016 15:10:28 +0200 Subject: [PATCH 53/54] re-implement re-selection of nodes --- .../autopsy/datamodel/_private/Accounts.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java index 49559e6ead..92254b663a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java @@ -50,18 +50,22 @@ import org.apache.commons.lang3.StringUtils; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; +import org.openide.nodes.NodeNotFoundException; +import org.openide.nodes.NodeOp; import org.openide.nodes.Sheet; import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; import org.sleuthkit.autopsy.datamodel.NodeProperty; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; @@ -1256,6 +1260,33 @@ final public class Accounts implements AutopsyVisitableItem { @Override public void actionPerformed(ActionEvent e) { + + /* get paths for selected nodes to reselect after applying review + * status change */ + List selectedPaths = Utilities.actionsGlobalContext().lookupAll(Node.class).stream() + .map(node -> { + String[] createPath; + /* + * If the we are rejecting and not showing rejected + * results, then the selected node, won't exist any + * more, so we select the previous one in stead. + */ + if (newStatus == BlackboardArtifact.ReviewStatus.REJECTED && showRejected == false) { + List siblings = Arrays.asList(node.getParentNode().getChildren().getNodes()); + int indexOf = siblings.indexOf(node); + //there is no previous for the first node, so instead we select the next one + Node sibling = indexOf > 0 + ? siblings.get(indexOf - 1) + : siblings.get(indexOf + 1); + createPath = NodeOp.createPath(sibling, null); + } else { + createPath = NodeOp.createPath(node, null); + } + //for the reselect to work we need to strip off the first part of the path. + return Arrays.copyOfRange(createPath, 1, createPath.length); + }).collect(Collectors.toList()); + + //change status of selected artifacts final Collection artifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); artifacts.forEach(artifact -> { try { @@ -1264,7 +1295,23 @@ final public class Accounts implements AutopsyVisitableItem { LOGGER.log(Level.SEVERE, "Error changing artifact review status.", ex); //NON-NLS } }); + //post event reviewStatusBus.post(new ReviewStatusChangeEvent(artifacts, newStatus)); + + final DataResultTopComponent directoryListing = DirectoryTreeTopComponent.findInstance().getDirectoryListing(); + final Node rootNode = directoryListing.getRootNode(); + + //convert paths back to nodes + List toArray = new ArrayList<>(); + selectedPaths.forEach(path -> { + try { + toArray.add(NodeOp.findPath(rootNode, path)); + } catch (NodeNotFoundException ex) { + //just ingnore paths taht don't exist. this is expected since we are rejecting + } + }); + //select nodes + directoryListing.setSelectedNodes(toArray.toArray(new Node[toArray.size()])); } } From 049913bc4b308f8001d7ac5939f1540947bf7701 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Wed, 5 Oct 2016 16:41:40 +0200 Subject: [PATCH 54/54] some cleanup and comments --- .../autopsy/datamodel/_private/Accounts.java | 206 ++++++++++-------- .../autopsy/datamodel/_private/BINRange.java | 18 ++ 2 files changed, 133 insertions(+), 91 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java index 92254b663a..4e29135b2d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/Accounts.java @@ -47,13 +47,11 @@ import javax.annotation.concurrent.Immutable; import javax.swing.AbstractAction; import javax.swing.Action; import org.apache.commons.lang3.StringUtils; -import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.NodeNotFoundException; import org.openide.nodes.NodeOp; import org.openide.nodes.Sheet; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.openide.util.lookup.Lookups; @@ -79,7 +77,7 @@ import org.sleuthkit.datamodel.TskCoreException; /** * AutopsyVisitableItem for the Accounts section of the tree. All nodes, - * factories, and data objects related to accounts are inner classes. + * factories, and custom key class related to accounts are inner classes. */ final public class Accounts implements AutopsyVisitableItem { @@ -139,31 +137,31 @@ final public class Accounts implements AutopsyVisitableItem { } /** - * Base class for factories that are also observers. + * Base class for children that are also observers of the reviewStatusBus. + * It * * @param The type of keys used by this factory. */ private abstract class ObservingChildren extends Children.Keys { - @Override - protected Node[] createNodes(X key) { - return new Node[]{createNodeForKey(key)}; - } - - abstract protected Node createNodeForKey(X key); - /** - * + * Create of keys used by this Children object to represent the child + * nodes. */ abstract protected Collection createKeys(); /** - * Update the keys for this Children + * Refresh the keys for this Children */ - void updateKeys() { + void refreshKeys() { setKeys(createKeys()); } + /** + * Handle a ReviewStatusChangeEvent + * + * @param event the ReviewStatusChangeEvent to handle. + */ @Subscribe abstract void handleReviewStatusChange(ReviewStatusChangeEvent event); @@ -176,7 +174,7 @@ final public class Accounts implements AutopsyVisitableItem { @Override protected void addNotify() { super.addNotify(); - updateKeys(); + refreshKeys(); reviewStatusBus.register(ObservingChildren.this); } } @@ -188,8 +186,7 @@ final public class Accounts implements AutopsyVisitableItem { final public class AccountsRootNode extends DisplayableItemNode { /** - * Creates child nodes for each account type (currently hard coded to - * make one for Credit Cards) + * Creates child nodes for each account type in the db. */ final private class AccountTypeFactory extends ObservingChildren { @@ -220,7 +217,7 @@ final public class Accounts implements AutopsyVisitableItem { ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue(); if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { - updateKeys(); + refreshKeys(); } } catch (IllegalStateException notUsed) { // Case is closed, do nothing. @@ -235,7 +232,7 @@ final public class Accounts implements AutopsyVisitableItem { */ try { Case.getCurrentCase(); - updateKeys(); + refreshKeys(); } catch (IllegalStateException notUsed) { // Case is closed, do nothing. } @@ -252,12 +249,9 @@ final public class Accounts implements AutopsyVisitableItem { @Subscribe @Override public void handleReviewStatusChange(ReviewStatusChangeEvent event) { - updateKeys(); + refreshKeys(); } - /** - * - */ @Override protected List createKeys() { List list = new ArrayList<>(); @@ -271,25 +265,25 @@ final public class Accounts implements AutopsyVisitableItem { list.add(accountType); } } catch (TskCoreException | SQLException ex) { - Exceptions.printStackTrace(ex); + LOGGER.log(Level.SEVERE, "Error querying for account_types", ex); } return list; } @Override - protected Node createNodeForKey(String key) { + protected Node[] createNodes(String key) { try { Account.Type accountType = Account.Type.valueOf(key); switch (accountType) { case CREDIT_CARD: - return new CreditCardNumberAccountTypeNode(); + return new Node[]{new CreditCardNumberAccountTypeNode()}; default: - return new DefaultAccountTypeNode(key); + return new Node[]{new DefaultAccountTypeNode(key)}; } } catch (IllegalArgumentException ex) { - LOGGER.log(Level.WARNING, "Unknown account type: " + key); + LOGGER.log(Level.WARNING, "Unknown account type: {0}", key); //Flesh out what happens with other account types here. - return new DefaultAccountTypeNode(key); + return new Node[]{new DefaultAccountTypeNode(key)}; } } @@ -307,8 +301,9 @@ final public class Accounts implements AutopsyVisitableItem { IngestManager.getInstance().addIngestModuleEventListener(pcl); Case.addPropertyChangeListener(pcl); super.addNotify(); - updateKeys(); + refreshKeys(); } + } public AccountsRootNode() { @@ -330,19 +325,22 @@ final public class Accounts implements AutopsyVisitableItem { } } + /** + * Default Node class for unknown account types and account types that have + * no special behavior. + */ final public class DefaultAccountTypeNode extends DisplayableItemNode { - final private class DefaultAccountFactory extends ChildFactory.Detachable { + private final String accountTypeName; - private final String accountTypeName; + final private class DefaultAccountFactory extends ObservingChildren { - private DefaultAccountFactory(String accountTypeName) { - this.accountTypeName = accountTypeName; + private DefaultAccountFactory() { } @Override - protected boolean createKeys(List list) { - + protected Collection createKeys() { + List list = new ArrayList<>(); String query = "SELECT blackboard_artifacts.artifact_id " //NON-NLS + " FROM blackboard_artifacts " //NON-NLS @@ -358,25 +356,30 @@ final public class Accounts implements AutopsyVisitableItem { } } catch (TskCoreException | SQLException ex) { LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS - return false; } - return true; + return list; } @Override - protected Node createNodeForKey(Long t) { + protected Node[] createNodes(Long t) { try { - return new BlackboardArtifactNode(skCase.getBlackboardArtifact(t)); + return new Node[]{new BlackboardArtifactNode(skCase.getBlackboardArtifact(t))}; } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error get black board artifact with id " + t, ex); - return null; + return new Node[0]; } } + + @Override + void handleReviewStatusChange(ReviewStatusChangeEvent event) { + refreshKeys(); + } } private DefaultAccountTypeNode(String accountTypeName) { super(Children.LEAF); - setChildren(Children.create(new DefaultAccountFactory(accountTypeName), true)); + this.accountTypeName = accountTypeName; + setChildren(Children.createLazy(DefaultAccountFactory::new)); setName(accountTypeName); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS } @@ -395,14 +398,13 @@ final public class Accounts implements AutopsyVisitableItem { /** * Enum for the children under the credit card AccountTypeNode. */ - enum CreditCardViewMode { + private enum CreditCardViewMode { BY_FILE, BY_BIN; } /** - * Node for the Credit Card account type. - * + * Node for the Credit Card account type. * */ final public class CreditCardNumberAccountTypeNode extends DisplayableItemNode { @@ -415,7 +417,7 @@ final public class Accounts implements AutopsyVisitableItem { @Subscribe @Override public void handleReviewStatusChange(ReviewStatusChangeEvent event) { - updateKeys(); + refreshKeys(); } /** @@ -428,14 +430,14 @@ final public class Accounts implements AutopsyVisitableItem { } @Override - protected Node createNodeForKey(CreditCardViewMode key) { + protected Node[] createNodes(CreditCardViewMode key) { switch (key) { case BY_BIN: - return new ByBINNode(); + return new Node[]{new ByBINNode()}; case BY_FILE: - return new ByFileNode(); + return new Node[]{new ByFileNode()}; default: - return null; + return new Node[0]; } } } @@ -472,12 +474,9 @@ final public class Accounts implements AutopsyVisitableItem { @Subscribe @Override public void handleReviewStatusChange(ReviewStatusChangeEvent event) { - updateKeys(); + refreshKeys(); } - /** - * - */ @Override protected List createKeys() { List list = new ArrayList<>(); @@ -515,19 +514,19 @@ final public class Accounts implements AutopsyVisitableItem { } @Override - protected Node createNodeForKey(FileWithCCN key) { + protected Node[] createNodes(FileWithCCN key) { //add all account artifacts for the file and the file itself to the lookup try { List lookupContents = new ArrayList<>(); - for (long artId : key.artifactIDS) { + for (long artId : key.artifactIDs) { lookupContents.add(skCase.getBlackboardArtifact(artId)); } AbstractFile abstractFileById = skCase.getAbstractFileById(key.getObjID()); lookupContents.add(abstractFileById); - return new FileWithCCNNode(key, abstractFileById, lookupContents.toArray()); + return new Node[]{new FileWithCCNNode(key, abstractFileById, lookupContents.toArray())}; } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error getting content for file with ccn hits.", ex); //NON-NLS - return null; + return new Node[0]; } } } @@ -597,17 +596,14 @@ final public class Accounts implements AutopsyVisitableItem { @Subscribe @Override public void handleReviewStatusChange(ReviewStatusChangeEvent event) { - updateKeys(); + refreshKeys(); } - /** - * - */ @Override protected List createKeys() { List list = new ArrayList<>(); - RangeMap ranges = TreeRangeMap.create(); + RangeMap binRanges = TreeRangeMap.create(); String query = "SELECT SUBSTR(blackboard_attributes.value_text,1,8) AS BIN, " //NON-NLS @@ -621,25 +617,26 @@ final public class Accounts implements AutopsyVisitableItem { + " ORDER BY BIN "; //NON-NLS try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query)) { ResultSet resultSet = results.getResultSet(); + //sort all te individual bins in to the ranges while (resultSet.next()) { final Integer bin = Integer.valueOf(resultSet.getString("BIN")); long count = resultSet.getLong("count"); BINRange binRange = (BINRange) CreditCards.getBINInfo(bin); - BinResult previousResult = ranges.get(bin); + BinResult previousResult = binRanges.get(bin); if (previousResult != null) { - ranges.remove(Range.closed(previousResult.getBINStart(), previousResult.getBINEnd())); + binRanges.remove(Range.closed(previousResult.getBINStart(), previousResult.getBINEnd())); count += previousResult.getCount(); } if (binRange != null) { - ranges.put(Range.closed(binRange.getBINstart(), binRange.getBINend()), new BinResult(count, binRange)); + binRanges.put(Range.closed(binRange.getBINstart(), binRange.getBINend()), new BinResult(count, binRange)); } else { - ranges.put(Range.closed(bin, bin), new BinResult(count, bin, bin)); + binRanges.put(Range.closed(bin, bin), new BinResult(count, bin, bin)); } } - ranges.asMapOfRanges().values().forEach(list::add); + binRanges.asMapOfRanges().values().forEach(list::add); } catch (TskCoreException | SQLException ex) { LOGGER.log(Level.SEVERE, "Error querying for BINs.", ex); //NON-NLS @@ -648,8 +645,8 @@ final public class Accounts implements AutopsyVisitableItem { } @Override - protected Node createNodeForKey(BinResult key) { - return new BINNode(key); + protected Node[] createNodes(BinResult key) { + return new Node[]{new BINNode(key)}; } } @@ -710,8 +707,8 @@ final public class Accounts implements AutopsyVisitableItem { public int hashCode() { int hash = 5; hash = 79 * hash + (int) (this.objID ^ (this.objID >>> 32)); - hash = 79 * hash + Objects.hashCode(this.solrDocumentId); - hash = 79 * hash + Objects.hashCode(this.artifactIDS); + hash = 79 * hash + Objects.hashCode(this.keywordSearchDocID); + hash = 79 * hash + Objects.hashCode(this.artifactIDs); hash = 79 * hash + (int) (this.hits ^ (this.hits >>> 32)); hash = 79 * hash + Objects.hashCode(this.statuses); return hash; @@ -735,10 +732,10 @@ final public class Accounts implements AutopsyVisitableItem { if (this.hits != other.hits) { return false; } - if (!Objects.equals(this.solrDocumentId, other.solrDocumentId)) { + if (!Objects.equals(this.keywordSearchDocID, other.keywordSearchDocID)) { return false; } - if (!Objects.equals(this.artifactIDS, other.artifactIDS)) { + if (!Objects.equals(this.artifactIDs, other.artifactIDs)) { return false; } if (!Objects.equals(this.statuses, other.statuses)) { @@ -748,35 +745,61 @@ final public class Accounts implements AutopsyVisitableItem { } private final long objID; - private final String solrDocumentId; - private final List artifactIDS; + private final String keywordSearchDocID; + private final List artifactIDs; private final long hits; private final Set statuses; - private FileWithCCN(long objID, String solrDocID, List artifactIDS, long hits, Set statuses) { + private FileWithCCN(long objID, String solrDocID, List artifactIDs, long hits, Set statuses) { this.objID = objID; - this.solrDocumentId = solrDocID; - this.artifactIDS = artifactIDS; + this.keywordSearchDocID = solrDocID; + this.artifactIDs = artifactIDs; this.hits = hits; this.statuses = statuses; } + /** + * Get the object ID of the file. + * + * @return the object ID of the file. + */ public long getObjID() { return objID; } - public String getSolrDocmentID() { - return solrDocumentId; + /** + * Get the keyword search docuement id. This is used for unnalocated + * files to limit results to one chunk/page + * + * @return the keyword search document id. + */ + public String getkeywordSearchDocID() { + return keywordSearchDocID; } - public List getArtifactIDS() { - return artifactIDS; + /** + * Get the artifact ids of the account artifacts from this file. + * + * @return the artifact ids of the account artifacts from this file. + */ + public List getArtifactIDs() { + return artifactIDs; } + /** + * Get the number of account artifacts from this file. + * + * @return the number of account artifacts from this file. + */ public long getHits() { return hits; } + /** + * Get the status(s) of the account artifacts from this file. + * + * @return the status(s) of the account artifacts from this file. + */ public Set getStatuses() { return statuses; } @@ -829,9 +852,9 @@ final public class Accounts implements AutopsyVisitableItem { private FileWithCCNNode(FileWithCCN key, Content content, Object[] lookupContents) { super(Children.LEAF, Lookups.fixed(lookupContents)); this.fileKey = key; - this.fileName = (key.getSolrDocmentID() == null) + this.fileName = (key.getkeywordSearchDocID() == null) ? content.getName() - : Bundle.Accounts_FileWithCCNNode_unallocatedSpaceFile_displayName(content.getName(), StringUtils.substringAfter(key.getSolrDocmentID(), "_")); //NON-NLS + : Bundle.Accounts_FileWithCCNNode_unallocatedSpaceFile_displayName(content.getName(), StringUtils.substringAfter(key.getkeywordSearchDocID(), "_")); //NON-NLS setName(fileName + key.getObjID()); setDisplayName(fileName); } @@ -899,14 +922,15 @@ final public class Accounts implements AutopsyVisitableItem { final public class BINNode extends DisplayableItemNode { /** - * Creates the nodes for the accounts of a given type + * Creates the nodes for the credit card numbers */ final private class CreditCardNumberFactory extends ObservingChildren { @Subscribe @Override public void handleReviewStatusChange(ReviewStatusChangeEvent event) { - updateKeys(); + refreshKeys(); + //make sure to refresh the nodes for artifacts that changed statuses. event.artifacts.stream().map(BlackboardArtifact::getArtifactID).forEach(this::refreshKey); } @@ -939,17 +963,17 @@ final public class Accounts implements AutopsyVisitableItem { } @Override - protected Node createNodeForKey(Long artifactID) { + protected Node[] createNodes(Long artifactID) { if (skCase == null) { - return null; + return new Node[0]; } try { BlackboardArtifact art = skCase.getBlackboardArtifact(artifactID); - return new AccountArtifactNode(art); + return new Node[]{new AccountArtifactNode(art)}; } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "Error creating BlackboardArtifactNode for artifact with ID " + artifactID, ex); //NON-NLS - return null; + return new Node[0]; } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/_private/BINRange.java b/Core/src/org/sleuthkit/autopsy/datamodel/_private/BINRange.java index 4c82cdda95..c29f9be85d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/_private/BINRange.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/_private/BINRange.java @@ -1,3 +1,21 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2016 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.sleuthkit.autopsy.datamodel._private; import java.util.Optional;